{"context":{"domain":"modenafs-app"},"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":"6a26a4d06aecdcf58a4260e0","name":"app","domain":"modenafs-app","visibility":"public","settings":{"defaultAccessPolicy":"public"},"updatedAt":"2026-07-27T14:19:36.810Z","createdAt":"2026-06-08T11:17:36.157Z"}]}},{"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":"6a733b1ca9d7cf0ea995fcdd","component":"data2-core-types@Component","system":"6a26a4d06aecdcf58a4260e0","params":{"extends":"data2-core-primitives@Block","component":"loginCC","package":"modenafs-app","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"export default {\n  css: `\n    * { box-sizing: border-box; }\n    :host, .wrap { height: 100%; }\n    .wrap {\n      height: 100%; display: flex; align-items: center; justify-content: center;\n      background: linear-gradient(135deg,#0d0d12,#1c1c26);\n      font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n      color: #ffffff; padding: 24px;\n    }\n    .card { width: 100%; max-width: 360px; }\n    .brand { font-size: 13px; font-weight: 700; letter-spacing: 3px; color: #8a8a9a; margin-bottom: 8px; }\n    .title { font-size: 26px; font-weight: 800; margin-bottom: 28px; }\n    .field { margin-bottom: 16px; }\n    .field label { display: block; font-size: 12px; font-weight: 600; color: #9a9aab; margin-bottom: 6px; }\n    .field input {\n      width: 100%; background: #0d0d12; border: 1px solid rgba(255,255,255,.08); border-radius: 12px;\n      padding: 14px; color: #ffffff; font-size: 15px; outline: none;\n    }\n    .field input:focus { border-color: #6d5efc; }\n    .error { color: #ff6b6b; font-size: 13px; margin-bottom: 12px; min-height: 18px; }\n    .btn {\n      width: 100%; padding: 15px; border: none; border-radius: 12px;\n      background: linear-gradient(135deg,#6d5efc,#8f7bff); color: #ffffff; font-weight: 700; font-size: 15px; cursor: pointer;\n    }\n    .btn:disabled { opacity: .6; cursor: default; }\n    .footer { text-align: center; font-size: 11px; color: #55556a; margin-top: 24px; }\n  `,\n  render(d2) {\n    const email = d2.state.email || '';\n    const password = d2.state.password || '';\n    const error = d2.state.error || '';\n    const busy = d2.state.busy;\n    return `<div class=\"wrap\"><div class=\"card\">\n      <div class=\"brand\">MODENAFS</div>\n      <div class=\"title\">Bem-vindo de volta</div>\n      <div class=\"field\"><label>Email</label><input type=\"email\" data-role=\"email\" value=\"${esc(email)}\" placeholder=\"voce@exemplo.com\" /></div>\n      <div class=\"field\"><label>Senha</label><input type=\"password\" data-role=\"password\" value=\"${esc(password)}\" placeholder=\"••••••••\" /></div>\n      <div class=\"error\">${esc(error)}</div>\n      <button class=\"btn\" data-role=\"submit\" ${busy ? 'disabled' : ''}>${busy ? 'Entrando…' : 'Entrar'}</button>\n      <div class=\"footer\">Acesso restrito • Modenafs</div>\n    </div></div>`;\n  },\n  mounted(d2) {\n    // d2.on(selectorString, 'input'|'change', fn) delegation does not fire for\n    // form controls on this CodeHost build (click delegation works fine) —\n    // bind directly to the elements instead, same fix applied across the\n    // other business screens in this project.\n    const bind = (sel, evt, apply) => {\n      const el = d2.$(sel);\n      if (el) d2.on(el, evt, (e) => apply(e.target.value));\n    };\n    bind('[data-role=\"email\"]', 'input', (v) => { d2.state.email = v; });\n    bind('[data-role=\"password\"]', 'input', (v) => { d2.state.password = v; });\n    const submit = async () => {\n      if (d2.state.busy) return;\n      d2.state.busy = true;\n      d2.state.error = '';\n      try {\n        const res = await d2.auth('appAuth').login({ credentials: { email: d2.state.email, password: d2.state.password } });\n        if (res && res.token) {\n          d2.router('vendasMobileRouter').goTo('/');\n        } else {\n          d2.state.error = 'Email ou senha inválidos';\n        }\n      } catch (e) {\n        d2.state.error = 'Email ou senha inválidos';\n      } finally {\n        d2.state.busy = false;\n      }\n    };\n    const submitBtn = d2.$('[data-role=\"submit\"]');\n    if (submitBtn) d2.on(submitBtn, 'click', submit);\n    d2.on(d2.root, 'keydown', (e) => { if (e.key === 'Enter') submit(); });\n  },\n};\n\nfunction esc(s) { return String(s == null ? '' : s).replace(/[&<>\"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[c])); }\n"}}}}}},"__d2PrevCode":{"code":"export default {\n  css: `\n    * { box-sizing: border-box; }\n    :host, .wrap { height: 100%; }\n    .wrap {\n      height: 100%; display: flex; align-items: center; justify-content: center;\n      background: linear-gradient(135deg,#0d0d12,#1c1c26);\n      font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n      color: #ffffff; padding: 24px;\n    }\n    .card { width: 100%; max-width: 360px; }\n    .brand { font-size: 13px; font-weight: 700; letter-spacing: 3px; color: #8a8a9a; margin-bottom: 8px; }\n    .title { font-size: 26px; font-weight: 800; margin-bottom: 28px; }\n    .field { margin-bottom: 16px; }\n    .field label { display: block; font-size: 12px; font-weight: 600; color: #9a9aab; margin-bottom: 6px; }\n    .field input {\n      width: 100%; background: #0d0d12; border: 1px solid rgba(255,255,255,.08); border-radius: 12px;\n      padding: 14px; color: #ffffff; font-size: 15px; outline: none;\n    }\n    .field input:focus { border-color: #6d5efc; }\n    .error { color: #ff6b6b; font-size: 13px; margin-bottom: 12px; min-height: 18px; }\n    .btn {\n      width: 100%; padding: 15px; border: none; border-radius: 12px;\n      background: linear-gradient(135deg,#6d5efc,#8f7bff); color: #ffffff; font-weight: 700; font-size: 15px; cursor: pointer;\n    }\n    .btn:disabled { opacity: .6; cursor: default; }\n    .footer { text-align: center; font-size: 11px; color: #55556a; margin-top: 24px; }\n  `,\n  render(d2) {\n    const email = d2.state.email || '';\n    const password = d2.state.password || '';\n    const error = d2.state.error || '';\n    const busy = d2.state.busy;\n    return `<div class=\"wrap\"><div class=\"card\">\n      <div class=\"brand\">MODENAFS</div>\n      <div class=\"title\">Bem-vindo de volta</div>\n      <div class=\"field\"><label>Email</label><input type=\"email\" data-role=\"email\" value=\"${esc(email)}\" placeholder=\"voce@exemplo.com\" /></div>\n      <div class=\"field\"><label>Senha</label><input type=\"password\" data-role=\"password\" value=\"${esc(password)}\" placeholder=\"••••••••\" /></div>\n      <div class=\"error\">${esc(error)}</div>\n      <button class=\"btn\" data-role=\"submit\" ${busy ? 'disabled' : ''}>${busy ? 'Entrando…' : 'Entrar'}</button>\n      <div class=\"footer\">Acesso restrito • Modenafs</div>\n    </div></div>`;\n  },\n  mounted(d2) {\n    d2.on('[data-role=\"email\"]', 'input', (e, el) => { d2.state.email = el.value; });\n    d2.on('[data-role=\"password\"]', 'input', (e, el) => { d2.state.password = el.value; });\n    const submit = async () => {\n      if (d2.state.busy) return;\n      d2.state.busy = true;\n      d2.state.error = '';\n      try {\n        const res = await d2.auth('appAuth').login({ credentials: { email: d2.state.email, password: d2.state.password } });\n        if (res && res.token) {\n          d2.router('vendasMobileRouter').goTo('/');\n        } else {\n          d2.state.error = 'Email ou senha inválidos';\n        }\n      } catch (e) {\n        d2.state.error = 'Email ou senha inválidos';\n      } finally {\n        d2.state.busy = false;\n      }\n    };\n    d2.on('[data-role=\"submit\"]', 'click', submit);\n    d2.on(d2.root, 'keydown', (e) => { if (e.key === 'Enter') submit(); });\n  },\n};\n\nfunction esc(s) { return String(s == null ? '' : s).replace(/[&<>\"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[c])); }\n","at":"2026-08-05T17:17:52.669Z"}}},{"_id":"6a733b065237770e05d026cf","component":"data2-core-types@Component","system":"6a26a4d06aecdcf58a4260e0","params":{"extends":"data2-core-primitives@Block","component":"appShell","package":"modenafs-app","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"const NAV_ITEMS = [\n  { key: 'geral', label: 'Visão Geral', path: '/' },\n  { key: 'vendas', label: 'Vendas', path: '/vendas' },\n  { key: 'anuncios', label: 'Anúncios', path: '/anuncios' },\n  { key: 'catalogo', label: 'Catálogo', path: '/catalogo' },\n  { key: 'manutencao', label: 'Manutenção', path: '/manutencao' },\n  { key: 'promocoes', label: 'Promoções', path: '/promocoes' },\n  { key: 'fiscal', label: 'Dados Fiscais', path: '/fiscal' },\n  { key: 'publicar', label: 'Publicar', path: '/publicar' },\n  { key: 'configuracoes', label: 'Configurações', path: '/configuracoes', disabled: true },\n];\n\nconst SOON_LABEL = {\n  '/configuracoes': 'Configurações',\n};\n\nfunction buildDailyChartSvg(daily) {\n  const W = 640, H = 170, padL = 6, padR = 6, padT = 10, padB = 22;\n  const innerW = W - padL - padR;\n  const innerH = H - padT - padB;\n  const n = Math.max(1, daily.length);\n  const maxRev = Math.max(1, ...daily.map((d) => d.revenue));\n  const colW = innerW / n;\n  const gridLines = [0.25, 0.5, 0.75].map((f) => {\n    const y = (padT + innerH * f).toFixed(1);\n    return `<line class=\"grid\" x1=\"${padL}\" y1=\"${y}\" x2=\"${W - padR}\" y2=\"${y}\"></line>`;\n  }).join('');\n  const baseline = `<line class=\"baseline\" x1=\"${padL}\" y1=\"${padT + innerH}\" x2=\"${W - padR}\" y2=\"${padT + innerH}\"></line>`;\n  const bars = daily.map((d, i) => {\n    const h = Math.max(1, Math.round((d.revenue / maxRev) * innerH));\n    const x = padL + i * colW;\n    const y = padT + (innerH - h);\n    const w = Math.max(1, colW * 0.6);\n    return `<rect class=\"bar\" data-idx=\"${i}\" x=\"${(x + (colW - w) / 2).toFixed(1)}\" y=\"${y}\" width=\"${w.toFixed(1)}\" height=\"${h}\" rx=\"2\"></rect>`;\n  }).join('');\n  const step = Math.max(1, Math.ceil(n / 7));\n  const labels = daily.map((d, i) => {\n    if (i % step !== 0 && i !== n - 1) return '';\n    const x = (padL + i * colW + colW / 2).toFixed(1);\n    return `<text class=\"axislabel\" x=\"${x}\" y=\"${H - 6}\" text-anchor=\"middle\">${esc(d.label)}</text>`;\n  }).join('');\n  return `<svg class=\"daily-chart\" data-padl=\"${padL}\" data-innerw=\"${innerW}\" viewBox=\"0 0 ${W} ${H}\" preserveAspectRatio=\"none\">\n    ${gridLines}${baseline}${bars}${labels}\n  </svg>`;\n}\n\nfunction buildHourlyChartSvg(hourly) {\n  const W = 640, H = 60, padL = 4, padR = 4, padT = 6, padB = 4;\n  const innerW = W - padL - padR;\n  const innerH = H - padT - padB;\n  const n = Math.max(1, hourly.length);\n  const maxRev = Math.max(1, ...hourly.map((h) => h.revenue));\n  const colW = innerW / n;\n  const pts = hourly.map((h, i) => {\n    const x = padL + i * colW + colW / 2;\n    const y = padT + (innerH - Math.max(0, (h.revenue / maxRev) * innerH));\n    return `${x.toFixed(1)},${y.toFixed(1)}`;\n  });\n  const path = `M${pts.join(' L')}`;\n  const areaPath = `M${padL},${padT + innerH} L${pts.join(' L')} L${(padL + innerW).toFixed(1)},${padT + innerH} Z`;\n  return `<svg class=\"hourly-chart\" data-padl=\"${padL}\" data-innerw=\"${innerW}\" viewBox=\"0 0 ${W} ${H}\" preserveAspectRatio=\"none\">\n    <path class=\"sparkline-fill\" d=\"${areaPath}\"></path>\n    <path class=\"sparkline-path\" d=\"${path}\"></path>\n  </svg>`;\n}\n\nfunction bindChartHover(d2, svgSelector, tooltipSelector, itemsFn, formatFn) {\n  const svg = d2.$(svgSelector);\n  const tooltip = d2.$(tooltipSelector);\n  if (!svg || !tooltip || svg.dataset.hoverBound) return;\n  svg.dataset.hoverBound = '1';\n  const wrap = svg.closest('.chart-wrap') || svg;\n  d2.on(svg, 'mousemove', (e) => {\n    const items = itemsFn(d2);\n    if (!items || !items.length) return;\n    const vb = svg.viewBox.baseVal;\n    const bbox = svg.getBoundingClientRect();\n    if (!bbox.width) return;\n    const vbX = ((e.clientX - bbox.left) / bbox.width) * vb.width;\n    const padL = Number(svg.dataset.padl) || 0;\n    const innerW = Number(svg.dataset.innerw) || vb.width;\n    const colW = innerW / items.length;\n    let idx = Math.floor((vbX - padL) / colW);\n    idx = Math.max(0, Math.min(items.length - 1, idx));\n    svg.querySelectorAll('.bar').forEach((b) => b.classList.remove('active'));\n    const activeBar = svg.querySelector(`.bar[data-idx=\"${idx}\"]`);\n    if (activeBar) activeBar.classList.add('active');\n    const { title, value } = formatFn(items[idx]);\n    tooltip.innerHTML = `<div class=\"d\">${esc(title)}</div><div class=\"v\">${esc(value)}</div>`;\n    tooltip.style.display = 'block';\n    const wrapRect = wrap.getBoundingClientRect();\n    tooltip.style.left = `${e.clientX - wrapRect.left}px`;\n    tooltip.style.top = `${e.clientY - wrapRect.top}px`;\n  });\n  d2.on(svg, 'mouseleave', () => {\n    tooltip.style.display = 'none';\n    svg.querySelectorAll('.bar').forEach((b) => b.classList.remove('active'));\n  });\n}\n\nfunction bindGeralCharts(d2) {\n  bindChartHover(d2, '.daily-chart', '[data-role=\"daily-tooltip\"]',\n    () => (d2.state.geral && d2.state.geral.daily) || [],\n    (d) => ({ title: d.dateLabel || d.label, value: `R$ ${d.revenue.toFixed(2)}` }));\n  bindChartHover(d2, '.hourly-chart', '[data-role=\"hourly-tooltip\"]',\n    () => (d2.state.geral && d2.state.geral.hourly) || [],\n    (h) => ({ title: `${String(h.hour).padStart(2, '0')}h`, value: `R$ ${h.revenue.toFixed(2)} · ${h.count} pedido${h.count === 1 ? '' : 's'}` }));\n}\n\nfunction triggerGeralLoad(d2) {\n  if (d2.state._geralLoading) return;\n  loadGeral(d2).finally(() => { d2.state._geralLoading = false; });\n}\n\nasync function loadPlugStatus(d2) {\n  d2.state._plugStatusLoading = true;\n  try {\n    const ds = await waitForDataset(d2, 'integrationTokensDs');\n    const rows = await ds.query({ service: 'plug' });\n    const rowsArr = Array.isArray(rows) ? rows : (rows && Array.isArray(rows.data) ? rows.data : []);\n    const rec = rowsArr[0] || null;\n    const updatedAtMs = rec && rec.updatedAt ? Date.parse(rec.updatedAt) : NaN;\n    d2.state.plugStatus = {\n      hasToken: !!(rec && rec.access_token),\n      updatedAtMs: Number.isFinite(updatedAtMs) ? updatedAtMs : null,\n    };\n  } catch (e) {\n    d2.state.plugStatus = { hasToken: false, updatedAtMs: null, error: (e && e.message) || String(e) };\n  } finally {\n    d2.state._plugStatusLoading = false;\n  }\n}\n\nfunction triggerPlugStatusLoad(d2) {\n  if (d2.state._plugStatusLoading) return;\n  loadPlugStatus(d2);\n}\n\nfunction plugStatusView(d2) {\n  const s = d2.state.plugStatus;\n  if (!s) return { label: 'checando…', cls: 'pending' };\n  if (!s.hasToken) return { label: 'erro', cls: 'bad' };\n  const ageSec = s.updatedAtMs ? Math.max(0, Math.round((Date.now() - s.updatedAtMs) / 1000)) : null;\n  if (ageSec === null || ageSec > 900) return { label: 'expirado', cls: 'bad' };\n  return { label: 'ok', cls: 'good' };\n}\n\nfunction primaryCode(sku) {\n  if (!sku) return '';\n  return String(sku).split('-')[0].trim();\n}\n\nfunction buildBarListHtml(items) {\n  if (!items || !items.length) return '<div style=\"color:#8a8f9a;font-size:12px\">Sem dados no período.</div>';\n  const max = Math.max(1, ...items.map((i) => i.value));\n  return items.map((i) => {\n    const pct = Math.max(2, Math.round((i.value / max) * 100));\n    return `<div class=\"barrow\">\n      <div class=\"lbl wide\" title=\"${esc(i.label)}\">${esc(i.label)}</div>\n      <div class=\"track\"><div class=\"fill\" style=\"width:${pct}%\"></div></div>\n      <div class=\"val wide\">${esc(i.valueLabel)}</div>\n    </div>`;\n  }).join('');\n}\n\nconst ADV_MARGIN_B = [['<0%', -1e9, 0], ['0-10%', 0, 10], ['10-20%', 10, 20], ['20-30%', 20, 30], ['30-50%', 30, 50], ['50%+', 50, 1e9]];\nconst ADV_DEMAND_B = [['0', -1, 1], ['1-4', 1, 5], ['5-19', 5, 20], ['20-99', 20, 100], ['100+', 100, 1e12]];\nconst ADV_PRICE_B = [['<R$50', 0, 50], ['50-150', 50, 150], ['150-300', 150, 300], ['300-600', 300, 600], ['600+', 600, 1e12]];\nconst ADV_DISC_B = [['sem promo', -1, 0.5], ['1-10%', 0.5, 10], ['10-20%', 10, 20], ['20-40%', 20, 40], ['40%+', 40, 1e9]];\nconst ADV_ADS_B = [['0', -1, 0.5], ['1-3', 0.5, 4], ['4-7', 4, 8], ['8+', 8, 1e9]];\nconst ADV_COMP_B = [['<=10', -1, 11], ['11-25', 11, 26], ['26-47', 26, 48], ['48+', 48, 1e9]];\nconst ADV_BAND_DIMS = { margin: ADV_MARGIN_B, demand: ADV_DEMAND_B, price: ADV_PRICE_B, discount: ADV_DISC_B, ads: ADV_ADS_B, competition: ADV_COMP_B };\nconst ADV_DIM_LABELS = [['category', 'categoria'], ['brand', 'marca'], ['margin', 'faixa de margem'], ['demand', 'faixa de demanda'], ['price', 'faixa de preco'], ['discount', 'faixa de desconto'], ['ads', 'faixa de ADS'], ['competition', 'faixa de concorrencia']];\nconst ADV_VALUE_LABELS = [['count', 'no de SKUs'], ['avg_margin', 'margem media %'], ['profit', 'lucro unit. somado (R$)'], ['demand', 'demanda total (unid. vendidas)'], ['ads', 'anuncios patrocinados'], ['promo', 'anuncios em promocao'], ['disc_avg', 'desconto medio %'], ['avg_competition', 'concorrencia media']];\nconst ADV_VALUE_KIND = { count: 'int', avg_margin: 'pct', profit: 'money', demand: 'int', ads: 'int', promo: 'int', disc_avg: 'pct', avg_competition: 'num' };\nconst ADV_LENS_INFO = {\n  boi_piranha: { label: 'Boi de piranha', hint: 'Os mais vendidos entre os mais baratos (ticket abaixo da mediana) -- peca popular e barata pra atrair trafego/venda.' },\n  baixar_mais: { label: 'Da pra baixar mais', hint: 'Margem acima do piso minimo (12%) -- headroom = quanto da pra cortar do preco e ainda bater a margem minima.' },\n  make_market: { label: 'Fazer mercado', hint: 'Tem demanda e pouca concorrencia -- facil ganhar share. market score = vendidos / (concorrentes+1).' },\n  absolute: { label: 'Lucro absoluto', hint: 'Maior lucro em R$ por unidade (preco menos custo).' },\n  margin: { label: 'Maior margem', hint: 'Maior margem % sobre o preco.' },\n  best_sellers: { label: 'Mais vendidos', hint: 'Mais vendidos (unidades, historico de pedidos pagos).' },\n};\n\nexport default {\n  css: `\n    * { box-sizing: border-box; }\n    :host, .shell { height: 100%; }\n    .shell {\n      display: flex; height: 100%; overflow: hidden;\n      background: #0f1115; color: #e7e4da;\n      font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n    }\n    .nav { width: 240px; flex: none; background: #14171d; border-right: 1px solid #262b33; display: flex; flex-direction: column; }\n    .brand { padding: 22px 20px 18px; font-size: 13px; font-weight: 800; letter-spacing: 3px; color: #6f9bef; }\n    .navlist { flex: 1; overflow-y: auto; padding: 4px 12px; display: flex; flex-direction: column; gap: 2px; }\n    .navitem {\n      display: flex; align-items: center; justify-content: space-between; gap: 8px;\n      padding: 10px 12px; border-radius: 8px; font-size: 13px; font-weight: 600; color: #9aa0ab;\n      cursor: pointer; border-left: 3px solid transparent;\n    }\n    .navitem:hover { background: #1b1f26; color: #e7e4da; }\n    .navitem.active { background: #1b1f26; color: #ffffff; border-left-color: #6f9bef; }\n    .navitem.disabled { cursor: default; color: #4b5058; }\n    .navitem.disabled:hover { background: transparent; color: #4b5058; }\n    .soon { font-size: 9px; text-transform: uppercase; letter-spacing: .03em; color: #6b7280; background: #1b1f26; padding: 2px 6px; border-radius: 999px; }\n    .userbox { padding: 14px 16px; border-top: 1px solid #262b33; display: flex; flex-direction: column; gap: 8px; }\n    .useremail { font-size: 11.5px; color: #8a8f9a; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n    .logout { font-size: 12px; font-weight: 700; color: #e2685a; background: none; border: none; cursor: pointer; text-align: left; padding: 0; }\n    .plugstatus { display: flex; align-items: center; gap: 6px; font-size: 10.5px; color: #8a8f9a; cursor: pointer; user-select: none; background: none; border: none; padding: 0; font-family: inherit; }\n    .plugstatus .dot { width: 7px; height: 7px; border-radius: 999px; background: #6b7280; flex: none; }\n    .plugstatus.good .dot { background: #5cbd8a; }\n    .plugstatus.bad .dot { background: #e2685a; }\n    .plugstatus.pending .dot { background: #6b7280; }\n    .plugstatus:hover { color: #e7e4da; }\n    .content { flex: 1; min-width: 0; overflow: auto; }\n    .panel-light { padding: 20px; height: 100%; }\n    .panel-card { background: #f7f7fa; border-radius: 16px; overflow: hidden; height: 100%; }\n    .soon-page { display: flex; align-items: center; justify-content: center; height: 100%; flex-direction: column; gap: 8px; color: #6b7280; }\n    .soon-page .t { font-size: 18px; font-weight: 800; color: #e7e4da; }\n    /* ===== MODENAFS shared design tokens — Visão Geral dashboard content only.\n       Scoped by usage: only renderGeral() markup emits these classes, so nothing\n       bleeds into the .nav sidebar or the login screen (which don't use them). */\n    .panel {\n      background: #14171d; border: 1px solid #242932; border-radius: 14px;\n      padding: 16px 18px; box-shadow: 0 4px 18px rgba(0,0,0,.3), 0 1px 3px rgba(0,0,0,.25);\n    }\n    .panel + .panel { margin-top: 14px; }\n    .panel-h {\n      font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: #8a8f9a;\n      margin-bottom: 12px; display: flex; align-items: center; gap: 7px; font-weight: 700;\n    }\n    .kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px,1fr)); gap: 12px; }\n    .kpi {\n      background: #171b21; border: 1px solid #242932; border-radius: 12px; padding: 13px 16px;\n      border-left: 3px solid #2a2f38; display: flex; flex-direction: column; gap: 4px;\n    }\n    .kpi .l { font-size: 10px; text-transform: uppercase; letter-spacing: .05em; color: #8a8f9a; font-weight: 600; }\n    .kpi .n { font-size: 23px; font-weight: 800; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }\n    .kpi.crit { border-left-color: #e2685a; } .kpi.crit .n { color: #e2685a; }\n    .kpi.warn { border-left-color: #e2a24a; } .kpi.warn .n { color: #e2a24a; }\n    .kpi.good { border-left-color: #5cbd8a; } .kpi.good .n { color: #5cbd8a; }\n    .pill {\n      display: inline-flex; align-items: center; gap: 4px; padding: 3px 9px; border-radius: 20px;\n      font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; white-space: nowrap;\n    }\n    .pill.good { background: rgba(92,189,138,.15); color: #5cbd8a; }\n    .pill.warn { background: rgba(226,162,74,.15); color: #e2a24a; }\n    .pill.bad { background: rgba(226,104,90,.15); color: #e2685a; }\n    .pill.accent { background: rgba(77,118,201,.18); color: #7ea2e8; }\n    .pill.muted { background: rgba(138,143,154,.15); color: #8a8f9a; }\n    .error-state {\n      padding: 16px 20px; color: #e2685a; font-size: 12.5px; background: rgba(226,104,90,.08);\n      border: 1px solid rgba(226,104,90,.3); border-radius: 10px; display: flex; align-items: center; gap: 12px; flex-wrap: wrap;\n    }\n    .error-state .btn-retry {\n      background: rgba(226,104,90,.18); color: #e2685a; border: 1px solid rgba(226,104,90,.4);\n      border-radius: 6px; padding: 6px 12px; font-size: 11.5px; font-weight: 700; cursor: pointer;\n    }\n    .error-state .btn-retry:hover { background: rgba(226,104,90,.28); }\n    .geral { padding: 28px 32px; height: 100%; overflow-y: auto; }\n    .geral h1 { font-size: 20px; font-weight: 800; margin: 0 0 20px; }\n    .geral .kpis { margin-bottom: 20px; }\n    .dash-grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 14px; align-items: start; }\n    .dash-grid .panel { margin-top: 0; }\n    .dash-grid .panel.wide { grid-column: 1 / -1; }\n    @media (max-width: 900px) { .dash-grid { grid-template-columns: 1fr; } }\n    .barrow { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }\n    .barrow:last-child { margin-bottom: 0; }\n    .barrow .lbl { width: 60px; font-size: 11px; color: #8a8f9a; flex: none; font-variant-numeric: tabular-nums; }\n    .barrow .track { flex: 1; height: 14px; background: #1b1f26; border-radius: 4px; overflow: hidden; }\n    .barrow .fill { height: 100%; background: linear-gradient(90deg,#4d76c9,#6f9bef); }\n    .barrow .val { width: 90px; text-align: right; font-size: 11px; font-variant-numeric: tabular-nums; color: #cbd0d8; flex: none; }\n    .barrow .lbl.wide { width: 168px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n    .barrow .val.wide { width: 128px; }\n    .statuschips { display: flex; gap: 10px; flex-wrap: wrap; }\n    .chart-wrap { position: relative; margin-top: 4px; }\n    .chart-wrap svg { width: 100%; height: 170px; display: block; overflow: visible; }\n    .chart-wrap.small svg { height: 60px; }\n    .grid { stroke: #23272f; stroke-width: 1; }\n    .baseline { stroke: #383e48; stroke-width: 1; }\n    .bar { fill: #4d76c9; transition: fill .12s; }\n    .bar.active { fill: #6f9bef; }\n    .axislabel { fill: #6b7280; font-size: 8px; font-family: inherit; }\n    .sparkline-path { fill: none; stroke: #6f9bef; stroke-width: 1.6; }\n    .sparkline-fill { fill: rgba(111,155,239,0.16); stroke: none; }\n    .chart-tooltip {\n      position: absolute; pointer-events: none; display: none; z-index: 5;\n      background: #1b1f26; border: 1px solid #2a2f38; border-radius: 6px; padding: 6px 10px;\n      font-size: 11px; color: #e7e4da; white-space: nowrap; transform: translate(-50%, -100%);\n      box-shadow: 0 4px 12px rgba(0,0,0,.4);\n    }\n    .chart-tooltip .d { color: #8a8f9a; font-size: 9.5px; text-transform: uppercase; letter-spacing: .03em; }\n    .chart-tooltip .v { font-weight: 700; margin-top: 2px; }\n    .barrow .val.wide { width: 172px; display: flex; align-items: center; justify-content: flex-end; gap: 6px; }\n    .heatmap-grid { display: grid; grid-template-columns: 62px repeat(6, 1fr); gap: 3px; margin-top: 4px; }\n    .heat-col-h { font-size: 9px; color: #6b7280; text-align: center; padding: 4px 2px; text-transform: uppercase; letter-spacing: .03em; }\n    .heat-row-h { font-size: 10.5px; color: #8a8f9a; display: flex; align-items: center; padding: 0 6px; font-weight: 600; }\n    .heat-cell { border-radius: 6px; min-height: 30px; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700; }\n    .chart-host { margin-top: 2px; }\n    .chart-legend { margin-top: 8px; font-size: 10.5px; color: #8a8f9a; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }\n    .route-error-page { padding: 28px 32px; height: 100%; box-sizing: border-box; overflow-y: auto; }\n    .adv-toggle-row { margin-top: 14px; }\n    .adv-toggle-btn { width: 100%; text-align: left; background: #14171d; border: 1px dashed #2a2f38; color: #9aa0ab; border-radius: 10px; padding: 10px 14px; font-size: 12px; font-weight: 700; cursor: pointer; }\n    .adv-toggle-btn:hover { background: #171b21; color: #e7e4da; border-color: #3a4048; }\n    .adv-section { margin-top: 14px; }\n    .adv-empty { color: #8a8f9a; font-size: 12px; padding: 10px 0; }\n    .adv-heatctl { display: flex; gap: 16px; flex-wrap: wrap; margin: 6px 0 8px; font-size: 11px; color: #8a8f9a; align-items: center; }\n    .adv-heatctl select { margin-left: 6px; background: #171b21; color: #e7e4da; border: 1px solid #2a2f38; border-radius: 6px; padding: 4px 8px; font-size: 11.5px; }\n    .adv-hint { font-size: 11px; color: #6b7280; margin-bottom: 10px; }\n    .adv-heatmap .heat-row-h { font-size: 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n    .adv-qgrid { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 10px; }\n    @media (max-width: 900px) { .adv-qgrid { grid-template-columns: repeat(2, 1fr); } }\n    .adv-qcell { border: 1px solid #242932; border-left-width: 3px; border-radius: 10px; padding: 12px 14px; cursor: pointer; background: #171b21; }\n    .adv-qcell:hover { background: #1b1f26; }\n    .adv-qcell.on { background: #1b1f26; box-shadow: inset 0 0 0 1px #3a4048; }\n    .adv-border-good { border-left-color: #5cbd8a; } .adv-border-warn { border-left-color: #e2a24a; }\n    .adv-border-accent { border-left-color: #7ea2e8; } .adv-border-muted { border-left-color: #8a8f9a; }\n    .adv-qn { font-size: 22px; font-weight: 800; }\n    .adv-qt { font-size: 11.5px; font-weight: 700; margin-top: 2px; }\n    .adv-qd { font-size: 10.5px; color: #8a8f9a; margin-top: 2px; }\n    .adv-good { color: #5cbd8a; } .adv-warn { color: #e2a24a; } .adv-accent { color: #7ea2e8; } .adv-muted { color: #8a8f9a; }\n    .adv-lenstabs { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; }\n    .adv-lens-tab { background: #171b21; border: 1px solid #242932; color: #9aa0ab; border-radius: 999px; padding: 6px 12px; font-size: 11px; font-weight: 700; cursor: pointer; }\n    .adv-lens-tab.on { background: #6f9bef; color: #0f1115; border-color: #6f9bef; }\n    .adv-lenshint { font-size: 11px; margin-bottom: 10px; }\n    .adv-table { width: 100%; border-collapse: collapse; font-size: 11.5px; }\n    .adv-table th { text-align: left; color: #8a8f9a; font-size: 10px; text-transform: uppercase; letter-spacing: .03em; padding: 6px 8px; border-bottom: 1px solid #242932; }\n    .adv-table td { padding: 6px 8px; border-bottom: 1px solid #1b1f26; }\n    .adv-table th.num, .adv-table td.num { text-align: right; font-variant-numeric: tabular-nums; }\n    .adv-table .pdesc { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n  `,\n  render(d2) {\n    const path = d2.router('vendasMobileRouter').path || '/';\n    const user = d2.auth('appAuth').user;\n\n    if (path === '/' && !d2.state.geral && !d2.state.geralError && !d2.state._geralLoading) {\n      triggerGeralLoad(d2);\n    }\n\n    if (!d2.state.plugStatus && !d2.state._plugStatusLoading) {\n      triggerPlugStatusLoad(d2);\n    }\n    const plugStatus = plugStatusView(d2);\n\n    const navHtml = NAV_ITEMS.map((it) => {\n      const active = path === it.path;\n      return `<div class=\"navitem ${active ? 'active' : ''} ${it.disabled ? 'disabled' : ''}\" data-path=\"${it.path}\" data-disabled=\"${it.disabled ? '1' : '0'}\">\n        <span>${it.label}</span>\n        ${it.disabled ? '<span class=\"soon\">em breve</span>' : ''}\n      </div>`;\n    }).join('');\n\n    let contentHtml;\n    if (path === '/vendas') {\n      try {\n        contentHtml = `<div class=\"panel-light\"><div class=\"panel-card\">${d2.render('modenafs-app@zJlTKXWalfhfnfsLp3MHw', { dataset: d2.param('salesDs') }, { key: 'vendas', style: 'height:100%;display:block' })}</div></div>`;\n      } catch (e) {\n        contentHtml = renderRouteError('Vendas', e);\n      }\n    } else if (path === '/anuncios') {\n      try {\n        contentHtml = d2.render('modenafs-app@b2GYj4kRIi3poqaRT5yT8', {\n          mlAdsDs: d2.param('mlAdsDs'), plugDs: d2.param('plugDs'), productsDs: d2.param('productsDs'), settingsDs: d2.param('settingsDs'),\n          freteRealDs: d2.param('freteRealDs'),\n        }, { key: 'anuncios', style: 'height:100%;display:block' });\n      } catch (e) {\n        contentHtml = renderRouteError('Anúncios', e);\n      }\n    } else if (path === '/manutencao') {\n      try {\n        contentHtml = d2.render('modenafs-app@manutencaoCC', {\n          mlAdsDs: d2.param('mlAdsDs'), plugDs: d2.param('plugDs'),\n        }, { key: 'manutencao', style: 'height:100%;display:block' });\n      } catch (e) {\n        contentHtml = renderRouteError('Manutenção', e);\n      }\n    } else if (path === '/catalogo') {\n      try {\n        contentHtml = d2.render('modenafs-app@catalogoCC', {\n          mlAdsDs: d2.param('mlAdsDs'),\n        }, { key: 'catalogo', style: 'height:100%;display:block' });\n      } catch (e) {\n        contentHtml = renderRouteError('Catálogo', e);\n      }\n    } else if (path === '/promocoes') {\n      try {\n        contentHtml = d2.render('modenafs-app@promocoesCC', {\n          mlAdsDs: d2.param('mlAdsDs'), plugDs: d2.param('plugDs'), productsDs: d2.param('productsDs'),\n          settingsDs: d2.param('settingsDs'), freteRealDs: d2.param('freteRealDs'),\n        }, { key: 'promocoes', style: 'height:100%;display:block' });\n      } catch (e) {\n        contentHtml = renderRouteError('Promoções', e);\n      }\n    } else if (path === '/fiscal') {\n      try {\n        contentHtml = d2.render('modenafs-app@fiscalCC', {\n          mlAdsDs: d2.param('mlAdsDs'), plugDs: d2.param('plugDs'), productsDs: d2.param('productsDs'), settingsDs: d2.param('settingsDs'),\n        }, { key: 'fiscal', style: 'height:100%;display:block' });\n      } catch (e) {\n        contentHtml = renderRouteError('Dados Fiscais', e);\n      }\n    } else if (path === '/publicar') {\n      try {\n        contentHtml = d2.render('modenafs-app@publicarCC', {}, { key: 'publicar', style: 'height:100%;display:block' });\n      } catch (e) {\n        contentHtml = renderRouteError('Publicar', e);\n      }\n    } else if (SOON_LABEL[path]) {\n      contentHtml = `<div class=\"soon-page\"><div class=\"t\">${SOON_LABEL[path]}</div><div>Em construção — próximo item do backlog do broker.</div></div>`;\n    } else {\n      try {\n        contentHtml = renderGeral(d2);\n      } catch (e) {\n        contentHtml = `<div class=\"geral\"><h1>Visão geral</h1><div class=\"error-state\">\n          <span>Falha ao renderizar a visão geral: ${esc((e && e.message) || String(e))}</span>\n          <button class=\"btn-retry\" data-action=\"retry-geral\">Tentar novamente</button>\n        </div></div>`;\n      }\n    }\n\n    return `<div class=\"shell\">\n      <div class=\"nav\">\n        <div class=\"brand\">MODENAFS</div>\n        <div class=\"navlist\">${navHtml}</div>\n        <div class=\"userbox\">\n          <div class=\"useremail\">${esc((user && user.email) || '')}</div>\n          <button class=\"plugstatus ${plugStatus.cls}\" data-action=\"refresh-plug-status\" title=\"Integração Plug — clique para atualizar\">\n            <span class=\"dot\"></span>Plug: ${plugStatus.label}\n          </button>\n          <button class=\"logout\" data-action=\"logout\">Sair</button>\n        </div>\n      </div>\n      <div class=\"content\">${contentHtml}</div>\n      ${d2.render('modenafs-app@fichaCC', {\n        mlAdsDs: d2.param('mlAdsDs'), plugDs: d2.param('plugDs'), productsDs: d2.param('productsDs'),\n        freteRealDs: d2.param('freteRealDs'), snapshotsDs: 'snapshotsDataSet',\n        itemVisitsDs: 'item-visitsDataSet', contentDs: 'contentDataSet',\n      }, { key: 'ficha-overlay', width: 0, height: 0, style: 'overflow:visible;pointer-events:none' })}\n    </div>`;\n  },\n  mounted(d2) {\n    d2.on('.navitem', 'click', (e, el) => {\n      if (el.dataset.disabled === '1') return;\n      d2.router('vendasMobileRouter').goTo(el.dataset.path);\n    });\n    d2.on('[data-action=\"logout\"]', 'click', async () => {\n      await d2.auth('appAuth').logout();\n      d2.router('vendasMobileRouter').goTo('/');\n    });\n    d2.on('[data-action=\"retry-geral\"]', 'click', () => {\n      d2.state.geral = null;\n      d2.state.geralError = null;\n      triggerGeralLoad(d2);\n    });\n    d2.on('[data-action=\"retry-route\"]', 'click', () => {\n      d2.refresh();\n    });\n    d2.on('[data-action=\"refresh-plug-status\"]', 'click', () => {\n      d2.state.plugStatus = null;\n      triggerPlugStatusLoad(d2);\n    });\n    d2.on('[data-action=\"toggle-advanced\"]', 'click', () => {\n      d2.state.advOpen = !d2.state.advOpen;\n      if (d2.state.advOpen && !d2.state.adv) loadAdvanced(d2);\n    });\n    d2.on('[data-action=\"retry-advanced\"]', 'click', () => {\n      d2.state.adv = null;\n      loadAdvanced(d2);\n    });\n    d2.on('.adv-qcell', 'click', (e, el) => {\n      if (!d2.state.adv) return;\n      const k = el.dataset.quad;\n      d2.state.adv = Object.assign({}, d2.state.adv, { openQuadrant: d2.state.adv.openQuadrant === k ? null : k });\n    });\n    d2.on('.adv-lens-tab', 'click', (e, el) => {\n      if (!d2.state.adv) return;\n      d2.state.adv = Object.assign({}, d2.state.adv, { lens: el.dataset.lens });\n    });\n    bindGeralCharts(d2);\n    bindAdvancedControls(d2);\n  },\n  updated(d2) {\n    bindGeralCharts(d2);\n    bindAdvancedControls(d2);\n  },\n};\n\nfunction esc(s) { return String(s == null ? '' : s).replace(/[&<>\"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[c])); }\nfunction compact(n) {\n  n = Number(n) || 0;\n  if (Math.abs(n) >= 1000) return (n / 1000).toFixed(1).replace('.0', '') + 'K';\n  return n.toFixed(0);\n}\n\nfunction renderRouteError(label, e) {\n  return `<div class=\"route-error-page\"><div class=\"error-state\">\n    <span>Falha ao renderizar ${esc(label)}: ${esc((e && e.message) || String(e))}</span>\n    <button class=\"btn-retry\" data-action=\"retry-route\">Tentar novamente</button>\n  </div></div>`;\n}\n\nfunction marginTierColor(pct) {\n  if (pct >= 20) return '#5cbd8a';\n  if (pct >= 10) return '#e2a24a';\n  return '#e2685a';\n}\n\nfunction heatColor(pct) {\n  if (!pct || pct <= 0) return '#171b21';\n  const c0 = [23, 27, 33];\n  const c1 = [111, 155, 239];\n  const t = Math.min(1, pct);\n  const rgb = c0.map((v, i) => Math.round(v + (c1[i] - v) * t));\n  return `rgb(${rgb[0]},${rgb[1]},${rgb[2]})`;\n}\n\nfunction advBand(bands, v) {\n  for (let i = 0; i < bands.length; i++) { if (v >= bands[i][1] && v < bands[i][2]) return bands[i][0]; }\n  return bands[bands.length - 1][0];\n}\nfunction advDimLabel(dim, m) {\n  if (dim === 'category') return m.category;\n  if (dim === 'brand') return m.brand === '—' ? null : m.brand;\n  const bands = ADV_BAND_DIMS[dim];\n  if (!bands) return m.category;\n  const map = { margin: m.margin, demand: m.demand, price: m.price, discount: m.discAvg, ads: m.ads, competition: m.comp };\n  const v = map[dim];\n  return (v === null || v === undefined) ? null : advBand(bands, v);\n}\nfunction advOrderedLabels(dim, counts, topN) {\n  if (ADV_BAND_DIMS[dim]) return ADV_BAND_DIMS[dim].map((b) => b[0]);\n  return Object.keys(counts).sort((a, b) => counts[b] - counts[a]).slice(0, topN);\n}\nfunction advZeroCell() { return { count: 0, msum: 0, mn: 0, profit: 0, demand: 0, ads: 0, promo: 0, discSum: 0, discN: 0, comp: 0 }; }\nfunction advCellValue(cell, kind) {\n  if (kind === 'count') return cell.count;\n  if (kind === 'avg_margin') return cell.mn ? Math.round((cell.msum / cell.mn) * 10) / 10 : null;\n  if (kind === 'profit') return Math.round(cell.profit);\n  if (kind === 'ads') return cell.ads;\n  if (kind === 'promo') return cell.promo;\n  if (kind === 'disc_avg') return cell.discN ? Math.round((cell.discSum / cell.discN) * 10) / 10 : null;\n  if (kind === 'avg_competition') return cell.count ? Math.round((cell.comp / cell.count) * 10) / 10 : null;\n  return cell.demand;\n}\nfunction computeAdvHeatmap(metrics, rowDim, colDim, valKind) {\n  const cells = {}; const rcount = {}; const ccount = {};\n  metrics.forEach((m) => {\n    const rl = advDimLabel(rowDim, m); const cl = advDimLabel(colDim, m);\n    if (rl == null || cl == null) return;\n    rcount[rl] = (rcount[rl] || 0) + 1; ccount[cl] = (ccount[cl] || 0) + 1;\n    if (!cells[rl]) cells[rl] = {};\n    const cell = cells[rl][cl] || (cells[rl][cl] = advZeroCell());\n    cell.count += 1; cell.demand += m.demand; cell.ads += m.ads; cell.promo += m.promoCount; cell.comp += m.comp;\n    if (m.discAvg != null) { cell.discSum += m.discAvg; cell.discN += 1; }\n    if (m.profit != null) cell.profit += m.profit;\n    if (m.margin != null) { cell.msum += m.margin; cell.mn += 1; }\n  });\n  const rows = advOrderedLabels(rowDim, rcount, 14);\n  const cols = advOrderedLabels(colDim, ccount, 10);\n  const cellsMatrix = rows.map((rl) => cols.map((cl) => advCellValue((cells[rl] && cells[rl][cl]) || advZeroCell(), valKind)));\n  return { rows: rows, cols: cols, cells: cellsMatrix, valueKind: ADV_VALUE_KIND[valKind] };\n}\nfunction computeAdvQuadrants(metrics) {\n  const withMargin = metrics.filter((m) => m.margin != null).map((m) => m.margin).sort((a, b) => a - b);\n  const marginMed = withMargin.length ? withMargin[Math.floor(withMargin.length / 2)] : 0;\n  const DEMAND_HI = 3;\n  const quad = { estrela: 0, vaca: 0, nicho: 0, duvida: 0 };\n  const items = { estrela: [], vaca: [], nicho: [], duvida: [] };\n  metrics.forEach((m) => {\n    if (m.margin == null) return;\n    const hd = m.demand >= DEMAND_HI; const hm = m.margin >= marginMed;\n    const k = hd && hm ? 'estrela' : hd ? 'vaca' : hm ? 'nicho' : 'duvida';\n    quad[k] += 1;\n    items[k].push(m);\n  });\n  Object.keys(items).forEach((k) => {\n    items[k].sort((a, b) => (k === 'nicho' || k === 'duvida') ? (((b.margin || 0) - (a.margin || 0)) || (b.demand - a.demand)) : ((b.demand - a.demand) || ((b.margin || 0) - (a.margin || 0))));\n    items[k] = items[k].slice(0, 30);\n  });\n  return { quad: quad, items: items, marginMed: marginMed };\n}\nfunction computeAdvCategoryPressure(metrics) {\n  const cats = {};\n  metrics.forEach((m) => {\n    const c = cats[m.category] || (cats[m.category] = { category: m.category, count: 0, comp: 0, ads: 0, promo: 0, discSum: 0, discN: 0 });\n    c.count += 1; c.comp += m.comp; c.ads += m.ads; c.promo += m.promoCount;\n    if (m.discAvg != null) { c.discSum += m.discAvg; c.discN += 1; }\n  });\n  return Object.keys(cats).map((k) => {\n    const c = cats[k];\n    return {\n      category: c.category, count: c.count,\n      avgCompetition: c.count ? Math.round((c.comp / c.count) * 10) / 10 : null,\n      adsRate: c.comp ? Math.round((1000 * c.ads) / c.comp) / 10 : 0,\n      promoRate: c.comp ? Math.round((1000 * c.promo) / c.comp) / 10 : 0,\n      discAvg: c.discN ? Math.round((c.discSum / c.discN) * 10) / 10 : null,\n    };\n  }).sort((a, b) => b.count - a.count).slice(0, 12);\n}\nfunction computeAdvBrands(metrics) {\n  const brands = {};\n  metrics.forEach((m) => {\n    if (!m.brand || m.brand === '—') return;\n    const b = brands[m.brand] || (brands[m.brand] = { brand: m.brand, count: 0, msum: 0, mn: 0, demand: 0 });\n    b.count += 1; b.demand += m.demand;\n    if (m.margin != null) { b.msum += m.margin; b.mn += 1; }\n  });\n  return Object.keys(brands).map((k) => {\n    const b = brands[k];\n    return { brand: b.brand, count: b.count, demand: b.demand, avgMargin: b.mn ? Math.round((b.msum / b.mn) * 10) / 10 : null };\n  }).sort((a, b) => b.count - a.count).slice(0, 14);\n}\nfunction computeAdvLenses(metrics) {\n  const cands = metrics.filter((m) => m.comp >= 4 && m.price && m.cost);\n  const sortedPrices = cands.map((m) => m.price).sort((a, b) => a - b);\n  const ticketMed = sortedPrices.length ? sortedPrices[Math.floor(sortedPrices.length / 2)] : 0;\n  const topN = (items, keyFn, n, whereFn) => {\n    const filtered = whereFn ? items.filter(whereFn) : items.slice();\n    return filtered.slice().sort((a, b) => (keyFn(b) || 0) - (keyFn(a) || 0)).slice(0, n);\n  };\n  return {\n    boi_piranha: topN(cands, (m) => m.demand, 30, (m) => m.demand > 0 && m.price <= ticketMed),\n    baixar_mais: topN(cands, (m) => m.headroom || 0, 30, (m) => !m.belowFloor && m.demand > 0 && (m.headroom || 0) > 0),\n    make_market: topN(cands, (m) => m.marketScore, 30, (m) => m.demand > 0),\n    absolute: topN(cands, (m) => m.profit, 30, null),\n    margin: topN(cands, (m) => m.margin, 30, null),\n    best_sellers: topN(cands, (m) => m.demand, 30, (m) => m.demand > 0),\n  };\n}\nfunction recomputeAdvHeatmap(d2) {\n  const a = d2.state.adv;\n  if (!a || !a.metrics) return;\n  const heatmap = computeAdvHeatmap(a.metrics, a.heatRow, a.heatCol, a.heatVal);\n  d2.state.adv = Object.assign({}, a, { heatmap: heatmap });\n}\nfunction bindAdvancedControls(d2) {\n  const bind = (id, key) => {\n    const el = d2.$('#' + id);\n    if (!el || el.dataset.bound) return;\n    el.dataset.bound = '1';\n    if (d2.state.adv && d2.state.adv[key]) el.value = d2.state.adv[key];\n    d2.on(el, 'change', () => {\n      if (!d2.state.adv) return;\n      const next = Object.assign({}, d2.state.adv);\n      next[key] = el.value;\n      d2.state.adv = next;\n      recomputeAdvHeatmap(d2);\n    });\n  };\n  bind('advHeatRow', 'heatRow');\n  bind('advHeatCol', 'heatCol');\n  bind('advHeatVal', 'heatVal');\n}\nasync function loadAdvanced(d2) {\n  const gen = (d2.state._advGen = (d2.state._advGen || 0) + 1);\n  d2.state.adv = Object.assign({}, d2.state.adv || {}, { loading: true, error: null });\n  try {\n    const productsDs = await waitForDataset(d2, 'productsDs');\n    const plugDs = await waitForDataset(d2, 'plugDs');\n    const mlAdsDs = await waitForDataset(d2, 'mlAdsDs');\n    const salesDs = await waitForDataset(d2, 'salesDs');\n    const arr = (r) => (Array.isArray(r) ? r : (r && Array.isArray(r.data) ? r.data : []));\n\n    const snapRes = await d2.rush('dash-adv-snapshots').invoke({});\n    if (d2.state._advGen !== gen) return;\n    const snapBody = (snapRes && snapRes.data) ? snapRes.data : snapRes;\n    const snapRows = arr(snapBody && snapBody.rows).filter((r) => r._id);\n    const codes = snapRows.map((r) => r._id);\n\n    const prodRes = await productsDs.aggregate([{ $match: { code: { $in: codes } } }, { $project: { _id: 0, code: 1, category: 1, description: 1 } }]);\n    const plugRes = await plugDs.aggregate([{ $match: { code: { $in: codes } } }, { $group: { _id: '$code', brand: { $first: '$brand' }, cost: { $first: '$cost' }, stock: { $sum: '$stock' } } }]);\n    const adsRes = await mlAdsDs.aggregate([{ $match: { code: { $in: codes }, status: 'active' } }, { $group: { _id: '$code', price: { $avg: '$price' } } }]);\n    const salesRes = await salesDs.aggregate([{ $match: { status: 'paid' } }, { $group: { _id: '$sku', units: { $sum: '$units' } } }]);\n    if (d2.state._advGen !== gen) return;\n\n    const catMap = {}; arr(prodRes).forEach((r) => { catMap[r.code] = r; });\n    const plugMap = {}; arr(plugRes).forEach((r) => { plugMap[r._id] = r; });\n    const priceMap = {}; arr(adsRes).forEach((r) => { priceMap[r._id] = r.price; });\n    const demandMap = {};\n    arr(salesRes).forEach((r) => {\n      const base = primaryCode(r._id);\n      demandMap[base] = (demandMap[base] || 0) + (Number(r.units) || 0);\n    });\n\n    const MIN_MARGIN_FLOOR = 12;\n    const metrics = snapRows.map((r) => {\n      const code = r._id;\n      const info = catMap[code] || {};\n      const plugInfo = plugMap[code] || {};\n      const price = priceMap[code] || null;\n      const cost = plugInfo.cost || null;\n      const margin = (price && cost) ? Math.round(((price - cost) / price) * 1000) / 10 : null;\n      const profit = (price && cost) ? Math.round((price - cost) * 100) / 100 : null;\n      const belowFloor = margin != null && margin < MIN_MARGIN_FLOOR;\n      const minProfitPrice = cost != null ? cost / (1 - MIN_MARGIN_FLOOR / 100) : null;\n      const headroom = (price && minProfitPrice && margin != null && margin >= MIN_MARGIN_FLOOR) ? Math.round((price - minProfitPrice) * 100) / 100 : null;\n      const comp = Number(r.comp) || 0;\n      const demand = demandMap[primaryCode(code)] || 0;\n      const rawCat = (info.category || 'Sem categoria').trim();\n      return {\n        code: code, description: info.description || code, category: rawCat ? rawCat.toUpperCase() : 'SEM CATEGORIA',\n        brand: plugInfo.brand || '—', price: price, cost: cost, margin: margin, profit: profit, demand: demand,\n        ads: Number(r.ads) || 0, comp: comp, promoCount: Number(r.promoCount) || 0,\n        discAvg: r.discN ? Math.round((r.discSum / r.discN) * 10) / 10 : null,\n        stock: plugInfo.stock != null ? plugInfo.stock : null,\n        belowFloor: belowFloor, headroom: headroom, marketScore: Math.round((demand / (comp + 1)) * 10) / 10,\n      };\n    });\n\n    const heatRow = (d2.state.adv && d2.state.adv.heatRow) || 'category';\n    const heatCol = (d2.state.adv && d2.state.adv.heatCol) || 'margin';\n    const heatVal = (d2.state.adv && d2.state.adv.heatVal) || 'count';\n    const heatmap = computeAdvHeatmap(metrics, heatRow, heatCol, heatVal);\n    const advQuad = computeAdvQuadrants(metrics);\n    const byCategory = computeAdvCategoryPressure(metrics);\n    const byBrand = computeAdvBrands(metrics);\n    const lenses = computeAdvLenses(metrics);\n    const priced = metrics.filter((m) => m.margin != null).length;\n\n    d2.state.adv = {\n      loading: false, error: null, metrics: metrics, heatRow: heatRow, heatCol: heatCol, heatVal: heatVal,\n      heatmap: heatmap, quad: advQuad.quad, quadItems: advQuad.items, marginMed: advQuad.marginMed,\n      byCategory: byCategory, byBrand: byBrand, lenses: lenses,\n      lens: (d2.state.adv && d2.state.adv.lens) || 'boi_piranha',\n      openQuadrant: (d2.state.adv && d2.state.adv.openQuadrant) || null,\n      priced: priced, universe: metrics.length,\n    };\n  } catch (e) {\n    if (d2.state._advGen !== gen) return;\n    d2.state.adv = Object.assign({}, d2.state.adv || {}, { loading: false, error: (e && e.message) || String(e) });\n  }\n}\n\nfunction renderAdvancedToggle(d2) {\n  const open = !!d2.state.advOpen;\n  const label = open ? 'ocultar analise avancada' : 'analise avancada';\n  return `<div class=\"adv-toggle-row\">\n    <button type=\"button\" class=\"adv-toggle-btn\" data-action=\"toggle-advanced\">${label}</button>\n  </div>`;\n}\n\nfunction buildAdvHeatmapHtml(hm) {\n  if (!hm || !hm.rows.length) return '<div class=\"adv-empty\">Sem dados para essas dimensoes.</div>';\n  const flat = hm.cells.reduce((acc, row) => acc.concat(row), []).filter((v) => v != null).map((v) => Math.abs(v));\n  const maxAbs = Math.max(1, flat.length ? Math.max.apply(null, flat) : 1);\n  const fmt = (v) => {\n    if (v == null) return '-';\n    if (v === 0) return '0';\n    if (hm.valueKind === 'money') return Math.abs(v) >= 1000 ? `R$ ${Math.round(v / 1000)}k` : `R$ ${Math.round(v)}`;\n    if (hm.valueKind === 'pct') return `${v}%`;\n    return Number(v).toLocaleString('pt-BR');\n  };\n  const bg = (v) => {\n    if (v == null) return '#171b21';\n    if (hm.valueKind === 'pct') return v >= 20 ? 'rgba(92,189,138,.4)' : v >= 10 ? 'rgba(226,162,74,.4)' : 'rgba(226,104,90,.4)';\n    return heatColor(Math.abs(v) / maxAbs);\n  };\n  const fg = (v) => (v != null && hm.valueKind !== 'pct' && Math.abs(v) / maxAbs > 0.55) ? '#0f1115' : '#cbd0d8';\n  const colHeads = hm.cols.map((c) => `<div class=\"heat-col-h\">${esc(c)}</div>`).join('');\n  const body = hm.rows.map((rl, ri) => {\n    const rowCells = hm.cells[ri].map((v) => `<div class=\"heat-cell\" style=\"background:${bg(v)};color:${fg(v)}\" title=\"${esc(rl)}\">${fmt(v)}</div>`).join('');\n    return `<div class=\"heat-row-h\" title=\"${esc(rl)}\">${esc(rl)}</div>${rowCells}`;\n  }).join('');\n  return `<div class=\"heatmap-grid adv-heatmap\" style=\"grid-template-columns:110px repeat(${hm.cols.length},1fr)\">\n    <div></div>${colHeads}${body}\n  </div>`;\n}\n\nfunction buildAdvQuadrantHtml(adv) {\n  const q = adv.quad || {};\n  const defs = [\n    ['estrela', 'Estrelas', 'alta demanda + alta margem', 'good'],\n    ['vaca', 'Volume', 'alta demanda, margem fina', 'warn'],\n    ['nicho', 'Nicho', 'baixa demanda, margem alta', 'accent'],\n    ['duvida', 'Duvida', 'baixa demanda + margem baixa', 'muted'],\n  ];\n  const cellsHtml = defs.map((d) => {\n    const k = d[0]; const t = d[1]; const desc = d[2]; const c = d[3];\n    return `<div class=\"adv-qcell adv-border-${c} ${adv.openQuadrant === k ? 'on' : ''}\" data-quad=\"${k}\">\n    <div class=\"adv-qn adv-${c}\">${(q[k] || 0).toLocaleString('pt-BR')}</div>\n    <div class=\"adv-qt\">${t} &rsaquo;</div><div class=\"adv-qd\">${desc}</div></div>`;\n  }).join('');\n  let detail = '';\n  if (adv.openQuadrant && adv.quadItems && adv.quadItems[adv.openQuadrant] && adv.quadItems[adv.openQuadrant].length) {\n    const rows = adv.quadItems[adv.openQuadrant].slice(0, 10);\n    const rowsHtml = rows.map((m) => {\n      const marginTxt = m.margin != null ? `${Math.round(m.margin)}%` : '-';\n      const profitTxt = m.profit != null ? `R$ ${m.profit.toFixed(2)}` : '-';\n      return `<tr><td class=\"muted\">${esc(m.code)}</td><td class=\"pdesc\">${esc(m.description)}</td><td>${esc(m.category)}</td><td class=\"num\">${(m.demand || 0).toLocaleString('pt-BR')}</td><td class=\"num\">${marginTxt}</td><td class=\"num\">${profitTxt}</td></tr>`;\n    }).join('');\n    detail = `<table class=\"adv-table\" style=\"margin-top:10px\"><thead><tr><th>codigo</th><th>peca</th><th>categoria</th><th class=\"num\">vendidos</th><th class=\"num\">margem</th><th class=\"num\">lucro</th></tr></thead><tbody>${rowsHtml}</tbody></table>`;\n  } else if (adv.openQuadrant) {\n    detail = '<div class=\"adv-empty\" style=\"margin-top:10px\">Sem SKUs nesta faixa.</div>';\n  }\n  return `<div class=\"adv-qgrid\">${cellsHtml}</div>${detail}`;\n}\nfunction buildAdvPressureHtml(byCategory) {\n  if (!byCategory.length) return '<div class=\"adv-empty\">Sem dados.</div>';\n  const rowsHtml = byCategory.map((c) => {\n    const compTxt = c.avgCompetition != null ? c.avgCompetition : '-';\n    const discTxt = c.discAvg != null ? `${c.discAvg}%` : '-';\n    return `<tr><td>${esc(c.category)}</td><td class=\"num\">${compTxt}</td><td class=\"num\">${c.adsRate}%</td><td class=\"num\">${c.promoRate}%</td><td class=\"num\">${discTxt}</td></tr>`;\n  }).join('');\n  return `<table class=\"adv-table\"><thead><tr><th>categoria</th><th class=\"num\">conc. med</th><th class=\"num\">% ADS</th><th class=\"num\">% promo</th><th class=\"num\">desc. med</th></tr></thead><tbody>${rowsHtml}</tbody></table>`;\n}\nfunction buildAdvBrandHtml(byBrand) {\n  if (!byBrand.length) return '<div class=\"adv-empty\">Sem dados de marca.</div>';\n  const maxM = Math.max(10, Math.max.apply(null, byBrand.map((b) => b.avgMargin || 0)));\n  return byBrand.map((b) => {\n    const pct = Math.max(2, Math.round((100 * (b.avgMargin || 0)) / maxM));\n    const marginTxt = b.avgMargin != null ? `${b.avgMargin}%` : '-';\n    return `<div class=\"barrow\"><span class=\"lbl wide\" title=\"${esc(b.brand)} - ${b.count} SKUs\">${esc(b.brand)} <span class=\"muted\">(${b.count})</span></span>\n    <span class=\"track\"><div class=\"fill\" style=\"width:${pct}%;background:${marginTierColor(b.avgMargin || 0)}\"></div></span>\n    <span class=\"val wide\">${marginTxt}</span></div>`;\n  }).join('');\n}\nfunction buildAdvLensTabsHtml(current) {\n  return Object.keys(ADV_LENS_INFO).map((k) => `<button type=\"button\" class=\"adv-lens-tab ${k === current ? 'on' : ''}\" data-lens=\"${k}\">${ADV_LENS_INFO[k].label}</button>`).join('');\n}\nfunction buildAdvLensTableHtml(rows) {\n  if (!rows || !rows.length) return '<div class=\"adv-empty\">Sem dados ainda para esta lente.</div>';\n  const rowsHtml = rows.map((o) => {\n    const marginTxt = o.margin != null ? `${Math.round(o.margin)}%` : '-';\n    const profitTxt = o.profit != null ? `R$ ${o.profit.toFixed(2)}` : '-';\n    const stockTxt = o.stock != null ? o.stock : '-';\n    return `<tr><td class=\"muted\">${esc(o.code)}</td><td class=\"pdesc\" title=\"${esc(o.description)}\">${esc(o.description)}</td><td>${esc(o.category)}</td>\n      <td class=\"num\">R$ ${(o.cost || 0).toFixed(2)}</td><td class=\"num\"><b>R$ ${(o.price || 0).toFixed(2)}</b></td>\n      <td class=\"num\">${marginTxt}</td><td class=\"num\">${profitTxt}</td>\n      <td class=\"num\">${o.comp}</td><td class=\"num\">${(o.demand || 0).toLocaleString('pt-BR')}</td><td class=\"num\">${stockTxt}</td></tr>`;\n  }).join('');\n  return `<table class=\"adv-table\"><thead><tr><th>codigo</th><th>peca</th><th>categoria</th><th class=\"num\">custo</th><th class=\"num\">preco</th><th class=\"num\">margem</th><th class=\"num\">lucro</th><th class=\"num\">concorr.</th><th class=\"num\">vendidos</th><th class=\"num\">estoque</th></tr></thead><tbody>${rowsHtml}</tbody></table>`;\n}\nfunction renderAdvancedSection(d2) {\n  const adv = d2.state.adv;\n  if (!adv || adv.loading) return '<div class=\"panel adv-section\"><div class=\"panel-h\">Analise avancada</div><div class=\"adv-empty\">Carregando analise avancada (cruza snapshots, plug, anuncios e vendas -- pode levar alguns segundos)...</div></div>';\n  if (adv.error) return `<div class=\"panel adv-section\"><div class=\"error-state\"><span>Falha ao carregar analise avancada: ${esc(adv.error)}</span><button class=\"btn-retry\" data-action=\"retry-advanced\">Tentar novamente</button></div></div>`;\n  const dimOptions = ADV_DIM_LABELS.map((d) => `<option value=\"${d[0]}\">${d[1]}</option>`).join('');\n  const valOptions = ADV_VALUE_LABELS.map((d) => `<option value=\"${d[0]}\">${d[1]}</option>`).join('');\n  const marginMedTxt = adv.marginMed != null ? `${Math.round(adv.marginMed)}%` : '-';\n  const heatmapHtml = buildAdvHeatmapHtml(adv.heatmap);\n  const quadrantHtml = buildAdvQuadrantHtml(adv);\n  const pressureHtml = buildAdvPressureHtml(adv.byCategory);\n  const brandHtml = buildAdvBrandHtml(adv.byBrand);\n  const lensTabsHtml = buildAdvLensTabsHtml(adv.lens);\n  const lensTableHtml = buildAdvLensTableHtml(adv.lenses[adv.lens]);\n  const lensHint = ADV_LENS_INFO[adv.lens].hint;\n  return `\n    <div class=\"panel adv-section\">\n      <div class=\"panel-h\">Heatmap configuravel <span class=\"muted\">(${adv.universe} SKUs cruzados, ${adv.priced} com margem calculada)</span></div>\n      <div class=\"adv-heatctl\">\n        <label>linha <select id=\"advHeatRow\">${dimOptions}</select></label>\n        <label>coluna <select id=\"advHeatCol\">${dimOptions}</select></label>\n        <label>valor <select id=\"advHeatVal\">${valOptions}</select></label>\n      </div>\n      <div class=\"adv-hint\">Cruze qualquer dimensao -- ex: faixa de demanda x faixa de desconto com valor no de SKUs mostra esforco promocional por volume.</div>\n      ${heatmapHtml}\n    </div>\n    <div class=\"dash-grid\" style=\"margin-top:14px\">\n      <div class=\"panel adv-section\">\n        <div class=\"panel-h\">Quadrante de oportunidade <span class=\"muted\">(demanda x margem, mediana ${marginMedTxt})</span></div>\n        ${quadrantHtml}\n      </div>\n      <div class=\"panel adv-section\">\n        <div class=\"panel-h\">Pressao competitiva <span class=\"muted\">(ADS, promocao, desconto por categoria)</span></div>\n        ${pressureHtml}\n      </div>\n    </div>\n    <div class=\"panel adv-section\" style=\"margin-top:14px\">\n      <div class=\"panel-h\">Margem por marca <span class=\"muted\">(top 14)</span></div>\n      ${brandHtml}\n    </div>\n    <div class=\"panel adv-section\" style=\"margin-top:14px\">\n      <div class=\"panel-h\">Ranking de oportunidade -- 6 lentes <span class=\"muted\">(demanda e concorrencia = mercado ML, via snapshots)</span></div>\n      <div class=\"adv-lenstabs\">${lensTabsHtml}</div>\n      <div class=\"adv-lenshint muted\">${lensHint}</div>\n      ${lensTableHtml}\n    </div>\n  `;\n}\n\nfunction buildHeatmapHtml(heatmap) {\n  const { rows, cols, cells, max } = heatmap;\n  const colHeads = cols.map((c) => `<div class=\"heat-col-h\">${esc(c)}</div>`).join('');\n  const body = rows.map((rowLabel, ri) => {\n    const rowCells = (cells[ri] || []).map((v) => {\n      const pct = max ? v / max : 0;\n      const bg = heatColor(pct);\n      const textColor = pct > 0.55 ? '#0f1115' : '#8a8f9a';\n      const label = v > 0 ? `R$ ${compact(v)}` : '·';\n      return `<div class=\"heat-cell\" style=\"background:${bg};color:${textColor}\" title=\"${esc(rowLabel)} · R$ ${v.toFixed(2)}\">${label}</div>`;\n    }).join('');\n    return `<div class=\"heat-row-h\">${esc(rowLabel)}</div>${rowCells}`;\n  }).join('');\n  return `<div class=\"heatmap-grid\"><div class=\"heat-corner\"></div>${colHeads}${body}</div>`;\n}\n\nfunction buildHotListHtml(items) {\n  if (!items || !items.length) return '<div style=\"color:#8a8f9a;font-size:12px\">Sem dados no período.</div>';\n  const max = Math.max(1, ...items.map((i) => i.value));\n  return items.map((i) => {\n    const pct = Math.max(2, Math.round((i.value / max) * 100));\n    const badge = i.trendBadge ? `<span class=\"pill ${i.trendClass}\">${esc(i.trendBadge)}</span>` : '';\n    return `<div class=\"barrow\">\n      <div class=\"lbl wide\" title=\"${esc(i.label)}\">${esc(i.label)}</div>\n      <div class=\"track\"><div class=\"fill\" style=\"width:${pct}%\"></div></div>\n      <div class=\"val wide\">${esc(i.valueLabel)} ${badge}</div>\n    </div>`;\n  }).join('');\n}\n\nfunction renderGeral(d2) {\n  const g = d2.state.geral;\n  const err = d2.state.geralError;\n  if (err) {\n    return `<div class=\"geral\"><h1>Visão geral</h1><div class=\"error-state\">\n      <span>Não foi possível carregar a visão geral: ${esc(err)}</span>\n      <button class=\"btn-retry\" data-action=\"retry-geral\">Tentar novamente</button>\n    </div></div>`;\n  }\n  if (!g) return `<div class=\"geral\"><h1>Visão geral</h1><div style=\"color:#8a8f9a\">Carregando…</div></div>`;\n  const dailyChartHtml = buildDailyChartSvg(g.daily);\n  const hourlyChartHtml = g.hourly ? buildHourlyChartSvg(g.hourly) : '';\n  const marginClass = g.margin30 < 10 ? 'crit' : (g.margin30 < 20 ? 'warn' : 'good');\n  const heatmapHtml = g.heatmap ? buildHeatmapHtml(g.heatmap) : '';\n  const catChartHtml = (g.categories && g.categories.length)\n    ? d2.render(\n        { component: 'data2-blocks@BlockChart', params: {\n          type: 'Horizontal',\n          dataset: g.categories,\n          dimension: 'category',\n          metric: 'revenue',\n          statistic: 'sum',\n          hideLegend: true,\n          textColor: '#cbd0d8',\n          gridColor: '#23272f',\n          datalabelColor: '#e7e4da',\n          dataColors: g.categories.map((c) => ({ value: c.category, color: c.marginColor })),\n        } },\n        {},\n        { key: 'catChart', style: 'width:100%;height:230px;display:block' },\n      )\n    : '<div style=\"color:#8a8f9a;font-size:12px\">Sem dados no período.</div>';\n  return `<div class=\"geral\">\n    <h1>Visão geral</h1>\n    <div class=\"kpis\">\n      <div class=\"kpi\"><div class=\"l\">Receita · 30d</div><div class=\"n\">R$ ${compact(g.revenue30)}</div></div>\n      <div class=\"kpi\"><div class=\"l\">Lucro · 30d</div><div class=\"n\">R$ ${compact(g.profit30)}</div></div>\n      <div class=\"kpi ${marginClass}\"><div class=\"l\">Margem média · 30d</div><div class=\"n\">${g.margin30.toFixed(1)}%</div></div>\n      <div class=\"kpi\"><div class=\"l\">Pedidos · 30d</div><div class=\"n\">${g.count30}</div></div>\n    </div>\n    <div class=\"dash-grid\">\n      <div class=\"panel wide\">\n        <div class=\"panel-h\">Receita diária (14d)</div>\n        <div class=\"chart-wrap\" data-chart=\"daily\">\n          ${dailyChartHtml}\n          <div class=\"chart-tooltip\" data-role=\"daily-tooltip\"></div>\n        </div>\n      </div>\n      ${g.hourly ? `<div class=\"panel wide\">\n        <div class=\"panel-h\">Distribuição por horário do dia (30d)</div>\n        <div class=\"chart-wrap small\" data-chart=\"hourly\">\n          ${hourlyChartHtml}\n          <div class=\"chart-tooltip\" data-role=\"hourly-tooltip\"></div>\n        </div>\n      </div>` : ''}\n      ${heatmapHtml ? `<div class=\"panel wide\">\n        <div class=\"panel-h\">Mapa de calor · dia da semana × horário (30d)</div>\n        ${heatmapHtml}\n      </div>` : ''}\n      <div class=\"panel\">\n        <div class=\"panel-h\">Mais vendidos (14d)</div>\n        ${buildHotListHtml(g.hot)}\n      </div>\n      <div class=\"panel\">\n        <div class=\"panel-h\">Receita &amp; margem por categoria (14d)</div>\n        <div class=\"chart-host\">${catChartHtml}</div>\n        <div class=\"chart-legend\">cor da barra = margem média · <span class=\"pill good\">≥20%</span> <span class=\"pill warn\">10–20%</span> <span class=\"pill bad\">&lt;10%</span></div>\n      </div>\n      <div class=\"panel wide\">\n        <div class=\"panel-h\">Anúncios por status</div>\n        <div class=\"statuschips\">\n          <span class=\"pill good\">${g.adsActive} ativos</span>\n          <span class=\"pill warn\">${g.adsPaused} pausados</span>\n          <span class=\"pill bad\">${g.adsReview} em revisão</span>\n        </div>\n      </div>\n    </div>\n    ${renderAdvancedToggle(d2)}\n    ${d2.state.advOpen ? renderAdvancedSection(d2) : ''}\n  </div>`;\n}\n\nasync function waitForDataset(d2, name, attempts = 30, delayMs = 150) {\n  for (let i = 0; i < attempts; i++) {\n    const ds = d2.data(name);\n    if (ds) return ds;\n    await new Promise((r) => setTimeout(r, delayMs));\n  }\n  throw new Error(`Dataset \"${name}\" indisponível.`);\n}\n\nasync function loadGeral(d2) {\n  const gen = (d2.state._geralGen = (d2.state._geralGen || 0) + 1);\n  d2.state._geralLoading = true;\n  d2.state.geralError = null;\n  try {\n    const [salesDs, adsDs, productsDs] = await Promise.all([\n      waitForDataset(d2, 'salesDs'),\n      waitForDataset(d2, 'mlAdsDs'),\n      waitForDataset(d2, 'productsDs'),\n    ]);\n    const since30 = new Date(Date.now() - 30 * 86400000).toISOString();\n    const since14 = new Date(Date.now() - 14 * 86400000).toISOString();\n    const since28 = new Date(Date.now() - 28 * 86400000).toISOString();\n    const arr = (r) => {\n      if (Array.isArray(r)) return r;\n      if (r && Array.isArray(r.data)) return r.data;\n      return null; // error/malformed shape — NOT a legitimate empty result\n    };\n    const requireArr = (r, label) => {\n      const a = arr(r);\n      if (a === null) throw new Error(`Resposta inesperada de \"${label}\" — provável falha silenciosa na consulta.`);\n      return a;\n    };\n    const [totalsRes, dailyRes, hourlyRes, statusRes, hotSkuRes, skuAggRes, priorHotRes, dowHourRes] = await Promise.all([\n      salesDs.aggregate([\n        { $match: { status: 'paid', order_date: { $gte: since30 } } },\n        { $group: { _id: null, revenue: { $sum: '$total' }, profit: { $sum: '$profit' }, count: { $sum: 1 } } },\n      ]),\n      salesDs.aggregate([\n        { $match: { status: 'paid', order_date: { $gte: since14 } } },\n        { $group: { _id: { $substrCP: ['$order_date', 0, 10] }, revenue: { $sum: '$total' } } },\n        { $sort: { _id: 1 } },\n      ]),\n      salesDs.aggregate([\n        { $match: { status: 'paid', order_date: { $gte: since30 } } },\n        { $group: { _id: { $hour: { date: { $toDate: '$order_date' }, timezone: 'America/Sao_Paulo' } }, revenue: { $sum: '$total' }, count: { $sum: 1 } } },\n      ]),\n      adsDs.aggregate([{ $group: { _id: '$status', n: { $sum: 1 } } }]),\n      salesDs.aggregate([\n        { $match: { status: 'paid', order_date: { $gte: since14 }, sku: { $exists: true, $ne: '' } } },\n        { $group: { _id: '$sku', revenue: { $sum: '$total' }, units: { $sum: '$units' }, count: { $sum: 1 } } },\n        { $sort: { revenue: -1 } },\n        { $limit: 8 },\n      ]),\n      salesDs.aggregate([\n        { $match: { status: 'paid', order_date: { $gte: since14 }, sku: { $exists: true, $ne: '' } } },\n        { $group: { _id: '$sku', revenue: { $sum: '$total' }, profit: { $sum: '$profit' }, count: { $sum: 1 } } },\n        { $limit: 500 },\n      ]),\n      salesDs.aggregate([\n        { $match: { status: 'paid', order_date: { $gte: since28, $lt: since14 }, sku: { $exists: true, $ne: '' } } },\n        { $group: { _id: '$sku', revenue: { $sum: '$total' } } },\n        { $limit: 500 },\n      ]),\n      salesDs.aggregate([\n        { $match: { status: 'paid', order_date: { $gte: since30 } } },\n        { $group: { _id: { dow: { $dayOfWeek: { date: { $toDate: '$order_date' }, timezone: 'America/Sao_Paulo' } }, hour: { $hour: { date: { $toDate: '$order_date' }, timezone: 'America/Sao_Paulo' } } }, revenue: { $sum: '$total' }, count: { $sum: 1 } } },\n      ]),\n    ]);\n    if (d2.state._geralGen !== gen) return;\n    const t = requireArr(totalsRes, 'totais de vendas (30d)')[0] || { revenue: 0, profit: 0, count: 0 };\n    const revenue30 = Number(t.revenue) || 0;\n    const profit30 = Number(t.profit) || 0;\n    const daily = requireArr(dailyRes, 'receita diária (14d)').map((r) => {\n      const iso = r._id || '';\n      const dd = iso.slice(8, 10);\n      const mm = iso.slice(5, 7);\n      return {\n        date: iso,\n        label: dd && mm ? `${dd}/${mm}` : iso.slice(5),\n        dateLabel: dd && mm ? `${dd}/${mm}/${iso.slice(0, 4)}` : iso,\n        revenue: Number(r.revenue) || 0,\n      };\n    });\n    const hourMap = {};\n    requireArr(hourlyRes, 'receita por hora (30d)').forEach((r) => { hourMap[r._id] = { revenue: Number(r.revenue) || 0, count: Number(r.count) || 0 }; });\n    const hourly = Array.from({ length: 24 }, (_, h) => ({\n      hour: h,\n      revenue: (hourMap[h] && hourMap[h].revenue) || 0,\n      count: (hourMap[h] && hourMap[h].count) || 0,\n    }));\n    const dowLabels = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'];\n    const bucketLabels = ['00–04h', '04–08h', '08–12h', '12–16h', '16–20h', '20–24h'];\n    const heatMatrix = Array.from({ length: 7 }, () => Array(6).fill(0));\n    requireArr(dowHourRes, 'atividade por dia×hora (30d)').forEach((r) => {\n      const dowRaw = (r._id && r._id.dow) || 1;\n      const hourRaw = (r._id && r._id.hour) || 0;\n      const dow = ((dowRaw - 1) % 7 + 7) % 7;\n      const bucket = Math.min(5, Math.max(0, Math.floor(hourRaw / 4)));\n      heatMatrix[dow][bucket] += Number(r.revenue) || 0;\n    });\n    const heatmap = { rows: dowLabels, cols: bucketLabels, cells: heatMatrix, max: Math.max(1, ...heatMatrix.flat()) };\n    const statusRows = requireArr(statusRes, 'status dos anúncios');\n    const findN = (k) => {\n      const r = statusRows.find((x) => x._id === k);\n      return r ? Number(r.n) || 0 : 0;\n    };\n\n    const hotRows = requireArr(hotSkuRes, 'ranking de SKUs (14d)').filter((r) => r._id);\n    const skuRows = requireArr(skuAggRes, 'agregação de SKUs (14d)').filter((r) => r._id);\n    const priorRows = requireArr(priorHotRes, 'ranking de SKUs (período anterior)').filter((r) => r._id);\n    const priorMap = {};\n    priorRows.forEach((r) => { priorMap[r._id] = Number(r.revenue) || 0; });\n    const codes = Array.from(new Set([...hotRows, ...skuRows].map((r) => primaryCode(r._id)).filter(Boolean)));\n    let codeMap = {};\n    if (codes.length) {\n      const infoRows = requireArr(await productsDs.aggregate([\n        { $match: { code: { $in: codes } } },\n        { $project: { code: 1, description: 1, category: 1, _id: 0 } },\n      ]), 'informações de produtos');\n      infoRows.forEach((r) => { codeMap[r.code] = r; });\n    }\n    if (d2.state._geralGen !== gen) return;\n\n    const hot = hotRows.map((r) => {\n      const info = codeMap[primaryCode(r._id)];\n      const revenue = Number(r.revenue) || 0;\n      const prior = priorMap[r._id] || 0;\n      let trendBadge = '→ estável';\n      let trendClass = 'muted';\n      if (!prior && revenue > 0) {\n        trendBadge = '🆕 novo';\n        trendClass = 'accent';\n      } else if (prior > 0) {\n        const growthPct = ((revenue - prior) / prior) * 100;\n        if (growthPct >= 20) {\n          trendBadge = `🔥 +${Math.round(growthPct)}%`;\n          trendClass = 'good';\n        } else if (growthPct <= -20) {\n          trendBadge = `📉 ${Math.round(growthPct)}%`;\n          trendClass = 'bad';\n        }\n      }\n      return {\n        label: (info && info.description) || r._id,\n        value: revenue,\n        valueLabel: `R$ ${compact(revenue)} · ${Number(r.count) || 0}`,\n        trendBadge,\n        trendClass,\n      };\n    });\n\n    const catTotals = {};\n    skuRows.forEach((r) => {\n      const info = codeMap[primaryCode(r._id)];\n      const rawCat = ((info && info.category) || 'Sem categoria').trim();\n      const cat = rawCat ? rawCat.toUpperCase() : 'SEM CATEGORIA';\n      if (!catTotals[cat]) catTotals[cat] = { revenue: 0, profit: 0, count: 0 };\n      catTotals[cat].revenue += Number(r.revenue) || 0;\n      catTotals[cat].profit += Number(r.profit) || 0;\n      catTotals[cat].count += Number(r.count) || 0;\n    });\n    let catList = Object.keys(catTotals).map((cat) => {\n      const c = catTotals[cat];\n      const avgMargin = c.revenue ? (c.profit / c.revenue) * 100 : 0;\n      return { category: cat, revenue: c.revenue, count: c.count, avgMargin };\n    });\n    catList.sort((a, b) => b.revenue - a.revenue);\n    if (catList.length > 7) {\n      const rest = catList.slice(7);\n      const restTotal = rest.reduce((acc, c) => ({ revenue: acc.revenue + c.revenue, profit: acc.profit + (c.revenue * c.avgMargin) / 100, count: acc.count + c.count }), { revenue: 0, profit: 0, count: 0 });\n      catList = catList.slice(0, 7).concat([{ category: 'OUTROS', revenue: restTotal.revenue, count: restTotal.count, avgMargin: restTotal.revenue ? (restTotal.profit / restTotal.revenue) * 100 : 0 }]);\n    }\n    const categories = catList.map((c) => ({\n      category: c.category,\n      revenue: Math.round(c.revenue * 100) / 100,\n      count: c.count,\n      avgMargin: Math.round(c.avgMargin * 10) / 10,\n      marginColor: marginTierColor(c.avgMargin),\n    }));\n\n    d2.state.geral = {\n      revenue30,\n      profit30,\n      margin30: revenue30 ? (profit30 / revenue30) * 100 : 0,\n      count30: Number(t.count) || 0,\n      daily,\n      hourly,\n      heatmap,\n      hot,\n      categories,\n      adsActive: findN('active'),\n      adsPaused: findN('paused'),\n      adsReview: findN('under_review'),\n    };\n    d2.state.geralError = null;\n  } catch (e) {\n    if (d2.state._geralGen !== gen) return;\n    d2.state.geralError = (e && e.message) || String(e);\n  }\n}\n"}},"freteRealDs":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"freteRealDs"}}}},"mlAdsDs":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"mlAdsDs"}}}},"plugDs":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"plugDs"}}}},"productsDs":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"productsDs"}}}},"salesDs":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"salesDs"}}}},"settingsDs":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"settingsDs"}}}},"integrationTokensDs":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"integrationTokensDs"}}}}}}}},"__d2PrevCode":{"code":"const NAV_ITEMS = [\n  { key: 'geral', label: 'Visão Geral', path: '/' },\n  { key: 'vendas', label: 'Vendas', path: '/vendas' },\n  { key: 'anuncios', label: 'Anúncios', path: '/anuncios' },\n  { key: 'catalogo', label: 'Catálogo', path: '/catalogo' },\n  { key: 'manutencao', label: 'Manutenção', path: '/manutencao' },\n  { key: 'promocoes', label: 'Promoções', path: '/promocoes' },\n  { key: 'fiscal', label: 'Dados Fiscais', path: '/fiscal' },\n  { key: 'publicar', label: 'Publicar', path: '/publicar' },\n  { key: 'configuracoes', label: 'Configurações', path: '/configuracoes', disabled: true },\n];\n\nconst SOON_LABEL = {\n  '/configuracoes': 'Configurações',\n};\n\nfunction buildDailyChartSvg(daily) {\n  const W = 640, H = 170, padL = 6, padR = 6, padT = 10, padB = 22;\n  const innerW = W - padL - padR;\n  const innerH = H - padT - padB;\n  const n = Math.max(1, daily.length);\n  const maxRev = Math.max(1, ...daily.map((d) => d.revenue));\n  const colW = innerW / n;\n  const gridLines = [0.25, 0.5, 0.75].map((f) => {\n    const y = (padT + innerH * f).toFixed(1);\n    return `<line class=\"grid\" x1=\"${padL}\" y1=\"${y}\" x2=\"${W - padR}\" y2=\"${y}\"></line>`;\n  }).join('');\n  const baseline = `<line class=\"baseline\" x1=\"${padL}\" y1=\"${padT + innerH}\" x2=\"${W - padR}\" y2=\"${padT + innerH}\"></line>`;\n  const bars = daily.map((d, i) => {\n    const h = Math.max(1, Math.round((d.revenue / maxRev) * innerH));\n    const x = padL + i * colW;\n    const y = padT + (innerH - h);\n    const w = Math.max(1, colW * 0.6);\n    return `<rect class=\"bar\" data-idx=\"${i}\" x=\"${(x + (colW - w) / 2).toFixed(1)}\" y=\"${y}\" width=\"${w.toFixed(1)}\" height=\"${h}\" rx=\"2\"></rect>`;\n  }).join('');\n  const step = Math.max(1, Math.ceil(n / 7));\n  const labels = daily.map((d, i) => {\n    if (i % step !== 0 && i !== n - 1) return '';\n    const x = (padL + i * colW + colW / 2).toFixed(1);\n    return `<text class=\"axislabel\" x=\"${x}\" y=\"${H - 6}\" text-anchor=\"middle\">${esc(d.label)}</text>`;\n  }).join('');\n  return `<svg class=\"daily-chart\" data-padl=\"${padL}\" data-innerw=\"${innerW}\" viewBox=\"0 0 ${W} ${H}\" preserveAspectRatio=\"none\">\n    ${gridLines}${baseline}${bars}${labels}\n  </svg>`;\n}\n\nfunction buildHourlyChartSvg(hourly) {\n  const W = 640, H = 60, padL = 4, padR = 4, padT = 6, padB = 4;\n  const innerW = W - padL - padR;\n  const innerH = H - padT - padB;\n  const n = Math.max(1, hourly.length);\n  const maxRev = Math.max(1, ...hourly.map((h) => h.revenue));\n  const colW = innerW / n;\n  const pts = hourly.map((h, i) => {\n    const x = padL + i * colW + colW / 2;\n    const y = padT + (innerH - Math.max(0, (h.revenue / maxRev) * innerH));\n    return `${x.toFixed(1)},${y.toFixed(1)}`;\n  });\n  const path = `M${pts.join(' L')}`;\n  const areaPath = `M${padL},${padT + innerH} L${pts.join(' L')} L${(padL + innerW).toFixed(1)},${padT + innerH} Z`;\n  return `<svg class=\"hourly-chart\" data-padl=\"${padL}\" data-innerw=\"${innerW}\" viewBox=\"0 0 ${W} ${H}\" preserveAspectRatio=\"none\">\n    <path class=\"sparkline-fill\" d=\"${areaPath}\"></path>\n    <path class=\"sparkline-path\" d=\"${path}\"></path>\n  </svg>`;\n}\n\nfunction bindChartHover(d2, svgSelector, tooltipSelector, itemsFn, formatFn) {\n  const svg = d2.$(svgSelector);\n  const tooltip = d2.$(tooltipSelector);\n  if (!svg || !tooltip || svg.dataset.hoverBound) return;\n  svg.dataset.hoverBound = '1';\n  const wrap = svg.closest('.chart-wrap') || svg;\n  d2.on(svg, 'mousemove', (e) => {\n    const items = itemsFn(d2);\n    if (!items || !items.length) return;\n    const vb = svg.viewBox.baseVal;\n    const bbox = svg.getBoundingClientRect();\n    if (!bbox.width) return;\n    const vbX = ((e.clientX - bbox.left) / bbox.width) * vb.width;\n    const padL = Number(svg.dataset.padl) || 0;\n    const innerW = Number(svg.dataset.innerw) || vb.width;\n    const colW = innerW / items.length;\n    let idx = Math.floor((vbX - padL) / colW);\n    idx = Math.max(0, Math.min(items.length - 1, idx));\n    svg.querySelectorAll('.bar').forEach((b) => b.classList.remove('active'));\n    const activeBar = svg.querySelector(`.bar[data-idx=\"${idx}\"]`);\n    if (activeBar) activeBar.classList.add('active');\n    const { title, value } = formatFn(items[idx]);\n    tooltip.innerHTML = `<div class=\"d\">${esc(title)}</div><div class=\"v\">${esc(value)}</div>`;\n    tooltip.style.display = 'block';\n    const wrapRect = wrap.getBoundingClientRect();\n    tooltip.style.left = `${e.clientX - wrapRect.left}px`;\n    tooltip.style.top = `${e.clientY - wrapRect.top}px`;\n  });\n  d2.on(svg, 'mouseleave', () => {\n    tooltip.style.display = 'none';\n    svg.querySelectorAll('.bar').forEach((b) => b.classList.remove('active'));\n  });\n}\n\nfunction bindGeralCharts(d2) {\n  bindChartHover(d2, '.daily-chart', '[data-role=\"daily-tooltip\"]',\n    () => (d2.state.geral && d2.state.geral.daily) || [],\n    (d) => ({ title: d.dateLabel || d.label, value: `R$ ${d.revenue.toFixed(2)}` }));\n  bindChartHover(d2, '.hourly-chart', '[data-role=\"hourly-tooltip\"]',\n    () => (d2.state.geral && d2.state.geral.hourly) || [],\n    (h) => ({ title: `${String(h.hour).padStart(2, '0')}h`, value: `R$ ${h.revenue.toFixed(2)} · ${h.count} pedido${h.count === 1 ? '' : 's'}` }));\n}\n\nfunction triggerGeralLoad(d2) {\n  if (d2.state._geralLoading) return;\n  loadGeral(d2).finally(() => { d2.state._geralLoading = false; });\n}\n\nasync function loadPlugStatus(d2) {\n  d2.state._plugStatusLoading = true;\n  try {\n    const ds = await waitForDataset(d2, 'integrationTokensDs');\n    const rows = await ds.query({ service: 'plug' });\n    const rowsArr = Array.isArray(rows) ? rows : (rows && Array.isArray(rows.data) ? rows.data : []);\n    const rec = rowsArr[0] || null;\n    const updatedAtMs = rec && rec.updatedAt ? Date.parse(rec.updatedAt) : NaN;\n    d2.state.plugStatus = {\n      hasToken: !!(rec && rec.access_token),\n      updatedAtMs: Number.isFinite(updatedAtMs) ? updatedAtMs : null,\n    };\n  } catch (e) {\n    d2.state.plugStatus = { hasToken: false, updatedAtMs: null, error: (e && e.message) || String(e) };\n  } finally {\n    d2.state._plugStatusLoading = false;\n  }\n}\n\nfunction triggerPlugStatusLoad(d2) {\n  if (d2.state._plugStatusLoading) return;\n  loadPlugStatus(d2);\n}\n\nfunction plugStatusView(d2) {\n  const s = d2.state.plugStatus;\n  if (!s) return { label: 'checando…', cls: 'pending' };\n  if (!s.hasToken) return { label: 'erro', cls: 'bad' };\n  const ageSec = s.updatedAtMs ? Math.max(0, Math.round((Date.now() - s.updatedAtMs) / 1000)) : null;\n  if (ageSec === null || ageSec > 900) return { label: 'expirado', cls: 'bad' };\n  return { label: 'ok', cls: 'good' };\n}\n\nfunction primaryCode(sku) {\n  if (!sku) return '';\n  return String(sku).split('-')[0].trim();\n}\n\nfunction buildBarListHtml(items) {\n  if (!items || !items.length) return '<div style=\"color:#8a8f9a;font-size:12px\">Sem dados no período.</div>';\n  const max = Math.max(1, ...items.map((i) => i.value));\n  return items.map((i) => {\n    const pct = Math.max(2, Math.round((i.value / max) * 100));\n    return `<div class=\"barrow\">\n      <div class=\"lbl wide\" title=\"${esc(i.label)}\">${esc(i.label)}</div>\n      <div class=\"track\"><div class=\"fill\" style=\"width:${pct}%\"></div></div>\n      <div class=\"val wide\">${esc(i.valueLabel)}</div>\n    </div>`;\n  }).join('');\n}\n\nexport default {\n  css: `\n    * { box-sizing: border-box; }\n    :host, .shell { height: 100%; }\n    .shell {\n      display: flex; height: 100%; overflow: hidden;\n      background: #0f1115; color: #e7e4da;\n      font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n    }\n    .nav { width: 240px; flex: none; background: #14171d; border-right: 1px solid #262b33; display: flex; flex-direction: column; }\n    .brand { padding: 22px 20px 18px; font-size: 13px; font-weight: 800; letter-spacing: 3px; color: #6f9bef; }\n    .navlist { flex: 1; overflow-y: auto; padding: 4px 12px; display: flex; flex-direction: column; gap: 2px; }\n    .navitem {\n      display: flex; align-items: center; justify-content: space-between; gap: 8px;\n      padding: 10px 12px; border-radius: 8px; font-size: 13px; font-weight: 600; color: #9aa0ab;\n      cursor: pointer; border-left: 3px solid transparent;\n    }\n    .navitem:hover { background: #1b1f26; color: #e7e4da; }\n    .navitem.active { background: #1b1f26; color: #ffffff; border-left-color: #6f9bef; }\n    .navitem.disabled { cursor: default; color: #4b5058; }\n    .navitem.disabled:hover { background: transparent; color: #4b5058; }\n    .soon { font-size: 9px; text-transform: uppercase; letter-spacing: .03em; color: #6b7280; background: #1b1f26; padding: 2px 6px; border-radius: 999px; }\n    .userbox { padding: 14px 16px; border-top: 1px solid #262b33; display: flex; flex-direction: column; gap: 8px; }\n    .useremail { font-size: 11.5px; color: #8a8f9a; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n    .logout { font-size: 12px; font-weight: 700; color: #e2685a; background: none; border: none; cursor: pointer; text-align: left; padding: 0; }\n    .plugstatus { display: flex; align-items: center; gap: 6px; font-size: 10.5px; color: #8a8f9a; cursor: pointer; user-select: none; background: none; border: none; padding: 0; font-family: inherit; }\n    .plugstatus .dot { width: 7px; height: 7px; border-radius: 999px; background: #6b7280; flex: none; }\n    .plugstatus.good .dot { background: #5cbd8a; }\n    .plugstatus.bad .dot { background: #e2685a; }\n    .plugstatus.pending .dot { background: #6b7280; }\n    .plugstatus:hover { color: #e7e4da; }\n    .content { flex: 1; min-width: 0; overflow: auto; }\n    .panel-light { padding: 20px; height: 100%; }\n    .panel-card { background: #f7f7fa; border-radius: 16px; overflow: hidden; height: 100%; }\n    .soon-page { display: flex; align-items: center; justify-content: center; height: 100%; flex-direction: column; gap: 8px; color: #6b7280; }\n    .soon-page .t { font-size: 18px; font-weight: 800; color: #e7e4da; }\n    /* ===== MODENAFS shared design tokens — Visão Geral dashboard content only.\n       Scoped by usage: only renderGeral() markup emits these classes, so nothing\n       bleeds into the .nav sidebar or the login screen (which don't use them). */\n    .panel {\n      background: #14171d; border: 1px solid #242932; border-radius: 14px;\n      padding: 16px 18px; box-shadow: 0 4px 18px rgba(0,0,0,.3), 0 1px 3px rgba(0,0,0,.25);\n    }\n    .panel + .panel { margin-top: 14px; }\n    .panel-h {\n      font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: #8a8f9a;\n      margin-bottom: 12px; display: flex; align-items: center; gap: 7px; font-weight: 700;\n    }\n    .kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px,1fr)); gap: 12px; }\n    .kpi {\n      background: #171b21; border: 1px solid #242932; border-radius: 12px; padding: 13px 16px;\n      border-left: 3px solid #2a2f38; display: flex; flex-direction: column; gap: 4px;\n    }\n    .kpi .l { font-size: 10px; text-transform: uppercase; letter-spacing: .05em; color: #8a8f9a; font-weight: 600; }\n    .kpi .n { font-size: 23px; font-weight: 800; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }\n    .kpi.crit { border-left-color: #e2685a; } .kpi.crit .n { color: #e2685a; }\n    .kpi.warn { border-left-color: #e2a24a; } .kpi.warn .n { color: #e2a24a; }\n    .kpi.good { border-left-color: #5cbd8a; } .kpi.good .n { color: #5cbd8a; }\n    .pill {\n      display: inline-flex; align-items: center; gap: 4px; padding: 3px 9px; border-radius: 20px;\n      font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; white-space: nowrap;\n    }\n    .pill.good { background: rgba(92,189,138,.15); color: #5cbd8a; }\n    .pill.warn { background: rgba(226,162,74,.15); color: #e2a24a; }\n    .pill.bad { background: rgba(226,104,90,.15); color: #e2685a; }\n    .pill.accent { background: rgba(77,118,201,.18); color: #7ea2e8; }\n    .pill.muted { background: rgba(138,143,154,.15); color: #8a8f9a; }\n    .error-state {\n      padding: 16px 20px; color: #e2685a; font-size: 12.5px; background: rgba(226,104,90,.08);\n      border: 1px solid rgba(226,104,90,.3); border-radius: 10px; display: flex; align-items: center; gap: 12px; flex-wrap: wrap;\n    }\n    .error-state .btn-retry {\n      background: rgba(226,104,90,.18); color: #e2685a; border: 1px solid rgba(226,104,90,.4);\n      border-radius: 6px; padding: 6px 12px; font-size: 11.5px; font-weight: 700; cursor: pointer;\n    }\n    .error-state .btn-retry:hover { background: rgba(226,104,90,.28); }\n    .geral { padding: 28px 32px; height: 100%; overflow-y: auto; }\n    .geral h1 { font-size: 20px; font-weight: 800; margin: 0 0 20px; }\n    .geral .kpis { margin-bottom: 20px; }\n    .dash-grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 14px; align-items: start; }\n    .dash-grid .panel { margin-top: 0; }\n    .dash-grid .panel.wide { grid-column: 1 / -1; }\n    @media (max-width: 900px) { .dash-grid { grid-template-columns: 1fr; } }\n    .barrow { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }\n    .barrow:last-child { margin-bottom: 0; }\n    .barrow .lbl { width: 60px; font-size: 11px; color: #8a8f9a; flex: none; font-variant-numeric: tabular-nums; }\n    .barrow .track { flex: 1; height: 14px; background: #1b1f26; border-radius: 4px; overflow: hidden; }\n    .barrow .fill { height: 100%; background: linear-gradient(90deg,#4d76c9,#6f9bef); }\n    .barrow .val { width: 90px; text-align: right; font-size: 11px; font-variant-numeric: tabular-nums; color: #cbd0d8; flex: none; }\n    .barrow .lbl.wide { width: 168px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n    .barrow .val.wide { width: 128px; }\n    .statuschips { display: flex; gap: 10px; flex-wrap: wrap; }\n    .chart-wrap { position: relative; margin-top: 4px; }\n    .chart-wrap svg { width: 100%; height: 170px; display: block; overflow: visible; }\n    .chart-wrap.small svg { height: 60px; }\n    .grid { stroke: #23272f; stroke-width: 1; }\n    .baseline { stroke: #383e48; stroke-width: 1; }\n    .bar { fill: #4d76c9; transition: fill .12s; }\n    .bar.active { fill: #6f9bef; }\n    .axislabel { fill: #6b7280; font-size: 8px; font-family: inherit; }\n    .sparkline-path { fill: none; stroke: #6f9bef; stroke-width: 1.6; }\n    .sparkline-fill { fill: rgba(111,155,239,0.16); stroke: none; }\n    .chart-tooltip {\n      position: absolute; pointer-events: none; display: none; z-index: 5;\n      background: #1b1f26; border: 1px solid #2a2f38; border-radius: 6px; padding: 6px 10px;\n      font-size: 11px; color: #e7e4da; white-space: nowrap; transform: translate(-50%, -100%);\n      box-shadow: 0 4px 12px rgba(0,0,0,.4);\n    }\n    .chart-tooltip .d { color: #8a8f9a; font-size: 9.5px; text-transform: uppercase; letter-spacing: .03em; }\n    .chart-tooltip .v { font-weight: 700; margin-top: 2px; }\n    .barrow .val.wide { width: 172px; display: flex; align-items: center; justify-content: flex-end; gap: 6px; }\n    .heatmap-grid { display: grid; grid-template-columns: 62px repeat(6, 1fr); gap: 3px; margin-top: 4px; }\n    .heat-col-h { font-size: 9px; color: #6b7280; text-align: center; padding: 4px 2px; text-transform: uppercase; letter-spacing: .03em; }\n    .heat-row-h { font-size: 10.5px; color: #8a8f9a; display: flex; align-items: center; padding: 0 6px; font-weight: 600; }\n    .heat-cell { border-radius: 6px; min-height: 30px; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700; }\n    .chart-host { margin-top: 2px; }\n    .chart-legend { margin-top: 8px; font-size: 10.5px; color: #8a8f9a; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }\n    .route-error-page { padding: 28px 32px; height: 100%; box-sizing: border-box; overflow-y: auto; }\n    .adv-toggle-row { margin-top: 14px; }\n    .adv-toggle-btn { width: 100%; text-align: left; background: #14171d; border: 1px dashed #2a2f38; color: #9aa0ab; border-radius: 10px; padding: 10px 14px; font-size: 12px; font-weight: 700; cursor: pointer; }\n    .adv-toggle-btn:hover { background: #171b21; color: #e7e4da; border-color: #3a4048; }\n    .adv-section { margin-top: 14px; }\n    .adv-empty { color: #8a8f9a; font-size: 12px; padding: 10px 0; }\n    .adv-heatctl { display: flex; gap: 16px; flex-wrap: wrap; margin: 6px 0 8px; font-size: 11px; color: #8a8f9a; align-items: center; }\n    .adv-heatctl select { margin-left: 6px; background: #171b21; color: #e7e4da; border: 1px solid #2a2f38; border-radius: 6px; padding: 4px 8px; font-size: 11.5px; }\n    .adv-hint { font-size: 11px; color: #6b7280; margin-bottom: 10px; }\n    .adv-heatmap .heat-row-h { font-size: 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n    .adv-qgrid { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 10px; }\n    @media (max-width: 900px) { .adv-qgrid { grid-template-columns: repeat(2, 1fr); } }\n    .adv-qcell { border: 1px solid #242932; border-left-width: 3px; border-radius: 10px; padding: 12px 14px; cursor: pointer; background: #171b21; }\n    .adv-qcell:hover { background: #1b1f26; }\n    .adv-qcell.on { background: #1b1f26; box-shadow: inset 0 0 0 1px #3a4048; }\n    .adv-border-good { border-left-color: #5cbd8a; } .adv-border-warn { border-left-color: #e2a24a; }\n    .adv-border-accent { border-left-color: #7ea2e8; } .adv-border-muted { border-left-color: #8a8f9a; }\n    .adv-qn { font-size: 22px; font-weight: 800; }\n    .adv-qt { font-size: 11.5px; font-weight: 700; margin-top: 2px; }\n    .adv-qd { font-size: 10.5px; color: #8a8f9a; margin-top: 2px; }\n    .adv-good { color: #5cbd8a; } .adv-warn { color: #e2a24a; } .adv-accent { color: #7ea2e8; } .adv-muted { color: #8a8f9a; }\n    .adv-lenstabs { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; }\n    .adv-lens-tab { background: #171b21; border: 1px solid #242932; color: #9aa0ab; border-radius: 999px; padding: 6px 12px; font-size: 11px; font-weight: 700; cursor: pointer; }\n    .adv-lens-tab.on { background: #6f9bef; color: #0f1115; border-color: #6f9bef; }\n    .adv-lenshint { font-size: 11px; margin-bottom: 10px; }\n    .adv-table { width: 100%; border-collapse: collapse; font-size: 11.5px; }\n    .adv-table th { text-align: left; color: #8a8f9a; font-size: 10px; text-transform: uppercase; letter-spacing: .03em; padding: 6px 8px; border-bottom: 1px solid #242932; }\n    .adv-table td { padding: 6px 8px; border-bottom: 1px solid #1b1f26; }\n    .adv-table th.num, .adv-table td.num { text-align: right; font-variant-numeric: tabular-nums; }\n    .adv-table .pdesc { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n  `,\n  render(d2) {\n    const path = d2.router('vendasMobileRouter').path || '/';\n    const user = d2.auth('appAuth').user;\n\n    if (path === '/' && !d2.state.geral && !d2.state.geralError && !d2.state._geralLoading) {\n      triggerGeralLoad(d2);\n    }\n\n    if (!d2.state.plugStatus && !d2.state._plugStatusLoading) {\n      triggerPlugStatusLoad(d2);\n    }\n    const plugStatus = plugStatusView(d2);\n\n    const navHtml = NAV_ITEMS.map((it) => {\n      const active = path === it.path;\n      return `<div class=\"navitem ${active ? 'active' : ''} ${it.disabled ? 'disabled' : ''}\" data-path=\"${it.path}\" data-disabled=\"${it.disabled ? '1' : '0'}\">\n        <span>${it.label}</span>\n        ${it.disabled ? '<span class=\"soon\">em breve</span>' : ''}\n      </div>`;\n    }).join('');\n\n    let contentHtml;\n    if (path === '/vendas') {\n      try {\n        contentHtml = `<div class=\"panel-light\"><div class=\"panel-card\">${d2.render('modenafs-app@zJlTKXWalfhfnfsLp3MHw', { dataset: d2.param('salesDs') }, { key: 'vendas', style: 'height:100%;display:block' })}</div></div>`;\n      } catch (e) {\n        contentHtml = renderRouteError('Vendas', e);\n      }\n    } else if (path === '/anuncios') {\n      try {\n        contentHtml = d2.render('modenafs-app@b2GYj4kRIi3poqaRT5yT8', {\n          mlAdsDs: d2.param('mlAdsDs'), plugDs: d2.param('plugDs'), productsDs: d2.param('productsDs'), settingsDs: d2.param('settingsDs'),\n          freteRealDs: d2.param('freteRealDs'),\n        }, { key: 'anuncios', style: 'height:100%;display:block' });\n      } catch (e) {\n        contentHtml = renderRouteError('Anúncios', e);\n      }\n    } else if (path === '/manutencao') {\n      try {\n        contentHtml = d2.render('modenafs-app@manutencaoCC', {\n          mlAdsDs: d2.param('mlAdsDs'), plugDs: d2.param('plugDs'),\n        }, { key: 'manutencao', style: 'height:100%;display:block' });\n      } catch (e) {\n        contentHtml = renderRouteError('Manutenção', e);\n      }\n    } else if (path === '/catalogo') {\n      try {\n        contentHtml = d2.render('modenafs-app@catalogoCC', {\n          mlAdsDs: d2.param('mlAdsDs'),\n        }, { key: 'catalogo', style: 'height:100%;display:block' });\n      } catch (e) {\n        contentHtml = renderRouteError('Catálogo', e);\n      }\n    } else if (path === '/promocoes') {\n      try {\n        contentHtml = d2.render('modenafs-app@promocoesCC', {\n          mlAdsDs: d2.param('mlAdsDs'), plugDs: d2.param('plugDs'), productsDs: d2.param('productsDs'),\n          settingsDs: d2.param('settingsDs'), freteRealDs: d2.param('freteRealDs'),\n        }, { key: 'promocoes', style: 'height:100%;display:block' });\n      } catch (e) {\n        contentHtml = renderRouteError('Promoções', e);\n      }\n    } else if (path === '/fiscal') {\n      try {\n        contentHtml = d2.render('modenafs-app@fiscalCC', {\n          mlAdsDs: d2.param('mlAdsDs'), plugDs: d2.param('plugDs'), productsDs: d2.param('productsDs'), settingsDs: d2.param('settingsDs'),\n        }, { key: 'fiscal', style: 'height:100%;display:block' });\n      } catch (e) {\n        contentHtml = renderRouteError('Dados Fiscais', e);\n      }\n    } else if (path === '/publicar') {\n      try {\n        contentHtml = d2.render('modenafs-app@publicarCC', {}, { key: 'publicar', style: 'height:100%;display:block' });\n      } catch (e) {\n        contentHtml = renderRouteError('Publicar', e);\n      }\n    } else if (SOON_LABEL[path]) {\n      contentHtml = `<div class=\"soon-page\"><div class=\"t\">${SOON_LABEL[path]}</div><div>Em construção — próximo item do backlog do broker.</div></div>`;\n    } else {\n      try {\n        contentHtml = renderGeral(d2);\n      } catch (e) {\n        contentHtml = `<div class=\"geral\"><h1>Visão geral</h1><div class=\"error-state\">\n          <span>Falha ao renderizar a visão geral: ${esc((e && e.message) || String(e))}</span>\n          <button class=\"btn-retry\" data-action=\"retry-geral\">Tentar novamente</button>\n        </div></div>`;\n      }\n    }\n\n    return `<div class=\"shell\">\n      <div class=\"nav\">\n        <div class=\"brand\">MODENAFS</div>\n        <div class=\"navlist\">${navHtml}</div>\n        <div class=\"userbox\">\n          <div class=\"useremail\">${esc((user && user.email) || '')}</div>\n          <button class=\"plugstatus ${plugStatus.cls}\" data-action=\"refresh-plug-status\" title=\"Integração Plug — clique para atualizar\">\n            <span class=\"dot\"></span>Plug: ${plugStatus.label}\n          </button>\n          <button class=\"logout\" data-action=\"logout\">Sair</button>\n        </div>\n      </div>\n      <div class=\"content\">${contentHtml}</div>\n      ${d2.render('modenafs-app@fichaCC', {\n        mlAdsDs: d2.param('mlAdsDs'), plugDs: d2.param('plugDs'), productsDs: d2.param('productsDs'),\n        freteRealDs: d2.param('freteRealDs'), snapshotsDs: 'snapshotsDataSet',\n        itemVisitsDs: 'item-visitsDataSet', contentDs: 'contentDataSet',\n      }, { key: 'ficha-overlay', width: 0, height: 0, style: 'overflow:visible;pointer-events:none' })}\n    </div>`;\n  },\n  mounted(d2) {\n    d2.on('.navitem', 'click', (e, el) => {\n      if (el.dataset.disabled === '1') return;\n      d2.router('vendasMobileRouter').goTo(el.dataset.path);\n    });\n    d2.on('[data-action=\"logout\"]', 'click', async () => {\n      await d2.auth('appAuth').logout();\n      d2.router('vendasMobileRouter').goTo('/');\n    });\n    d2.on('[data-action=\"retry-geral\"]', 'click', () => {\n      d2.state.geral = null;\n      d2.state.geralError = null;\n      triggerGeralLoad(d2);\n    });\n    d2.on('[data-action=\"retry-route\"]', 'click', () => {\n      d2.refresh();\n    });\n    d2.on('[data-action=\"refresh-plug-status\"]', 'click', () => {\n      d2.state.plugStatus = null;\n      triggerPlugStatusLoad(d2);\n    });\n    d2.on('[data-action=\"toggle-advanced\"]', 'click', () => {\n      d2.state.advOpen = !d2.state.advOpen;\n      if (d2.state.advOpen && !d2.state.adv) loadAdvanced(d2);\n    });\n    d2.on('[data-action=\"retry-advanced\"]', 'click', () => {\n      d2.state.adv = null;\n      loadAdvanced(d2);\n    });\n    d2.on('.adv-qcell', 'click', (e, el) => {\n      if (!d2.state.adv) return;\n      const k = el.dataset.quad;\n      d2.state.adv = Object.assign({}, d2.state.adv, { openQuadrant: d2.state.adv.openQuadrant === k ? null : k });\n    });\n    d2.on('.adv-lens-tab', 'click', (e, el) => {\n      if (!d2.state.adv) return;\n      d2.state.adv = Object.assign({}, d2.state.adv, { lens: el.dataset.lens });\n    });\n    bindGeralCharts(d2);\n    bindAdvancedControls(d2);\n  },\n  updated(d2) {\n    bindGeralCharts(d2);\n    bindAdvancedControls(d2);\n  },\n};\n\nfunction esc(s) { return String(s == null ? '' : s).replace(/[&<>\"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[c])); }\nfunction compact(n) {\n  n = Number(n) || 0;\n  if (Math.abs(n) >= 1000) return (n / 1000).toFixed(1).replace('.0', '') + 'K';\n  return n.toFixed(0);\n}\n\nfunction renderRouteError(label, e) {\n  return `<div class=\"route-error-page\"><div class=\"error-state\">\n    <span>Falha ao renderizar ${esc(label)}: ${esc((e && e.message) || String(e))}</span>\n    <button class=\"btn-retry\" data-action=\"retry-route\">Tentar novamente</button>\n  </div></div>`;\n}\n\nfunction marginTierColor(pct) {\n  if (pct >= 20) return '#5cbd8a';\n  if (pct >= 10) return '#e2a24a';\n  return '#e2685a';\n}\n\nfunction heatColor(pct) {\n  if (!pct || pct <= 0) return '#171b21';\n  const c0 = [23, 27, 33];\n  const c1 = [111, 155, 239];\n  const t = Math.min(1, pct);\n  const rgb = c0.map((v, i) => Math.round(v + (c1[i] - v) * t));\n  return `rgb(${rgb[0]},${rgb[1]},${rgb[2]})`;\n}\n\nconst ADV_MARGIN_B = [['<0%', -1e9, 0], ['0-10%', 0, 10], ['10-20%', 10, 20], ['20-30%', 20, 30], ['30-50%', 30, 50], ['50%+', 50, 1e9]];\nconst ADV_DEMAND_B = [['0', -1, 1], ['1-4', 1, 5], ['5-19', 5, 20], ['20-99', 20, 100], ['100+', 100, 1e12]];\nconst ADV_PRICE_B = [['<R$50', 0, 50], ['50-150', 50, 150], ['150-300', 150, 300], ['300-600', 300, 600], ['600+', 600, 1e12]];\nconst ADV_DISC_B = [['sem promo', -1, 0.5], ['1-10%', 0.5, 10], ['10-20%', 10, 20], ['20-40%', 20, 40], ['40%+', 40, 1e9]];\nconst ADV_ADS_B = [['0', -1, 0.5], ['1-3', 0.5, 4], ['4-7', 4, 8], ['8+', 8, 1e9]];\nconst ADV_COMP_B = [['<=10', -1, 11], ['11-25', 11, 26], ['26-47', 26, 48], ['48+', 48, 1e9]];\nconst ADV_BAND_DIMS = { margin: ADV_MARGIN_B, demand: ADV_DEMAND_B, price: ADV_PRICE_B, discount: ADV_DISC_B, ads: ADV_ADS_B, competition: ADV_COMP_B };\nconst ADV_DIM_LABELS = [['category', 'categoria'], ['brand', 'marca'], ['margin', 'faixa de margem'], ['demand', 'faixa de demanda'], ['price', 'faixa de preco'], ['discount', 'faixa de desconto'], ['ads', 'faixa de ADS'], ['competition', 'faixa de concorrencia']];\nconst ADV_VALUE_LABELS = [['count', 'no de SKUs'], ['avg_margin', 'margem media %'], ['profit', 'lucro unit. somado (R$)'], ['demand', 'demanda total (unid. vendidas)'], ['ads', 'anuncios patrocinados'], ['promo', 'anuncios em promocao'], ['disc_avg', 'desconto medio %'], ['avg_competition', 'concorrencia media']];\nconst ADV_VALUE_KIND = { count: 'int', avg_margin: 'pct', profit: 'money', demand: 'int', ads: 'int', promo: 'int', disc_avg: 'pct', avg_competition: 'num' };\n\nfunction advBand(bands, v) {\n  for (let i = 0; i < bands.length; i++) { if (v >= bands[i][1] && v < bands[i][2]) return bands[i][0]; }\n  return bands[bands.length - 1][0];\n}\nfunction advDimLabel(dim, m) {\n  if (dim === 'category') return m.category;\n  if (dim === 'brand') return m.brand === '—' ? null : m.brand;\n  const bands = ADV_BAND_DIMS[dim];\n  if (!bands) return m.category;\n  const map = { margin: m.margin, demand: m.demand, price: m.price, discount: m.discAvg, ads: m.ads, competition: m.comp };\n  const v = map[dim];\n  return (v === null || v === undefined) ? null : advBand(bands, v);\n}\nfunction advOrderedLabels(dim, counts, topN) {\n  if (ADV_BAND_DIMS[dim]) return ADV_BAND_DIMS[dim].map((b) => b[0]);\n  return Object.keys(counts).sort((a, b) => counts[b] - counts[a]).slice(0, topN);\n}\nfunction advZeroCell() { return { count: 0, msum: 0, mn: 0, profit: 0, demand: 0, ads: 0, promo: 0, discSum: 0, discN: 0, comp: 0 }; }\nfunction advCellValue(cell, kind) {\n  if (kind === 'count') return cell.count;\n  if (kind === 'avg_margin') return cell.mn ? Math.round((cell.msum / cell.mn) * 10) / 10 : null;\n  if (kind === 'profit') return Math.round(cell.profit);\n  if (kind === 'ads') return cell.ads;\n  if (kind === 'promo') return cell.promo;\n  if (kind === 'disc_avg') return cell.discN ? Math.round((cell.discSum / cell.discN) * 10) / 10 : null;\n  if (kind === 'avg_competition') return cell.count ? Math.round((cell.comp / cell.count) * 10) / 10 : null;\n  return cell.demand;\n}\nfunction computeAdvHeatmap(metrics, rowDim, colDim, valKind) {\n  const cells = {}; const rcount = {}; const ccount = {};\n  metrics.forEach((m) => {\n    const rl = advDimLabel(rowDim, m); const cl = advDimLabel(colDim, m);\n    if (rl == null || cl == null) return;\n    rcount[rl] = (rcount[rl] || 0) + 1; ccount[cl] = (ccount[cl] || 0) + 1;\n    if (!cells[rl]) cells[rl] = {};\n    const cell = cells[rl][cl] || (cells[rl][cl] = advZeroCell());\n    cell.count += 1; cell.demand += m.demand; cell.ads += m.ads; cell.promo += m.promoCount; cell.comp += m.comp;\n    if (m.discAvg != null) { cell.discSum += m.discAvg; cell.discN += 1; }\n    if (m.profit != null) cell.profit += m.profit;\n    if (m.margin != null) { cell.msum += m.margin; cell.mn += 1; }\n  });\n  const rows = advOrderedLabels(rowDim, rcount, 14);\n  const cols = advOrderedLabels(colDim, ccount, 10);\n  const cellsMatrix = rows.map((rl) => cols.map((cl) => advCellValue((cells[rl] && cells[rl][cl]) || advZeroCell(), valKind)));\n  return { rows: rows, cols: cols, cells: cellsMatrix, valueKind: ADV_VALUE_KIND[valKind] };\n}\nfunction computeAdvQuadrants(metrics) {\n  const withMargin = metrics.filter((m) => m.margin != null).map((m) => m.margin).sort((a, b) => a - b);\n  const marginMed = withMargin.length ? withMargin[Math.floor(withMargin.length / 2)] : 0;\n  const DEMAND_HI = 3;\n  const quad = { estrela: 0, vaca: 0, nicho: 0, duvida: 0 };\n  const items = { estrela: [], vaca: [], nicho: [], duvida: [] };\n  metrics.forEach((m) => {\n    if (m.margin == null) return;\n    const hd = m.demand >= DEMAND_HI; const hm = m.margin >= marginMed;\n    const k = hd && hm ? 'estrela' : hd ? 'vaca' : hm ? 'nicho' : 'duvida';\n    quad[k] += 1;\n    items[k].push(m);\n  });\n  Object.keys(items).forEach((k) => {\n    items[k].sort((a, b) => (k === 'nicho' || k === 'duvida') ? (((b.margin || 0) - (a.margin || 0)) || (b.demand - a.demand)) : ((b.demand - a.demand) || ((b.margin || 0) - (a.margin || 0))));\n    items[k] = items[k].slice(0, 30);\n  });\n  return { quad: quad, items: items, marginMed: marginMed };\n}\nfunction computeAdvCategoryPressure(metrics) {\n  const cats = {};\n  metrics.forEach((m) => {\n    const c = cats[m.category] || (cats[m.category] = { category: m.category, count: 0, comp: 0, ads: 0, promo: 0, discSum: 0, discN: 0 });\n    c.count += 1; c.comp += m.comp; c.ads += m.ads; c.promo += m.promoCount;\n    if (m.discAvg != null) { c.discSum += m.discAvg; c.discN += 1; }\n  });\n  return Object.keys(cats).map((k) => {\n    const c = cats[k];\n    return {\n      category: c.category, count: c.count,\n      avgCompetition: c.count ? Math.round((c.comp / c.count) * 10) / 10 : null,\n      adsRate: c.comp ? Math.round((1000 * c.ads) / c.comp) / 10 : 0,\n      promoRate: c.comp ? Math.round((1000 * c.promo) / c.comp) / 10 : 0,\n      discAvg: c.discN ? Math.round((c.discSum / c.discN) * 10) / 10 : null,\n    };\n  }).sort((a, b) => b.count - a.count).slice(0, 12);\n}\nfunction computeAdvBrands(metrics) {\n  const brands = {};\n  metrics.forEach((m) => {\n    if (!m.brand || m.brand === '—') return;\n    const b = brands[m.brand] || (brands[m.brand] = { brand: m.brand, count: 0, msum: 0, mn: 0, demand: 0 });\n    b.count += 1; b.demand += m.demand;\n    if (m.margin != null) { b.msum += m.margin; b.mn += 1; }\n  });\n  return Object.keys(brands).map((k) => {\n    const b = brands[k];\n    return { brand: b.brand, count: b.count, demand: b.demand, avgMargin: b.mn ? Math.round((b.msum / b.mn) * 10) / 10 : null };\n  }).sort((a, b) => b.count - a.count).slice(0, 14);\n}\nconst ADV_LENS_INFO = {\n  boi_piranha: { label: 'Boi de piranha', hint: 'Os mais vendidos entre os mais baratos (ticket abaixo da mediana) -- peca popular e barata pra atrair trafego/venda.' },\n  baixar_mais: { label: 'Da pra baixar mais', hint: 'Margem acima do piso minimo (12%) -- headroom = quanto da pra cortar do preco e ainda bater a margem minima.' },\n  make_market: { label: 'Fazer mercado', hint: 'Tem demanda e pouca concorrencia -- facil ganhar share. market score = vendidos / (concorrentes+1).' },\n  absolute: { label: 'Lucro absoluto', hint: 'Maior lucro em R$ por unidade (preco menos custo).' },\n  margin: { label: 'Maior margem', hint: 'Maior margem % sobre o preco.' },\n  best_sellers: { label: 'Mais vendidos', hint: 'Mais vendidos (unidades, historico de pedidos pagos).' },\n};\nfunction computeAdvLenses(metrics) {\n  const cands = metrics.filter((m) => m.comp >= 4 && m.price && m.cost);\n  const sortedPrices = cands.map((m) => m.price).sort((a, b) => a - b);\n  const ticketMed = sortedPrices.length ? sortedPrices[Math.floor(sortedPrices.length / 2)] : 0;\n  const topN = (items, keyFn, n, whereFn) => {\n    const filtered = whereFn ? items.filter(whereFn) : items.slice();\n    return filtered.slice().sort((a, b) => (keyFn(b) || 0) - (keyFn(a) || 0)).slice(0, n);\n  };\n  return {\n    boi_piranha: topN(cands, (m) => m.demand, 30, (m) => m.demand > 0 && m.price <= ticketMed),\n    baixar_mais: topN(cands, (m) => m.headroom || 0, 30, (m) => !m.belowFloor && m.demand > 0 && (m.headroom || 0) > 0),\n    make_market: topN(cands, (m) => m.marketScore, 30, (m) => m.demand > 0),\n    absolute: topN(cands, (m) => m.profit, 30, null),\n    margin: topN(cands, (m) => m.margin, 30, null),\n    best_sellers: topN(cands, (m) => m.demand, 30, (m) => m.demand > 0),\n  };\n}\nfunction recomputeAdvHeatmap(d2) {\n  const a = d2.state.adv;\n  if (!a || !a.metrics) return;\n  const heatmap = computeAdvHeatmap(a.metrics, a.heatRow, a.heatCol, a.heatVal);\n  d2.state.adv = Object.assign({}, a, { heatmap: heatmap });\n}\nfunction bindAdvancedControls(d2) {\n  const bind = (id, key) => {\n    const el = d2.$('#' + id);\n    if (!el || el.dataset.bound) return;\n    el.dataset.bound = '1';\n    if (d2.state.adv && d2.state.adv[key]) el.value = d2.state.adv[key];\n    d2.on(el, 'change', () => {\n      if (!d2.state.adv) return;\n      const next = Object.assign({}, d2.state.adv);\n      next[key] = el.value;\n      d2.state.adv = next;\n      recomputeAdvHeatmap(d2);\n    });\n  };\n  bind('advHeatRow', 'heatRow');\n  bind('advHeatCol', 'heatCol');\n  bind('advHeatVal', 'heatVal');\n}\nasync function loadAdvanced(d2) {\n  const gen = (d2.state._advGen = (d2.state._advGen || 0) + 1);\n  d2.state.adv = Object.assign({}, d2.state.adv || {}, { loading: true, error: null });\n  try {\n    const productsDs = await waitForDataset(d2, 'productsDs');\n    const plugDs = await waitForDataset(d2, 'plugDs');\n    const mlAdsDs = await waitForDataset(d2, 'mlAdsDs');\n    const salesDs = await waitForDataset(d2, 'salesDs');\n    const arr = (r) => (Array.isArray(r) ? r : (r && Array.isArray(r.data) ? r.data : []));\n\n    const snapRes = await d2.rush('dash-adv-snapshots').invoke({});\n    if (d2.state._advGen !== gen) return;\n    const snapBody = (snapRes && snapRes.data) ? snapRes.data : snapRes;\n    const snapRows = arr(snapBody && snapBody.rows).filter((r) => r._id);\n    const codes = snapRows.map((r) => r._id);\n\n    const prodRes = await productsDs.aggregate([{ $match: { code: { $in: codes } } }, { $project: { _id: 0, code: 1, category: 1, description: 1 } }]);\n    const plugRes = await plugDs.aggregate([{ $match: { code: { $in: codes } } }, { $group: { _id: '$code', brand: { $first: '$brand' }, cost: { $first: '$cost' }, stock: { $sum: '$stock' } } }]);\n    const adsRes = await mlAdsDs.aggregate([{ $match: { code: { $in: codes }, status: 'active' } }, { $group: { _id: '$code', price: { $avg: '$price' } } }]);\n    const salesRes = await salesDs.aggregate([{ $match: { status: 'paid' } }, { $group: { _id: '$sku', units: { $sum: '$units' } } }]);\n    if (d2.state._advGen !== gen) return;\n\n    const catMap = {}; arr(prodRes).forEach((r) => { catMap[r.code] = r; });\n    const plugMap = {}; arr(plugRes).forEach((r) => { plugMap[r._id] = r; });\n    const priceMap = {}; arr(adsRes).forEach((r) => { priceMap[r._id] = r.price; });\n    const demandMap = {};\n    arr(salesRes).forEach((r) => {\n      const base = primaryCode(r._id);\n      demandMap[base] = (demandMap[base] || 0) + (Number(r.units) || 0);\n    });\n\n    const MIN_MARGIN_FLOOR = 12;\n    const metrics = snapRows.map((r) => {\n      const code = r._id;\n      const info = catMap[code] || {};\n      const plugInfo = plugMap[code] || {};\n      const price = priceMap[code] || null;\n      const cost = plugInfo.cost || null;\n      const margin = (price && cost) ? Math.round(((price - cost) / price) * 1000) / 10 : null;\n      const profit = (price && cost) ? Math.round((price - cost) * 100) / 100 : null;\n      const belowFloor = margin != null && margin < MIN_MARGIN_FLOOR;\n      const minProfitPrice = cost != null ? cost / (1 - MIN_MARGIN_FLOOR / 100) : null;\n      const headroom = (price && minProfitPrice && margin != null && margin >= MIN_MARGIN_FLOOR) ? Math.round((price - minProfitPrice) * 100) / 100 : null;\n      const comp = Number(r.comp) || 0;\n      const demand = demandMap[primaryCode(code)] || 0;\n      const rawCat = (info.category || 'Sem categoria').trim();\n      return {\n        code: code, description: info.description || code, category: rawCat ? rawCat.toUpperCase() : 'SEM CATEGORIA',\n        brand: plugInfo.brand || '—', price: price, cost: cost, margin: margin, profit: profit, demand: demand,\n        ads: Number(r.ads) || 0, comp: comp, promoCount: Number(r.promoCount) || 0,\n        discAvg: r.discN ? Math.round((r.discSum / r.discN) * 10) / 10 : null,\n        stock: plugInfo.stock != null ? plugInfo.stock : null,\n        belowFloor: belowFloor, headroom: headroom, marketScore: Math.round((demand / (comp + 1)) * 10) / 10,\n      };\n    });\n\n    const heatRow = (d2.state.adv && d2.state.adv.heatRow) || 'category';\n    const heatCol = (d2.state.adv && d2.state.adv.heatCol) || 'margin';\n    const heatVal = (d2.state.adv && d2.state.adv.heatVal) || 'count';\n    const heatmap = computeAdvHeatmap(metrics, heatRow, heatCol, heatVal);\n    const advQuad = computeAdvQuadrants(metrics);\n    const byCategory = computeAdvCategoryPressure(metrics);\n    const byBrand = computeAdvBrands(metrics);\n    const lenses = computeAdvLenses(metrics);\n    const priced = metrics.filter((m) => m.margin != null).length;\n\n    d2.state.adv = {\n      loading: false, error: null, metrics: metrics, heatRow: heatRow, heatCol: heatCol, heatVal: heatVal,\n      heatmap: heatmap, quad: advQuad.quad, quadItems: advQuad.items, marginMed: advQuad.marginMed,\n      byCategory: byCategory, byBrand: byBrand, lenses: lenses,\n      lens: (d2.state.adv && d2.state.adv.lens) || 'boi_piranha',\n      openQuadrant: (d2.state.adv && d2.state.adv.openQuadrant) || null,\n      priced: priced, universe: metrics.length,\n    };\n  } catch (e) {\n    if (d2.state._advGen !== gen) return;\n    d2.state.adv = Object.assign({}, d2.state.adv || {}, { loading: false, error: (e && e.message) || String(e) });\n  }\n}\n\nfunction renderAdvancedToggle(d2) {\n  const open = !!d2.state.advOpen;\n  const label = open ? 'ocultar analise avancada' : 'analise avancada';\n  return `<div class=\"adv-toggle-row\">\n    <button type=\"button\" class=\"adv-toggle-btn\" data-action=\"toggle-advanced\">${label}</button>\n  </div>`;\n}\n\nfunction buildAdvHeatmapHtml(hm) {\n  if (!hm || !hm.rows.length) return '<div class=\"adv-empty\">Sem dados para essas dimensoes.</div>';\n  const flat = hm.cells.reduce((acc, row) => acc.concat(row), []).filter((v) => v != null).map((v) => Math.abs(v));\n  const maxAbs = Math.max(1, flat.length ? Math.max.apply(null, flat) : 1);\n  const fmt = (v) => {\n    if (v == null) return '-';\n    if (v === 0) return '0';\n    if (hm.valueKind === 'money') return Math.abs(v) >= 1000 ? `R$ ${Math.round(v / 1000)}k` : `R$ ${Math.round(v)}`;\n    if (hm.valueKind === 'pct') return `${v}%`;\n    return Number(v).toLocaleString('pt-BR');\n  };\n  const bg = (v) => {\n    if (v == null) return '#171b21';\n    if (hm.valueKind === 'pct') return v >= 20 ? 'rgba(92,189,138,.4)' : v >= 10 ? 'rgba(226,162,74,.4)' : 'rgba(226,104,90,.4)';\n    return heatColor(Math.abs(v) / maxAbs);\n  };\n  const fg = (v) => (v != null && hm.valueKind !== 'pct' && Math.abs(v) / maxAbs > 0.55) ? '#0f1115' : '#cbd0d8';\n  const colHeads = hm.cols.map((c) => `<div class=\"heat-col-h\">${esc(c)}</div>`).join('');\n  const body = hm.rows.map((rl, ri) => {\n    const rowCells = hm.cells[ri].map((v) => `<div class=\"heat-cell\" style=\"background:${bg(v)};color:${fg(v)}\" title=\"${esc(rl)}\">${fmt(v)}</div>`).join('');\n    return `<div class=\"heat-row-h\" title=\"${esc(rl)}\">${esc(rl)}</div>${rowCells}`;\n  }).join('');\n  return `<div class=\"heatmap-grid adv-heatmap\" style=\"grid-template-columns:110px repeat(${hm.cols.length},1fr)\">\n    <div></div>${colHeads}${body}\n  </div>`;\n}\n\nfunction buildAdvQuadrantHtml(adv) {\n  const q = adv.quad || {};\n  const defs = [\n    ['estrela', 'Estrelas', 'alta demanda + alta margem', 'good'],\n    ['vaca', 'Volume', 'alta demanda, margem fina', 'warn'],\n    ['nicho', 'Nicho', 'baixa demanda, margem alta', 'accent'],\n    ['duvida', 'Duvida', 'baixa demanda + margem baixa', 'muted'],\n  ];\n  const cellsHtml = defs.map((d) => {\n    const k = d[0]; const t = d[1]; const desc = d[2]; const c = d[3];\n    return `<div class=\"adv-qcell adv-border-${c} ${adv.openQuadrant === k ? 'on' : ''}\" data-quad=\"${k}\">\n    <div class=\"adv-qn adv-${c}\">${(q[k] || 0).toLocaleString('pt-BR')}</div>\n    <div class=\"adv-qt\">${t} &rsaquo;</div><div class=\"adv-qd\">${desc}</div></div>`;\n  }).join('');\n  let detail = '';\n  if (adv.openQuadrant && adv.quadItems && adv.quadItems[adv.openQuadrant] && adv.quadItems[adv.openQuadrant].length) {\n    const rows = adv.quadItems[adv.openQuadrant].slice(0, 10);\n    const rowsHtml = rows.map((m) => {\n      const marginTxt = m.margin != null ? `${Math.round(m.margin)}%` : '-';\n      const profitTxt = m.profit != null ? `R$ ${m.profit.toFixed(2)}` : '-';\n      return `<tr><td class=\"muted\">${esc(m.code)}</td><td class=\"pdesc\">${esc(m.description)}</td><td>${esc(m.category)}</td><td class=\"num\">${(m.demand || 0).toLocaleString('pt-BR')}</td><td class=\"num\">${marginTxt}</td><td class=\"num\">${profitTxt}</td></tr>`;\n    }).join('');\n    detail = `<table class=\"adv-table\" style=\"margin-top:10px\"><thead><tr><th>codigo</th><th>peca</th><th>categoria</th><th class=\"num\">vendidos</th><th class=\"num\">margem</th><th class=\"num\">lucro</th></tr></thead><tbody>${rowsHtml}</tbody></table>`;\n  } else if (adv.openQuadrant) {\n    detail = '<div class=\"adv-empty\" style=\"margin-top:10px\">Sem SKUs nesta faixa.</div>';\n  }\n  return `<div class=\"adv-qgrid\">${cellsHtml}</div>${detail}`;\n}\nfunction buildAdvPressureHtml(byCategory) {\n  if (!byCategory.length) return '<div class=\"adv-empty\">Sem dados.</div>';\n  const rowsHtml = byCategory.map((c) => {\n    const compTxt = c.avgCompetition != null ? c.avgCompetition : '-';\n    const discTxt = c.discAvg != null ? `${c.discAvg}%` : '-';\n    return `<tr><td>${esc(c.category)}</td><td class=\"num\">${compTxt}</td><td class=\"num\">${c.adsRate}%</td><td class=\"num\">${c.promoRate}%</td><td class=\"num\">${discTxt}</td></tr>`;\n  }).join('');\n  return `<table class=\"adv-table\"><thead><tr><th>categoria</th><th class=\"num\">conc. med</th><th class=\"num\">% ADS</th><th class=\"num\">% promo</th><th class=\"num\">desc. med</th></tr></thead><tbody>${rowsHtml}</tbody></table>`;\n}\nfunction buildAdvBrandHtml(byBrand) {\n  if (!byBrand.length) return '<div class=\"adv-empty\">Sem dados de marca.</div>';\n  const maxM = Math.max(10, Math.max.apply(null, byBrand.map((b) => b.avgMargin || 0)));\n  return byBrand.map((b) => {\n    const pct = Math.max(2, Math.round((100 * (b.avgMargin || 0)) / maxM));\n    const marginTxt = b.avgMargin != null ? `${b.avgMargin}%` : '-';\n    return `<div class=\"barrow\"><span class=\"lbl wide\" title=\"${esc(b.brand)} - ${b.count} SKUs\">${esc(b.brand)} <span class=\"muted\">(${b.count})</span></span>\n    <span class=\"track\"><div class=\"fill\" style=\"width:${pct}%;background:${marginTierColor(b.avgMargin || 0)}\"></div></span>\n    <span class=\"val wide\">${marginTxt}</span></div>`;\n  }).join('');\n}\nfunction buildAdvLensTabsHtml(current) {\n  return Object.keys(ADV_LENS_INFO).map((k) => `<button type=\"button\" class=\"adv-lens-tab ${k === current ? 'on' : ''}\" data-lens=\"${k}\">${ADV_LENS_INFO[k].label}</button>`).join('');\n}\nfunction buildAdvLensTableHtml(rows) {\n  if (!rows || !rows.length) return '<div class=\"adv-empty\">Sem dados ainda para esta lente.</div>';\n  const rowsHtml = rows.map((o) => {\n    const marginTxt = o.margin != null ? `${Math.round(o.margin)}%` : '-';\n    const profitTxt = o.profit != null ? `R$ ${o.profit.toFixed(2)}` : '-';\n    const stockTxt = o.stock != null ? o.stock : '-';\n    return `<tr><td class=\"muted\">${esc(o.code)}</td><td class=\"pdesc\" title=\"${esc(o.description)}\">${esc(o.description)}</td><td>${esc(o.category)}</td>\n      <td class=\"num\">R$ ${(o.cost || 0).toFixed(2)}</td><td class=\"num\"><b>R$ ${(o.price || 0).toFixed(2)}</b></td>\n      <td class=\"num\">${marginTxt}</td><td class=\"num\">${profitTxt}</td>\n      <td class=\"num\">${o.comp}</td><td class=\"num\">${(o.demand || 0).toLocaleString('pt-BR')}</td><td class=\"num\">${stockTxt}</td></tr>`;\n  }).join('');\n  return `<table class=\"adv-table\"><thead><tr><th>codigo</th><th>peca</th><th>categoria</th><th class=\"num\">custo</th><th class=\"num\">preco</th><th class=\"num\">margem</th><th class=\"num\">lucro</th><th class=\"num\">concorr.</th><th class=\"num\">vendidos</th><th class=\"num\">estoque</th></tr></thead><tbody>${rowsHtml}</tbody></table>`;\n}\nfunction renderAdvancedSection(d2) {\n  const adv = d2.state.adv;\n  if (!adv || adv.loading) return '<div class=\"panel adv-section\"><div class=\"panel-h\">Analise avancada</div><div class=\"adv-empty\">Carregando analise avancada (cruza snapshots, plug, anuncios e vendas -- pode levar alguns segundos)...</div></div>';\n  if (adv.error) return `<div class=\"panel adv-section\"><div class=\"error-state\"><span>Falha ao carregar analise avancada: ${esc(adv.error)}</span><button class=\"btn-retry\" data-action=\"retry-advanced\">Tentar novamente</button></div></div>`;\n  const dimOptions = ADV_DIM_LABELS.map((d) => `<option value=\"${d[0]}\">${d[1]}</option>`).join('');\n  const valOptions = ADV_VALUE_LABELS.map((d) => `<option value=\"${d[0]}\">${d[1]}</option>`).join('');\n  const marginMedTxt = adv.marginMed != null ? `${Math.round(adv.marginMed)}%` : '-';\n  const heatmapHtml = buildAdvHeatmapHtml(adv.heatmap);\n  const quadrantHtml = buildAdvQuadrantHtml(adv);\n  const pressureHtml = buildAdvPressureHtml(adv.byCategory);\n  const brandHtml = buildAdvBrandHtml(adv.byBrand);\n  const lensTabsHtml = buildAdvLensTabsHtml(adv.lens);\n  const lensTableHtml = buildAdvLensTableHtml(adv.lenses[adv.lens]);\n  const lensHint = ADV_LENS_INFO[adv.lens].hint;\n  return `\n    <div class=\"panel adv-section\">\n      <div class=\"panel-h\">Heatmap configuravel <span class=\"muted\">(${adv.universe} SKUs cruzados, ${adv.priced} com margem calculada)</span></div>\n      <div class=\"adv-heatctl\">\n        <label>linha <select id=\"advHeatRow\">${dimOptions}</select></label>\n        <label>coluna <select id=\"advHeatCol\">${dimOptions}</select></label>\n        <label>valor <select id=\"advHeatVal\">${valOptions}</select></label>\n      </div>\n      <div class=\"adv-hint\">Cruze qualquer dimensao -- ex: faixa de demanda x faixa de desconto com valor no de SKUs mostra esforco promocional por volume.</div>\n      ${heatmapHtml}\n    </div>\n    <div class=\"dash-grid\" style=\"margin-top:14px\">\n      <div class=\"panel adv-section\">\n        <div class=\"panel-h\">Quadrante de oportunidade <span class=\"muted\">(demanda x margem, mediana ${marginMedTxt})</span></div>\n        ${quadrantHtml}\n      </div>\n      <div class=\"panel adv-section\">\n        <div class=\"panel-h\">Pressao competitiva <span class=\"muted\">(ADS, promocao, desconto por categoria)</span></div>\n        ${pressureHtml}\n      </div>\n    </div>\n    <div class=\"panel adv-section\" style=\"margin-top:14px\">\n      <div class=\"panel-h\">Margem por marca <span class=\"muted\">(top 14)</span></div>\n      ${brandHtml}\n    </div>\n    <div class=\"panel adv-section\" style=\"margin-top:14px\">\n      <div class=\"panel-h\">Ranking de oportunidade -- 6 lentes <span class=\"muted\">(demanda e concorrencia = mercado ML, via snapshots)</span></div>\n      <div class=\"adv-lenstabs\">${lensTabsHtml}</div>\n      <div class=\"adv-lenshint muted\">${lensHint}</div>\n      ${lensTableHtml}\n    </div>\n  `;\n}\n\nfunction buildHeatmapHtml(heatmap) {\n  const { rows, cols, cells, max } = heatmap;\n  const colHeads = cols.map((c) => `<div class=\"heat-col-h\">${esc(c)}</div>`).join('');\n  const body = rows.map((rowLabel, ri) => {\n    const rowCells = (cells[ri] || []).map((v) => {\n      const pct = max ? v / max : 0;\n      const bg = heatColor(pct);\n      const textColor = pct > 0.55 ? '#0f1115' : '#8a8f9a';\n      const label = v > 0 ? `R$ ${compact(v)}` : '·';\n      return `<div class=\"heat-cell\" style=\"background:${bg};color:${textColor}\" title=\"${esc(rowLabel)} · R$ ${v.toFixed(2)}\">${label}</div>`;\n    }).join('');\n    return `<div class=\"heat-row-h\">${esc(rowLabel)}</div>${rowCells}`;\n  }).join('');\n  return `<div class=\"heatmap-grid\"><div class=\"heat-corner\"></div>${colHeads}${body}</div>`;\n}\n\nfunction buildHotListHtml(items) {\n  if (!items || !items.length) return '<div style=\"color:#8a8f9a;font-size:12px\">Sem dados no período.</div>';\n  const max = Math.max(1, ...items.map((i) => i.value));\n  return items.map((i) => {\n    const pct = Math.max(2, Math.round((i.value / max) * 100));\n    const badge = i.trendBadge ? `<span class=\"pill ${i.trendClass}\">${esc(i.trendBadge)}</span>` : '';\n    return `<div class=\"barrow\">\n      <div class=\"lbl wide\" title=\"${esc(i.label)}\">${esc(i.label)}</div>\n      <div class=\"track\"><div class=\"fill\" style=\"width:${pct}%\"></div></div>\n      <div class=\"val wide\">${esc(i.valueLabel)} ${badge}</div>\n    </div>`;\n  }).join('');\n}\n\nfunction renderGeral(d2) {\n  const g = d2.state.geral;\n  const err = d2.state.geralError;\n  if (err) {\n    return `<div class=\"geral\"><h1>Visão geral</h1><div class=\"error-state\">\n      <span>Não foi possível carregar a visão geral: ${esc(err)}</span>\n      <button class=\"btn-retry\" data-action=\"retry-geral\">Tentar novamente</button>\n    </div></div>`;\n  }\n  if (!g) return `<div class=\"geral\"><h1>Visão geral</h1><div style=\"color:#8a8f9a\">Carregando…</div></div>`;\n  const dailyChartHtml = buildDailyChartSvg(g.daily);\n  const hourlyChartHtml = g.hourly ? buildHourlyChartSvg(g.hourly) : '';\n  const marginClass = g.margin30 < 10 ? 'crit' : (g.margin30 < 20 ? 'warn' : 'good');\n  const heatmapHtml = g.heatmap ? buildHeatmapHtml(g.heatmap) : '';\n  const catChartHtml = (g.categories && g.categories.length)\n    ? d2.render(\n        { component: 'data2-blocks@BlockChart', params: {\n          type: 'Horizontal',\n          dataset: g.categories,\n          dimension: 'category',\n          metric: 'revenue',\n          statistic: 'sum',\n          hideLegend: true,\n          textColor: '#cbd0d8',\n          gridColor: '#23272f',\n          datalabelColor: '#e7e4da',\n          dataColors: g.categories.map((c) => ({ value: c.category, color: c.marginColor })),\n        } },\n        {},\n        { key: 'catChart', style: 'width:100%;height:230px;display:block' },\n      )\n    : '<div style=\"color:#8a8f9a;font-size:12px\">Sem dados no período.</div>';\n  return `<div class=\"geral\">\n    <h1>Visão geral</h1>\n    <div class=\"kpis\">\n      <div class=\"kpi\"><div class=\"l\">Receita · 30d</div><div class=\"n\">R$ ${compact(g.revenue30)}</div></div>\n      <div class=\"kpi\"><div class=\"l\">Lucro · 30d</div><div class=\"n\">R$ ${compact(g.profit30)}</div></div>\n      <div class=\"kpi ${marginClass}\"><div class=\"l\">Margem média · 30d</div><div class=\"n\">${g.margin30.toFixed(1)}%</div></div>\n      <div class=\"kpi\"><div class=\"l\">Pedidos · 30d</div><div class=\"n\">${g.count30}</div></div>\n    </div>\n    <div class=\"dash-grid\">\n      <div class=\"panel wide\">\n        <div class=\"panel-h\">Receita diária (14d)</div>\n        <div class=\"chart-wrap\" data-chart=\"daily\">\n          ${dailyChartHtml}\n          <div class=\"chart-tooltip\" data-role=\"daily-tooltip\"></div>\n        </div>\n      </div>\n      ${g.hourly ? `<div class=\"panel wide\">\n        <div class=\"panel-h\">Distribuição por horário do dia (30d)</div>\n        <div class=\"chart-wrap small\" data-chart=\"hourly\">\n          ${hourlyChartHtml}\n          <div class=\"chart-tooltip\" data-role=\"hourly-tooltip\"></div>\n        </div>\n      </div>` : ''}\n      ${heatmapHtml ? `<div class=\"panel wide\">\n        <div class=\"panel-h\">Mapa de calor · dia da semana × horário (30d)</div>\n        ${heatmapHtml}\n      </div>` : ''}\n      <div class=\"panel\">\n        <div class=\"panel-h\">Mais vendidos (14d)</div>\n        ${buildHotListHtml(g.hot)}\n      </div>\n      <div class=\"panel\">\n        <div class=\"panel-h\">Receita &amp; margem por categoria (14d)</div>\n        <div class=\"chart-host\">${catChartHtml}</div>\n        <div class=\"chart-legend\">cor da barra = margem média · <span class=\"pill good\">≥20%</span> <span class=\"pill warn\">10–20%</span> <span class=\"pill bad\">&lt;10%</span></div>\n      </div>\n      <div class=\"panel wide\">\n        <div class=\"panel-h\">Anúncios por status</div>\n        <div class=\"statuschips\">\n          <span class=\"pill good\">${g.adsActive} ativos</span>\n          <span class=\"pill warn\">${g.adsPaused} pausados</span>\n          <span class=\"pill bad\">${g.adsReview} em revisão</span>\n        </div>\n      </div>\n    </div>\n    ${renderAdvancedToggle(d2)}\n    ${d2.state.advOpen ? renderAdvancedSection(d2) : ''}\n  </div>`;\n}\n\nasync function waitForDataset(d2, name, attempts = 30, delayMs = 150) {\n  for (let i = 0; i < attempts; i++) {\n    const ds = d2.data(name);\n    if (ds) return ds;\n    await new Promise((r) => setTimeout(r, delayMs));\n  }\n  throw new Error(`Dataset \"${name}\" indisponível.`);\n}\n\nasync function loadGeral(d2) {\n  const gen = (d2.state._geralGen = (d2.state._geralGen || 0) + 1);\n  d2.state._geralLoading = true;\n  d2.state.geralError = null;\n  try {\n    const [salesDs, adsDs, productsDs] = await Promise.all([\n      waitForDataset(d2, 'salesDs'),\n      waitForDataset(d2, 'mlAdsDs'),\n      waitForDataset(d2, 'productsDs'),\n    ]);\n    const since30 = new Date(Date.now() - 30 * 86400000).toISOString();\n    const since14 = new Date(Date.now() - 14 * 86400000).toISOString();\n    const since28 = new Date(Date.now() - 28 * 86400000).toISOString();\n    const arr = (r) => {\n      if (Array.isArray(r)) return r;\n      if (r && Array.isArray(r.data)) return r.data;\n      return null; // error/malformed shape — NOT a legitimate empty result\n    };\n    const requireArr = (r, label) => {\n      const a = arr(r);\n      if (a === null) throw new Error(`Resposta inesperada de \"${label}\" — provável falha silenciosa na consulta.`);\n      return a;\n    };\n    const [totalsRes, dailyRes, hourlyRes, statusRes, hotSkuRes, skuAggRes, priorHotRes, dowHourRes] = await Promise.all([\n      salesDs.aggregate([\n        { $match: { status: 'paid', order_date: { $gte: since30 } } },\n        { $group: { _id: null, revenue: { $sum: '$total' }, profit: { $sum: '$profit' }, count: { $sum: 1 } } },\n      ]),\n      salesDs.aggregate([\n        { $match: { status: 'paid', order_date: { $gte: since14 } } },\n        { $group: { _id: { $substrCP: ['$order_date', 0, 10] }, revenue: { $sum: '$total' } } },\n        { $sort: { _id: 1 } },\n      ]),\n      salesDs.aggregate([\n        { $match: { status: 'paid', order_date: { $gte: since30 } } },\n        { $group: { _id: { $hour: { date: { $toDate: '$order_date' }, timezone: 'America/Sao_Paulo' } }, revenue: { $sum: '$total' }, count: { $sum: 1 } } },\n      ]),\n      adsDs.aggregate([{ $group: { _id: '$status', n: { $sum: 1 } } }]),\n      salesDs.aggregate([\n        { $match: { status: 'paid', order_date: { $gte: since14 }, sku: { $exists: true, $ne: '' } } },\n        { $group: { _id: '$sku', revenue: { $sum: '$total' }, units: { $sum: '$units' }, count: { $sum: 1 } } },\n        { $sort: { revenue: -1 } },\n        { $limit: 8 },\n      ]),\n      salesDs.aggregate([\n        { $match: { status: 'paid', order_date: { $gte: since14 }, sku: { $exists: true, $ne: '' } } },\n        { $group: { _id: '$sku', revenue: { $sum: '$total' }, profit: { $sum: '$profit' }, count: { $sum: 1 } } },\n        { $limit: 500 },\n      ]),\n      salesDs.aggregate([\n        { $match: { status: 'paid', order_date: { $gte: since28, $lt: since14 }, sku: { $exists: true, $ne: '' } } },\n        { $group: { _id: '$sku', revenue: { $sum: '$total' } } },\n        { $limit: 500 },\n      ]),\n      salesDs.aggregate([\n        { $match: { status: 'paid', order_date: { $gte: since30 } } },\n        { $group: { _id: { dow: { $dayOfWeek: { date: { $toDate: '$order_date' }, timezone: 'America/Sao_Paulo' } }, hour: { $hour: { date: { $toDate: '$order_date' }, timezone: 'America/Sao_Paulo' } } }, revenue: { $sum: '$total' }, count: { $sum: 1 } } },\n      ]),\n    ]);\n    if (d2.state._geralGen !== gen) return;\n    const t = requireArr(totalsRes, 'totais de vendas (30d)')[0] || { revenue: 0, profit: 0, count: 0 };\n    const revenue30 = Number(t.revenue) || 0;\n    const profit30 = Number(t.profit) || 0;\n    const daily = requireArr(dailyRes, 'receita diária (14d)').map((r) => {\n      const iso = r._id || '';\n      const dd = iso.slice(8, 10);\n      const mm = iso.slice(5, 7);\n      return {\n        date: iso,\n        label: dd && mm ? `${dd}/${mm}` : iso.slice(5),\n        dateLabel: dd && mm ? `${dd}/${mm}/${iso.slice(0, 4)}` : iso,\n        revenue: Number(r.revenue) || 0,\n      };\n    });\n    const hourMap = {};\n    requireArr(hourlyRes, 'receita por hora (30d)').forEach((r) => { hourMap[r._id] = { revenue: Number(r.revenue) || 0, count: Number(r.count) || 0 }; });\n    const hourly = Array.from({ length: 24 }, (_, h) => ({\n      hour: h,\n      revenue: (hourMap[h] && hourMap[h].revenue) || 0,\n      count: (hourMap[h] && hourMap[h].count) || 0,\n    }));\n    const dowLabels = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'];\n    const bucketLabels = ['00–04h', '04–08h', '08–12h', '12–16h', '16–20h', '20–24h'];\n    const heatMatrix = Array.from({ length: 7 }, () => Array(6).fill(0));\n    requireArr(dowHourRes, 'atividade por dia×hora (30d)').forEach((r) => {\n      const dowRaw = (r._id && r._id.dow) || 1;\n      const hourRaw = (r._id && r._id.hour) || 0;\n      const dow = ((dowRaw - 1) % 7 + 7) % 7;\n      const bucket = Math.min(5, Math.max(0, Math.floor(hourRaw / 4)));\n      heatMatrix[dow][bucket] += Number(r.revenue) || 0;\n    });\n    const heatmap = { rows: dowLabels, cols: bucketLabels, cells: heatMatrix, max: Math.max(1, ...heatMatrix.flat()) };\n    const statusRows = requireArr(statusRes, 'status dos anúncios');\n    const findN = (k) => {\n      const r = statusRows.find((x) => x._id === k);\n      return r ? Number(r.n) || 0 : 0;\n    };\n\n    const hotRows = requireArr(hotSkuRes, 'ranking de SKUs (14d)').filter((r) => r._id);\n    const skuRows = requireArr(skuAggRes, 'agregação de SKUs (14d)').filter((r) => r._id);\n    const priorRows = requireArr(priorHotRes, 'ranking de SKUs (período anterior)').filter((r) => r._id);\n    const priorMap = {};\n    priorRows.forEach((r) => { priorMap[r._id] = Number(r.revenue) || 0; });\n    const codes = Array.from(new Set([...hotRows, ...skuRows].map((r) => primaryCode(r._id)).filter(Boolean)));\n    let codeMap = {};\n    if (codes.length) {\n      const infoRows = requireArr(await productsDs.aggregate([\n        { $match: { code: { $in: codes } } },\n        { $project: { code: 1, description: 1, category: 1, _id: 0 } },\n      ]), 'informações de produtos');\n      infoRows.forEach((r) => { codeMap[r.code] = r; });\n    }\n    if (d2.state._geralGen !== gen) return;\n\n    const hot = hotRows.map((r) => {\n      const info = codeMap[primaryCode(r._id)];\n      const revenue = Number(r.revenue) || 0;\n      const prior = priorMap[r._id] || 0;\n      let trendBadge = '→ estável';\n      let trendClass = 'muted';\n      if (!prior && revenue > 0) {\n        trendBadge = '🆕 novo';\n        trendClass = 'accent';\n      } else if (prior > 0) {\n        const growthPct = ((revenue - prior) / prior) * 100;\n        if (growthPct >= 20) {\n          trendBadge = `🔥 +${Math.round(growthPct)}%`;\n          trendClass = 'good';\n        } else if (growthPct <= -20) {\n          trendBadge = `📉 ${Math.round(growthPct)}%`;\n          trendClass = 'bad';\n        }\n      }\n      return {\n        label: (info && info.description) || r._id,\n        value: revenue,\n        valueLabel: `R$ ${compact(revenue)} · ${Number(r.count) || 0}`,\n        trendBadge,\n        trendClass,\n      };\n    });\n\n    const catTotals = {};\n    skuRows.forEach((r) => {\n      const info = codeMap[primaryCode(r._id)];\n      const rawCat = ((info && info.category) || 'Sem categoria').trim();\n      const cat = rawCat ? rawCat.toUpperCase() : 'SEM CATEGORIA';\n      if (!catTotals[cat]) catTotals[cat] = { revenue: 0, profit: 0, count: 0 };\n      catTotals[cat].revenue += Number(r.revenue) || 0;\n      catTotals[cat].profit += Number(r.profit) || 0;\n      catTotals[cat].count += Number(r.count) || 0;\n    });\n    let catList = Object.keys(catTotals).map((cat) => {\n      const c = catTotals[cat];\n      const avgMargin = c.revenue ? (c.profit / c.revenue) * 100 : 0;\n      return { category: cat, revenue: c.revenue, count: c.count, avgMargin };\n    });\n    catList.sort((a, b) => b.revenue - a.revenue);\n    if (catList.length > 7) {\n      const rest = catList.slice(7);\n      const restTotal = rest.reduce((acc, c) => ({ revenue: acc.revenue + c.revenue, profit: acc.profit + (c.revenue * c.avgMargin) / 100, count: acc.count + c.count }), { revenue: 0, profit: 0, count: 0 });\n      catList = catList.slice(0, 7).concat([{ category: 'OUTROS', revenue: restTotal.revenue, count: restTotal.count, avgMargin: restTotal.revenue ? (restTotal.profit / restTotal.revenue) * 100 : 0 }]);\n    }\n    const categories = catList.map((c) => ({\n      category: c.category,\n      revenue: Math.round(c.revenue * 100) / 100,\n      count: c.count,\n      avgMargin: Math.round(c.avgMargin * 10) / 10,\n      marginColor: marginTierColor(c.avgMargin),\n    }));\n\n    d2.state.geral = {\n      revenue30,\n      profit30,\n      margin30: revenue30 ? (profit30 / revenue30) * 100 : 0,\n      count30: Number(t.count) || 0,\n      daily,\n      hourly,\n      heatmap,\n      hot,\n      categories,\n      adsActive: findN('active'),\n      adsPaused: findN('paused'),\n      adsReview: findN('under_review'),\n    };\n    d2.state.geralError = null;\n  } catch (e) {\n    if (d2.state._geralGen !== gen) return;\n    d2.state.geralError = (e && e.message) || String(e);\n  }\n}\n","at":"2026-08-07T14:18:45.626Z"}}},{"_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":[]}},{"reference":"ComponentInstancesTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[{"_id":"6a710b4393c25ab6db120255","component":"data2-core-primitives@Router","system":"6a26a4d06aecdcf58a4260e0","displayName":"Vendas Mobile Router","params":{"routerType":{"component":"data2-core-primitives@String","params":{"content":"browser"}},"routes":[{"component":"data2-core-primitives@Route","params":{"path":"","name":"Visão Geral","content":{"component":"data2-core-types@ArtboardReference","params":{"reference":"KjY-dPEAY4AQwmXs4sdTl"}},"policies":[{"component":"data2-core-auth@Policy","params":{"authenticationStrategy":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"appAuth"}}}}]}},{"component":"data2-core-primitives@Route","params":{"path":"/vendas","name":"Vendas","content":{"component":"data2-core-types@ArtboardReference","params":{"reference":"KjY-dPEAY4AQwmXs4sdTl"}},"policies":[{"component":"data2-core-auth@Policy","params":{"authenticationStrategy":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"appAuth"}}}}]}},{"component":"data2-core-primitives@Route","params":{"path":"/anuncios","name":"Anúncios ao vivo","content":{"component":"data2-core-types@ArtboardReference","params":{"reference":"KjY-dPEAY4AQwmXs4sdTl"}},"policies":[{"component":"data2-core-auth@Policy","params":{"authenticationStrategy":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"appAuth"}}}}]}},{"component":"data2-core-primitives@Route","params":{"path":"/catalogo","name":"Catálogo","content":{"component":"data2-core-types@ArtboardReference","params":{"reference":"KjY-dPEAY4AQwmXs4sdTl"}},"policies":[{"component":"data2-core-auth@Policy","params":{"authenticationStrategy":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"appAuth"}}}}]}},{"component":"data2-core-primitives@Route","params":{"path":"/manutencao","name":"Manutenção","content":{"component":"data2-core-types@ArtboardReference","params":{"reference":"KjY-dPEAY4AQwmXs4sdTl"}},"policies":[{"component":"data2-core-auth@Policy","params":{"authenticationStrategy":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"appAuth"}}}}]}},{"component":"data2-core-primitives@Route","params":{"path":"/promocoes","name":"Promoções","content":{"component":"data2-core-types@ArtboardReference","params":{"reference":"KjY-dPEAY4AQwmXs4sdTl"}},"policies":[{"component":"data2-core-auth@Policy","params":{"authenticationStrategy":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"appAuth"}}}}]}},{"component":"data2-core-primitives@Route","params":{"path":"/fiscal","name":"Dados Fiscais","content":{"component":"data2-core-types@ArtboardReference","params":{"reference":"KjY-dPEAY4AQwmXs4sdTl"}},"policies":[{"component":"data2-core-auth@Policy","params":{"authenticationStrategy":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"appAuth"}}}}]}},{"component":"data2-core-primitives@Route","params":{"path":"/publicar","name":"Publicar","content":{"component":"data2-core-types@ArtboardReference","params":{"reference":"KjY-dPEAY4AQwmXs4sdTl"}},"policies":[{"component":"data2-core-auth@Policy","params":{"authenticationStrategy":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"appAuth"}}}}]}},{"component":"data2-core-primitives@Route","params":{"path":"/configuracoes","name":"Configurações","content":{"component":"data2-core-types@ArtboardReference","params":{"reference":"KjY-dPEAY4AQwmXs4sdTl"}},"policies":[{"component":"data2-core-auth@Policy","params":{"authenticationStrategy":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"appAuth"}}}}]}}],"login":{"component":"data2-core-types@ArtboardReference","params":{"reference":"VNUpqOFxTlGon6SRrHlen"}}},"reference":"vendasMobileRouter"},{"_id":"6a710b024eebe61018c56067","component":"data2-core-primitives@Artboard","system":"6a26a4d06aecdcf58a4260e0","displayName":"Login","params":{"title":{"component":"data2-core-primitives@String","params":{"content":"Login"}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":390,"height":844}},"position":{"component":"data2-core-types@Position","params":{"x":1941,"y":1837,"exactX":1941.04,"exactY":1836.79}}},"reference":"VNUpqOFxTlGon6SRrHlen"},{"_id":"6a733b2922f85e215ff62061","component":"data2-core-primitives@Artboard","system":"6a26a4d06aecdcf58a4260e0","displayName":"App Shell","params":{"title":{"component":"data2-core-primitives@String","params":{"content":"App Shell"}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":900}},"position":{"component":"data2-core-types@Position","params":{"x":-346,"y":-773,"exactX":-346.47,"exactY":-773.0500000000001}}},"reference":"KjY-dPEAY4AQwmXs4sdTl"},{"_id":"be95ee5cf7a39ffd264a85db","parent":"6a710b024eebe61018c56067","component":"modenafs-app@loginCC","system":"6a26a4d06aecdcf58a4260e0","displayName":"loginCC","params":{"super":{"position":{"component":"data2-core-types@Position","params":{"x":0,"y":0,"freeTransform":true,"left":true,"right":true,"top":true,"bottom":true}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":390,"height":844}}}},"reference":"2Uej-j1uAR_ZaZCHsB_TE"},{"_id":"dadebcae7deaee125b9dba26","parent":"6a733b2922f85e215ff62061","component":"modenafs-app@appShell","system":"6a26a4d06aecdcf58a4260e0","displayName":"appShell","params":{"salesDs":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"sales-ordersDataSet"}},"mlAdsDs":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"ml-adsDataSet"}},"plugDs":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"plugDataSet"}},"productsDs":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"productsDataSet"}},"settingsDs":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"settingsDataSet"}},"super":{"position":{"component":"data2-core-types@Position","params":{"x":0,"y":0,"freeTransform":true,"left":true,"right":true,"top":true,"bottom":true}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":900}}},"freteRealDs":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"frete-realDataSet"}},"integrationTokensDs":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"integration-tokensDataSet"}},"snapshotsDs":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"snapshotsUiDataSet"}},"itemVisitsDs":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"item-visitsDataSet"}},"contentDs":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"contentDataSet"}}},"reference":"2x8s2FlPkM3ohuPI7TiOU"}]}},{"_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":"6a7103e008b6800f847bf2d4","displayName":"Vendas Mobile","reference":"rkPio0t-C_EN0qYWW2J8J","params":{"name":{"component":"data2-core-primitives@String","params":{"content":"Vendas Mobile"}},"shortName":{"component":"data2-core-primitives@String","params":{"content":"Vendas Mobile"}},"domain":{"component":"data2-core-primitives@String","params":{"content":"vendas-mobile"}},"serverSideRendering":{"component":"data2-core-primitives@Boolean","params":{"content":true}},"entryPoint":{"component":"data2-core-types@ComponentInstanceReference","params":{"component":"data2-core-primitives@Router","reference":"vendasMobileRouter"}},"responseHeaders":{"X-Frame-Options":{"component":"data2-core-primitives@String","params":{"content":""}},"Content-Security-Policy":{"component":"data2-core-primitives@String","params":{"content":""}},"X-XSS-Protection":{"component":"data2-core-primitives@String","params":{"content":""}}}},"system":"6a26a4d06aecdcf58a4260e0","component":"data2-core-primitives@Application"}]}},{"reference":"DataComponentInstancesTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[{"_id":"6a710a5ab87db3d7773fd051","component":"data2-core@AuthenticationStrategy","system":"6a26a4d06aecdcf58a4260e0","params":{"credentials":[{"key":"email"},{"key":"password"}],"verifier":{"component":"data2-core-types@DataSetReference","params":{"reference":"auth-test-usersDataSet"}},"email":"email","password":"password"},"reference":"appAuth"},{"_id":"6a74cc951b86a79670a9375b","component":"data2-core@DataSet","system":"6a26a4d06aecdcf58a4260e0","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"auth-test-users"}}},"reference":"auth-test-usersDataSet"},{"_id":"6a74cc949f1ece2343b3be0e","component":"data2-core@Data2TableDataSource","system":"6a26a4d06aecdcf58a4260e0","params":{"table":"auth-test-users","schema":[{"component":"data2-core-types@Field","params":{"key":"email","title":"Email","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"password","title":"Password","component":"data2-core-types@Password","required":true}},{"component":"data2-core-types@Field","params":{"key":"name","title":"Name","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"created_at","title":"Created At","component":"data2-core-primitives@Date"}}]},"reference":"auth-test-users"},{"_id":"6a709eeb45f02cd14f4da980","component":"data2-core@DataSet","system":"6a26a4d06aecdcf58a4260e0","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"content"}}},"reference":"contentDataSet"},{"_id":"6a709ef9884f7600e0e0157a","component":"data2-core@DataSet","system":"6a26a4d06aecdcf58a4260e0","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"item-visits"}}},"reference":"item-visitsDataSet"},{"_id":"6a75e5858bf663d9684ac0cf","component":"data2-core@DataSet","system":"6a26a4d06aecdcf58a4260e0","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"snapshots"}},"pageSize":5},"reference":"snapshotsUiDataSet"},{"_id":"6a70bdcba9d7cf0ea98f38b9","component":"data2-core@DataSet","system":"6a26a4d06aecdcf58a4260e0","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"integration-tokens"}}},"reference":"integration-tokensDataSet"},{"_id":"6a70a323e61df36c32b8994e","component":"data2-core@DataSet","system":"6a26a4d06aecdcf58a4260e0","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"frete-real"}}},"reference":"frete-realDataSet"},{"_id":"6a709ee3e61df36c32b886d4","component":"data2-core@DataSet","system":"6a26a4d06aecdcf58a4260e0","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"settings"}}},"reference":"settingsDataSet"},{"_id":"6a709ed91370e69d3eccd812","component":"data2-core@DataSet","system":"6a26a4d06aecdcf58a4260e0","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"products"}}},"reference":"productsDataSet"},{"_id":"6a709eef6483fdd7832628c7","component":"data2-core@DataSet","system":"6a26a4d06aecdcf58a4260e0","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"plug"}}},"reference":"plugDataSet"},{"_id":"6a709ef4c2dec104f3ada23a","component":"data2-core@DataSet","system":"6a26a4d06aecdcf58a4260e0","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"ml-ads"}}},"reference":"ml-adsDataSet"},{"_id":"6a709079d1c8db219eddec34","component":"data2-core@DataSet","system":"6a26a4d06aecdcf58a4260e0","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"sales-orders"}},"sort":{"order_date":{"component":"data2-core-numerical-operators@Subtract","params":{"components":[0,1]}}}},"reference":"sales-ordersDataSet"},{"_id":"6a709eeab0362a2dfde73f09","component":"data2-core@Data2TableDataSource","system":"6a26a4d06aecdcf58a4260e0","params":{"table":"content","schema":[{"component":"data2-core-types@Field","params":{"key":"code","title":"Code","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"json","title":"Json","component":"data2-core-primitives@Object"}},{"component":"data2-core-types@Field","params":{"key":"created_at","title":"Created At","component":"data2-core-primitives@String"}}]},"reference":"content"},{"_id":"6a709ef8e07b51a57e84fc62","component":"data2-core@Data2TableDataSource","system":"6a26a4d06aecdcf58a4260e0","params":{"table":"item-visits","schema":[{"component":"data2-core-types@Field","params":{"key":"item_id","title":"Item Id","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"visits","title":"Visits","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"updated_at","title":"Updated At","component":"data2-core-primitives@String"}}]},"reference":"item-visits"},{"_id":"6a709ede6483fdd783262878","component":"data2-core@Data2TableDataSource","system":"6a26a4d06aecdcf58a4260e0","params":{"table":"snapshots","schema":[{"component":"data2-core-types@Field","params":{"key":"code","title":"Code","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"query","title":"Query","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"url","title":"Url","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"count","title":"Count","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"pmin","title":"Pmin","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"p25","title":"P25","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"median","title":"Median","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"p75","title":"P75","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"pmax","title":"Pmax","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"mean","title":"Mean","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"n_prices","title":"N Prices","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"ads_count","title":"Ads Count","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"prices_json","title":"Prices Json","component":"data2-core-primitives@Object"}},{"component":"data2-core-types@Field","params":{"key":"items_json","title":"Items Json","component":"data2-core-primitives@Object"}},{"component":"data2-core-types@Field","params":{"key":"filters_json","title":"Filters Json","component":"data2-core-primitives@Object"}},{"component":"data2-core-types@Field","params":{"key":"error","title":"Error","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"scraped_at","title":"Scraped At","component":"data2-core-primitives@String"}}]},"reference":"snapshots"},{"_id":"6a70bdcb56ea416681a65ef0","component":"data2-core@Data2TableDataSource","system":"6a26a4d06aecdcf58a4260e0","params":{"table":"integration-tokens","schema":[{"component":"data2-core-types@Field","params":{"key":"service","title":"Service","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"access_token","title":"Access Token","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"refresh_token","title":"Refresh Token","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"updatedAt","title":"Updated At","component":"data2-core-primitives@String"}}]},"reference":"integration-tokens"},{"_id":"6a70a323b0362a2dfde750e0","component":"data2-core@Data2TableDataSource","system":"6a26a4d06aecdcf58a4260e0","params":{"table":"frete-real","schema":[{"component":"data2-core-types@Field","params":{"key":"item_id","title":"Item Id","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"list_cost","title":"List Cost","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"billable_weight","title":"Billable Weight","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"price_ref","title":"Price Ref","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"discount_rate","title":"Discount Rate","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"updated_at","title":"Updated At","component":"data2-core-primitives@Number"}}]},"reference":"frete-real"},{"_id":"6a709ee36483fdd783262891","component":"data2-core@Data2TableDataSource","system":"6a26a4d06aecdcf58a4260e0","params":{"table":"settings","schema":[{"component":"data2-core-types@Field","params":{"key":"key","title":"Key","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"value","title":"Value","component":"data2-core-primitives@Object"}}]},"reference":"settings"},{"_id":"6a709ed91370e69d3eccd80d","component":"data2-core@Data2TableDataSource","system":"6a26a4d06aecdcf58a4260e0","params":{"table":"products","schema":[{"component":"data2-core-types@Field","params":{"key":"code","title":"Code","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"description","title":"Description","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"category","title":"Category","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"sales_history","title":"Sales History","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"sell_price","title":"Sell Price","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"cost","title":"Cost","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":"raw_json","title":"Raw Json","component":"data2-core-primitives@Object"}},{"component":"data2-core-types@Field","params":{"key":"updated_at","title":"Updated At","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"pkg_cost","title":"Pkg Cost","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"decision_status","title":"Decision Status","component":"data2-core-primitives@String"}}]},"reference":"products"},{"_id":"6a709eee1370e69d3eccd893","component":"data2-core@Data2TableDataSource","system":"6a26a4d06aecdcf58a4260e0","params":{"table":"plug","schema":[{"component":"data2-core-types@Field","params":{"key":"code","title":"Code","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"plug_product","title":"Plug Product","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"plug_category","title":"Plug Category","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"brand","title":"Brand","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"obs","title":"Obs","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"description","title":"Description","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"images_json","title":"Images Json","component":"data2-core-primitives@Object"}},{"component":"data2-core-types@Field","params":{"key":"side","title":"Side","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"cost","title":"Cost","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"stock","title":"Stock","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"technical_json","title":"Technical Json","component":"data2-core-primitives@Object"}},{"component":"data2-core-types@Field","params":{"key":"updated_at","title":"Updated At","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"clip","title":"Clip","component":"data2-core-primitives@String"}}]},"reference":"plug"},{"_id":"6a709ef4b0362a2dfde73f3a","component":"data2-core@Data2TableDataSource","system":"6a26a4d06aecdcf58a4260e0","params":{"table":"ml-ads","schema":[{"component":"data2-core-types@Field","params":{"key":"code","title":"Code","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"listing_type","title":"Listing Type","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"external_id","title":"External Id","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"price","title":"Price","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":"title","title":"Title","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"published_at","title":"Published At","component":"data2-core-primitives@String"}}]},"reference":"ml-ads"},{"_id":"6a709079b5cc5536295a7741","component":"data2-core@Data2TableDataSource","system":"6a26a4d06aecdcf58a4260e0","params":{"table":"sales-orders","schema":[{"component":"data2-core-types@Field","params":{"key":"order_id","title":"Order ID","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"order_date","title":"Order Date","component":"data2-core-primitives@Date"}},{"component":"data2-core-types@Field","params":{"key":"sku","title":"SKU","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"item_id","title":"Item ID","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"status","title":"Status","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"units","title":"Units","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"total","title":"Total","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"cost","title":"Cost","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"profit","title":"Profit","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"margin_pct","title":"Margin %","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"fulfillment_state","title":"Fulfillment State","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"rufato_order","title":"Rufato Order","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"plug_drop","title":"Plug Drop","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"error","title":"Error","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"synced_at","title":"Synced At","component":"data2-core-primitives@Date"}},{"component":"data2-core-types@Field","params":{"key":"real_loss","title":"Real Loss (Cancelled + Already Purchased)","component":"data2-core-primitives@Number"}}]},"reference":"sales-orders"}]}},{"reference":"BundlesTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[]}}],"processesParams":{}}}}