{"context":{"domain":"babi-lf"},"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":"6ab58b1260cbe7aa719c6d7b","name":"Lucas Fontana","domain":"babi-lf","visibility":"private","updatedAt":"2026-09-24T20:41:54.351Z","createdAt":"2026-09-24T20:41:54.351Z"}]}},{"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":"6ab5b717d41d6b6b0d5623ac","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Footer","package":"babi-lf","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 DEFAULT_COLUMNS = [\n  { title: 'A loja', links: [\n    { label: 'Sobre o Lucas Fontana', href: '#' },\n    { label: 'Perguntas frequentes', href: '#' },\n    { label: 'Fale com o Lucas', href: '#' },\n    { label: 'Minha conta', href: '#' }\n  ] },\n  { title: 'Políticas', links: [\n    { label: 'Trocas e devoluções', href: '#' },\n    { label: 'Envio e entrega', href: '#' },\n    { label: 'Política de privacidade', short: 'Privacidade', href: '#' },\n    { label: 'Termos e condições de venda', short: 'Termos de venda', href: '#' }\n  ] },\n  { title: 'Atendimento (SAC)', plain: true, links: [\n    { label: '[E-MAIL DO SAC]' },\n    { label: '[WHATSAPP DO SAC]' },\n    { label: '[HORÁRIO DE ATENDIMENTO]' }\n  ] }\n];\n\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n\nconst svg = (inner) => `<svg class=\"ic\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">${inner}</svg>`;\nconst ICON_IG = svg('<rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"5\"/><circle cx=\"12\" cy=\"12\" r=\"4\"/><circle cx=\"17.5\" cy=\"6.5\" r=\"0.8\" fill=\"currentColor\"/>');\nconst ICON_YT = svg('<rect x=\"2.5\" y=\"5\" width=\"19\" height=\"14\" rx=\"4\"/><path d=\"m10 9 5 3-5 3V9Z\"/>');\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.lf-footer {\n  --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff;\n  --grey-200: #c9cacd; --grey-300: #a7a9ad; --graphite-700: #34363a; --line-inverse: #26282b;\n  container: lf / inline-size;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;\n  -webkit-font-smoothing: antialiased;\n  background: var(--ink); color: var(--grey-200); width: 100%;\n  min-height: 100%; display: flex; flex-direction: column;\n}\n.lf-footer > .in { flex: 1 0 auto; }\n.lf-footer a:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.rule { height: 6px; display: flex; }\n.rule span { flex: 1; background: var(--red-500); }\n.rule i { width: 240px; background: repeating-conic-gradient(var(--white) 0 25%, var(--ink) 0 50%) 0 0 / 6px 6px; }\n.in { padding: 72px 96px 40px; display: flex; flex-direction: column; gap: 56px; }\n.top { display: flex; gap: 72px; }\n.brand { flex: 0 0 340px; display: flex; flex-direction: column; gap: 20px; }\n\n.logo { display: inline-flex; align-items: center; gap: 12px; color: var(--white); text-decoration: none; flex-shrink: 0; align-self: flex-start; }\n.logo-bars { display: flex; gap: 4px; }\n.logo-bars span { width: 7px; height: 30px; transform: skewX(-18deg); background: var(--red-500); }\n.logo-bars span + span { background: var(--white); }\n.logo-words { display: flex; flex-direction: column; gap: 3px; }\n.logo-name { font-size: 22px; font-weight: 800; font-stretch: 125%; font-style: italic; letter-spacing: .02em; line-height: 1; }\n.logo-tag { font-size: 10px; font-weight: 600; letter-spacing: .44em; color: var(--grey-300); line-height: 1; text-transform: uppercase; }\n\n.about { margin: 0; font-size: 14px; line-height: 1.6; }\n.social { display: flex; gap: 10px; }\n.social a { width: 44px; height: 44px; border: 1px solid var(--graphite-700); color: var(--grey-200); display: flex; align-items: center; justify-content: center; }\n.social a:hover { border-color: var(--white); color: var(--white); }\n.ic { width: 18px; height: 18px; flex: none; }\n\n.cols { flex: 1; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 32px; }\n.col { display: flex; flex-direction: column; gap: 14px; font-size: 14px; }\n.col h3 { margin: 0; font-size: 12px; font-weight: 700; letter-spacing: .2em; color: var(--white); text-transform: uppercase; }\n.col a { color: var(--grey-200); text-decoration: none; }\n.col a:hover { color: var(--white); }\n.short { display: none; }\n\n.legal { border-top: 1px solid var(--line-inverse); padding-top: 28px; display: flex; justify-content: space-between; align-items: center; gap: 24px; font-size: 13px; color: var(--grey-300); }\n.legal strong { color: var(--white); font-weight: 600; }\n.addr::before { content: ' · '; }\n\n@container lf (max-width: 1199px) {\n  .rule { height: 5px; }\n  .rule i { width: 160px; }\n  .in { padding: 56px 40px 32px; gap: 40px; }\n  .top { flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 24px; }\n  .brand { flex: 1 1 100%; flex-direction: row; justify-content: space-between; align-items: center; gap: 24px; }\n  .about { display: none; }\n  .cols { flex: 1 1 100%; gap: 24px; }\n  .col { gap: 12px; } .col h3 { font-size: 11px; }\n  .legal { flex-direction: column; align-items: flex-start; gap: 8px; padding-top: 24px; font-size: 12px; line-height: 1.5; }\n  .logo { gap: 10px; } .logo-bars { gap: 3px; } .logo-bars span { width: 6px; height: 28px; }\n  .logo-name { font-size: 20px; } .logo-tag { font-size: 9px; }\n}\n@container lf (max-width: 767px) {\n  .rule i { width: 96px; background-size: 5px 5px; }\n  .in { padding: 48px 20px 32px; gap: 36px; }\n  .brand { flex-direction: column; align-items: flex-start; gap: 16px; }\n  .about { display: block; }\n  .cols { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px 20px; }\n  .col { gap: 4px; }\n  .col h3 { padding-bottom: 6px; }\n  .col a { min-height: 36px; display: flex; align-items: center; }\n  .col-contact { gap: 10px; }\n  .legal { gap: 10px; }\n  .addr { display: block; } .addr::before { content: none; }\n  .long { display: none; } .short { display: inline; }\n  .logo { gap: 10px; } .logo-bars span { width: 6px; height: 26px; }\n  .logo-name { font-size: 19px; } .logo-tag { font-size: 9px; }\n}\n`,\n\n  mounted() {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const cols = Array.isArray(p.columns) && p.columns.length ? p.columns : DEFAULT_COLUMNS;\n    const about = p.about || 'Os produtos que aparecem no canal, com a curadoria de quem testa de verdade.';\n    const company = p.company || '[RAZÃO SOCIAL] · CNPJ [00.000.000/0000-00]';\n    const address = p.address || '[ENDEREÇO COMPLETO]';\n    const home = p.homeHref || '#';\n    const ig = p.instagram === null ? null : (p.instagram || '#');\n    const yt = p.youtube === null ? null : (p.youtube || '#');\n\n    const colsHtml = cols.map((c, i) => {\n      const links = (c.links || []).map((l, k) => {\n        const text = l.short\n          ? `<span class=\"long\">${esc(l.label)}</span><span class=\"short\">${esc(l.short)}</span>`\n          : esc(l.label);\n        return c.plain\n          ? `<span data-key=\"c${i}l${k}\">${text}</span>`\n          : `<a data-key=\"c${i}l${k}\" href=\"${esc(l.href || '#')}\">${text}</a>`;\n      }).join('');\n      return `<div class=\"col${c.plain ? ' col-contact' : ''}\" data-key=\"c${i}\"><h3>${esc(c.title)}</h3>${links}</div>`;\n    }).join('');\n\n    return `\n<footer class=\"lf-footer\">\n  <div class=\"rule\" aria-hidden=\"true\"><span></span><i></i></div>\n  <div class=\"in\">\n    <div class=\"top\">\n      <div class=\"brand\">\n        <a class=\"logo\" href=\"${esc(home)}\" aria-label=\"Loja Lucas Fontana — início\">\n          <span class=\"logo-bars\" aria-hidden=\"true\"><span></span><span></span></span>\n          <span class=\"logo-words\" aria-hidden=\"true\"><span class=\"logo-name\">LUCAS FONTANA</span><span class=\"logo-tag\">Loja oficial</span></span>\n        </a>\n        <p class=\"about\">${esc(about)}</p>\n        <div class=\"social\">\n          ${ig !== null ? `<a href=\"${esc(ig)}\" target=\"_blank\" rel=\"noopener\" aria-label=\"Instagram do Lucas\">${ICON_IG}</a>` : ''}\n          ${yt !== null ? `<a href=\"${esc(yt)}\" target=\"_blank\" rel=\"noopener\" aria-label=\"YouTube do Lucas\">${ICON_YT}</a>` : ''}\n        </div>\n      </div>\n      <div class=\"cols\">${colsHtml}</div>\n    </div>\n    <div class=\"legal\">\n      <span>${esc(company)}<span class=\"addr\">${esc(address)}</span></span>\n      <span>Pagamento: <strong>Pix</strong> · <strong>Cartão de crédito</strong></span>\n    </div>\n  </div>\n</footer>`;\n  }\n};"}},"about":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"about"}}}},"address":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"address"}}}},"columns":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"columns"}}}},"company":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"company"}}}},"homeHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"homeHref"}}}},"instagram":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"instagram"}}}},"youtube":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"youtube"}}}}}}}}}},{"_id":"6ab5ba1fb58135ae6e6d7daa","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"AnnouncementBar","package":"babi-lf","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 DEFAULT_ITEMS = ['Pagamentos em PIX ou Cartão', 'Enviamos para todo o Brasil', 'Loja oficial do canal'];\n\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.lf-ab {\n  --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff;\n  container: lf / inline-size; width: 100%;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;\n  -webkit-font-smoothing: antialiased;\n}\n.in { height: 40px; display: flex; align-items: center; justify-content: center; gap: 28px; background: var(--ink); color: var(--white);\n  font-size: 12px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; white-space: nowrap; overflow: hidden; }\n.sep { width: 14px; height: 2px; background: var(--red-500); transform: skewX(-30deg); flex: none; }\n.edge { display: none; }\n@container lf (max-width: 1199px) { .in { gap: 20px; font-size: 11px; } .in > .x3 { display: none; } }\n@container lf (max-width: 767px) {\n  .in { height: 36px; gap: 10px; letter-spacing: .12em; }\n  .in > .item, .in > .sep { display: none; }\n  .in > .primary { display: inline; }\n  .in > .edge { display: block; width: 12px; }\n}\n`,\n\n  mounted() {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const items = Array.isArray(p.items) && p.items.length ? p.items : DEFAULT_ITEMS;\n    const n = Number(p.primary);\n    const primary = Number.isInteger(n) && n >= 0 && n < items.length ? n : Math.min(1, items.length - 1);\n    let out = '<span class=\"sep edge\" aria-hidden=\"true\"></span>';\n    items.forEach((t, i) => {\n      const third = i >= 2 ? ' x3' : '';\n      if (i) out += `<span class=\"sep${third}\" aria-hidden=\"true\"></span>`;\n      out += `<span class=\"item${third}${i === primary ? ' primary' : ''}\" data-key=\"i${i}\">${esc(t)}</span>`;\n    });\n    out += '<span class=\"sep edge\" aria-hidden=\"true\"></span>';\n    return `<div class=\"lf-ab\" role=\"region\" aria-label=\"Avisos da loja\"><div class=\"in\">${out}</div></div>`;\n  }\n};"}},"items":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"items"}}}},"primary":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"primary"}}}}}}}}}},{"_id":"6ab5be22d41d6b6b0d5630b6","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Select","package":"babi-lf","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 DEFAULT_OPTIONS = [\n  { value: 'relevancia', label: 'Relevância' },\n  { value: 'menor-preco', label: 'Menor preço' },\n  { value: 'maior-preco', label: 'Maior preço' },\n  { value: 'mais-vendidos', label: 'Mais vendidos' }\n];\n\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n\nconst CHEVRON = '<svg class=\"ic\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M6 9l6 6 6-6\"/></svg>';\n\nconst TABLET = (p) => `\n${p} .box { height: 48px; }\n${p} .label .long { display: none; }\n${p} .label .short { display: inline; }`;\nconst MOBILE = (p) => `\n${p} { display: flex; width: 100%; }\n${p} .label { display: none; }\n${p} .prefix { display: inline; font-weight: 500; }\n${p} .box { flex: 1; min-width: 0; padding: 0 8px; font-size: 13px; gap: 4px; }\n${p} .box .ic { width: 14px; height: 14px; }`;\n\nconst norm = (list) => (Array.isArray(list) && list.length ? list : DEFAULT_OPTIONS).map((o) =>\n  o && typeof o === 'object' ? { value: String(o.value != null ? o.value : o.label), label: String(o.label != null ? o.label : o.value) } : { value: String(o), label: String(o) });\n\nexport default {\n  css: `\n:host { display: block; }\n* { box-sizing: border-box; }\n.lf-select {\n  --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-500: #6b6e73; --line-strong: #d9d9d6;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;\n  -webkit-font-smoothing: antialiased;\n  position: relative; display: inline-flex; align-items: center; gap: 12px; min-width: 0; max-width: 100%;\n}\n.label { font-size: 14px; color: var(--grey-500); white-space: nowrap; }\n.short { display: none; }\n.box { position: relative; display: flex; align-items: center; justify-content: space-between; gap: 12px; height: 44px; min-width: 160px;\n  padding: 0 12px 0 16px; border: 1px solid var(--line-strong); border-radius: 2px; background: var(--white);\n  font-size: 15px; font-weight: 700; color: var(--ink); white-space: nowrap; }\n.box > .cur { min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n.box .ic { width: 16px; height: 16px; flex: none; }\n.box select { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; font-size: 16px; margin: 0; border: 0; }\n.box:focus-within { border-color: var(--ink); outline: 2px solid var(--red-500); outline-offset: 2px; }\n.prefix { display: none; }\n${TABLET('.v-tablet')}\n${TABLET('.v-mobile')}\n${MOBILE('.v-mobile')}\n@media (max-width: 1199px) { ${TABLET('.v-auto')} }\n@media (max-width: 767px) { ${MOBILE('.v-auto')} }\n`,\n\n  mounted(d2) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    d2.on('select', 'change', (e, el) => {\n      d2.state.value = el.value;\n      try { d2.emit('onChange', el.value); } catch (err) { /* nenhum handler ligado */ }\n    });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const opts = norm(p.options);\n    const label = p.label || 'Ordenar por';\n    const shortLabel = p.shortLabel || 'Ordenar';\n    const layout = ['desktop', 'tablet', 'mobile'].indexOf(p.layout) >= 0 ? p.layout : 'auto';\n    const want = d2.state.value != null ? d2.state.value : (p.value != null && p.value !== '' ? String(p.value) : opts[0].value);\n    const cur = opts.filter((o) => o.value === String(want))[0] || opts[0];\n\n    const options = opts.map((o, i) =>\n      `<option data-key=\"o${i}\" value=\"${esc(o.value)}\"${o.value === cur.value ? ' selected' : ''}>${esc(o.label)}</option>`).join('');\n\n    return `\n<div class=\"lf-select v-${layout}\">\n  <span class=\"label\" aria-hidden=\"true\"><span class=\"long\">${esc(label)}</span><span class=\"short\">${esc(shortLabel)}</span></span>\n  <span class=\"box\">\n    <span class=\"cur\"><span class=\"prefix\">${esc(shortLabel)}: </span>${esc(cur.label)}</span>\n    ${CHEVRON}\n    <select aria-label=\"${esc(label)}\">${options}</select>\n  </span>\n</div>`;\n  }\n};"}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChange"}}}},"options":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"options"}}}},"shortLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"shortLabel"}}}},"value":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"value"}}}}}}}}}},{"_id":"6ab5c0802086c2e434179cac","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Button","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Button — Loja Lucas Fontana\n// Um único componente para todos os botões da loja, controlado por parâmetros.\n// `glyph` põe um ícone à esquerda do texto (\"Assistir no YouTube\" com o ícone do YouTube).\n// `ghost` é o contorno branco para fundos escuros (SupportCard, cards escuros): transparente, inverte no hover.\nconst VARIANTS = ['primary', 'brand', 'light', 'outline', 'ghost'];\nconst SIZES = ['sm', 'md', 'lg', 'hero', 'inset'];\nconst WIDTHS = ['auto', 'mobile', 'always'];\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\n\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst pick = (v, list, fb) => (list.indexOf(String(v)) >= 0 ? String(v) : fb);\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\n\nconst ARROW = '<svg class=\"ic\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M5 12h14M13 6l6 6-6 6\"/></svg>';\n\n// Ícones à esquerda: mesmos desenhos do componente Icon (grade de 24px, traço 1.6)\nconst GLYPHS = {\n  youtube: '<rect x=\"2.5\" y=\"5\" width=\"19\" height=\"14\" rx=\"4\"/><path d=\"m10 9 5 3-5 3V9Z\"/>',\n  instagram: '<rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"5\"/><circle cx=\"12\" cy=\"12\" r=\"4\"/><circle cx=\"17.5\" cy=\"6.5\" r=\"0.8\" fill=\"currentColor\"/>',\n  play: '<path d=\"M8 5.5v13l10-6.5-10-6.5Z\" fill=\"currentColor\" stroke=\"none\"/>',\n  message: '<path d=\"M4 5h16v11H9l-5 4V5Z\"/>',\n  briefcase: '<rect x=\"3\" y=\"7\" width=\"18\" height=\"13\" rx=\"1\"/><path d=\"M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2\"/><path d=\"M3 13h18\"/>',\n  bag: '<path d=\"M5 8h14l-1.2 12.2a1 1 0 0 1-1 .8H7.2a1 1 0 0 1-1-.8L5 8Z\"/><path d=\"M9 8V6a3 3 0 0 1 6 0v2\"/>',\n  user: '<circle cx=\"12\" cy=\"8\" r=\"4\"/><path d=\"M4 21c1.5-4 4.5-6 8-6s6.5 2 8 6\"/>',\n  truck: '<path d=\"M3 6h11v10H3zM14 9h4l3 3v4h-7\"/><circle cx=\"7\" cy=\"17.5\" r=\"1.8\"/><circle cx=\"17\" cy=\"17.5\" r=\"1.8\"/>'\n};\nconst glyphSvg = (n) => (n && GLYPHS[n]\n  ? `<svg class=\"ic g\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">${GLYPHS[n]}</svg>`\n  : '');\n\n// Regras de tablet (<1200) e mobile (<768), aplicadas pela variante fixa ou pela largura da tela (auto)\nconst TABLET = (p) => `\n${p} .btn.s-hero { height: 52px; padding: 0 28px; font-size: 13px; gap: 12px; }\n${p} .btn.s-hero .ic { width: 16px; height: 16px; }\n${p} .btn.s-inset { height: 36px; padding: 0 14px; font-size: 12px; letter-spacing: .08em; }`;\nconst MOBILE = (p) => `\n${p} .btn.w-mobile { display: flex; width: 100%; padding: 0 20px; }\n${p} .long { display: none; }\n${p} .short { display: inline; }`;\n\nexport default {\n  css: `\n:host { display: block; }\n* { box-sizing: border-box; }\n.wrap { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --graphite-800: #2a2b2e; --grey-100: #ececea;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  display: block; width: 100%; }\n.btn { display: inline-flex; align-items: center; justify-content: center; gap: 12px; height: 48px; padding: 0 24px;\n  border: 1.5px solid transparent; border-radius: 2px; font-family: inherit; font-size: 13px; font-weight: 700;\n  letter-spacing: .1em; line-height: 1; text-transform: uppercase; text-decoration: none; cursor: pointer; white-space: nowrap;\n  transition: background-color .15s ease, color .15s ease, border-color .15s ease; margin: 0; }\n.btn:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.btn .ic { width: 16px; height: 16px; flex: none; }\n.btn .ic.g { width: 18px; height: 18px; margin-right: -2px; }\n.short { display: none; }\n\n.s-sm { height: 44px; padding: 0 18px; }\n.s-lg { height: 52px; padding: 0 28px; }\n.s-hero { height: 56px; padding: 0 32px; font-size: 14px; gap: 14px; }\n.s-hero .ic { width: 18px; height: 18px; }\n.s-inset { height: 40px; padding: 0 20px; border: 0; }\n\n.w-always { display: flex; width: 100%; }\n\n.v-primary { background: var(--ink); color: var(--white); }\n.v-primary:hover { background: var(--graphite-800); color: var(--white); }\n.v-brand { background: var(--red-500); color: var(--white); }\n.v-brand:hover { background: var(--ink); color: var(--white); }\n.v-light { background: var(--white); color: var(--ink); }\n.v-light:hover { background: var(--grey-100); color: var(--ink); }\n.v-outline { background: var(--white); color: var(--ink); border-color: var(--ink); }\n.v-outline:hover { background: var(--ink); color: var(--white); }\n.v-ghost { background: transparent; color: var(--white); border-color: var(--white); }\n.v-ghost:hover { background: var(--white); color: var(--ink); }\n.v-ghost:focus-visible { outline-color: var(--white); }\n.btn.is-disabled { opacity: .4; cursor: not-allowed; pointer-events: none; }\n\n${TABLET('.l-tablet')}\n${TABLET('.l-mobile')}\n${MOBILE('.l-mobile')}\n@media (max-width: 1199px) { ${TABLET('.l-auto')} }\n@media (max-width: 767px) { ${MOBILE('.l-auto')} }\n`,\n\n  mounted(d2) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    d2.on('.btn', 'click', (e, el) => {\n      if (el.classList.contains('is-disabled')) { e.preventDefault(); return; }\n      if (el.tagName === 'BUTTON') {\n        try { d2.emit('onClick'); } catch (err) { /* nenhum handler ligado */ }\n      }\n    });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const label = p.label || 'Botão';\n    const variant = pick(p.variant, VARIANTS, 'primary');\n    const size = pick(p.size, SIZES, 'md');\n    const width = pick(p.fullWidth, WIDTHS, 'auto');\n    const layout = pick(p.layout, LAYOUTS, 'auto');\n    const disabled = truthy(p.isDisabled);\n    const arrow = truthy(p.arrow);\n    const href = p.href ? String(p.href) : '';\n\n    const text = p.shortLabel\n      ? `<span class=\"long\">${esc(label)}</span><span class=\"short\">${esc(p.shortLabel)}</span>`\n      : `<span>${esc(label)}</span>`;\n    const cls = `btn v-${variant} s-${size} w-${width}${disabled ? ' is-disabled' : ''}`;\n    const inner = `${glyphSvg(p.glyph)}${text}${arrow ? ARROW : ''}`;\n\n    const el = href\n      ? `<a class=\"${cls}\" href=\"${esc(href)}\"${truthy(p.newTab) ? ' target=\"_blank\" rel=\"noopener\"' : ''}${disabled ? ' aria-disabled=\"true\" tabindex=\"-1\"' : ''}>${inner}</a>`\n      : `<button type=\"button\" class=\"${cls}\"${disabled ? ' disabled' : ''}>${inner}</button>`;\n\n    return `<div class=\"wrap l-${layout}\">${el}</div>`;\n  }\n};"}},"arrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"arrow"}}}},"fullWidth":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"fullWidth"}}}},"glyph":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"glyph"}}}},"href":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"href"}}}},"isDisabled":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"isDisabled"}}}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"newTab":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"newTab"}}}},"onClick":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onClick"}}}},"shortLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"shortLabel"}}}},"size":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"size"}}}},"variant":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"variant"}}}}}}}}}},{"_id":"6ab5c22eb58135ae6e6d8a73","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Doc","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Documentação — Loja Lucas Fontana\n// Renderiza um texto em formato markdown simples (títulos, listas, tabelas, código) no visual da loja.\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n\nconst inline = (s) => esc(s)\n  .replace(/`([^`]+)`/g, '<code>$1</code>')\n  .replace(/\\*\\*([^*]+)\\*\\*/g, '<b>$1</b>');\n\nfunction md(src) {\n  const lines = String(src || '').replace(/\\r/g, '').split('\\n');\n  let html = '', i = 0;\n  while (i < lines.length) {\n    const l = lines[i];\n    if (!l.trim()) { i++; continue; }\n    if (l.startsWith('```')) {\n      const buf = []; i++;\n      while (i < lines.length && !lines[i].startsWith('```')) { buf.push(lines[i]); i++; }\n      i++;\n      html += `<pre>${esc(buf.join('\\n'))}</pre>`;\n      continue;\n    }\n    if (l.startsWith('### ')) { html += `<h4>${inline(l.slice(4))}</h4>`; i++; continue; }\n    if (l.startsWith('## ')) { html += `<h3>${inline(l.slice(3))}</h3>`; i++; continue; }\n    if (l.startsWith('> ')) {\n      const buf = [];\n      while (i < lines.length && lines[i].startsWith('> ')) { buf.push(inline(lines[i].slice(2))); i++; }\n      html += `<div class=\"note\">${buf.join('<br>')}</div>`;\n      continue;\n    }\n    if (l.trim().startsWith('|')) {\n      const rows = [];\n      while (i < lines.length && lines[i].trim().startsWith('|')) { rows.push(lines[i].trim()); i++; }\n      const cells = (r) => r.replace(/^\\||\\|$/g, '').split('|').map((c) => c.trim());\n      const body = rows.filter((r, k) => !(k === 1 && /^\\|?[\\s:-]+\\|/.test(r)));\n      const [head, ...rest] = body;\n      html += '<div class=\"tw\"><table><thead><tr>' + cells(head).map((c) => `<th>${inline(c)}</th>`).join('') + '</tr></thead><tbody>' +\n        rest.map((r) => '<tr>' + cells(r).map((c) => `<td>${inline(c)}</td>`).join('') + '</tr>').join('') + '</tbody></table></div>';\n      continue;\n    }\n    if (l.startsWith('- ')) {\n      const buf = [];\n      while (i < lines.length && lines[i].startsWith('- ')) { buf.push(`<li>${inline(lines[i].slice(2))}</li>`); i++; }\n      html += `<ul>${buf.join('')}</ul>`;\n      continue;\n    }\n    const buf = [];\n    while (i < lines.length && lines[i].trim() && !/^(#|- |\\||> |```)/.test(lines[i])) { buf.push(inline(lines[i])); i++; }\n    html += `<p>${buf.join(' ')}</p>`;\n  }\n  return html;\n}\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.doc { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-50: #f5f5f3; --grey-100: #ececea; --grey-500: #6b6e73; --grey-700: #45474b; --line: #e4e4e2;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  background: var(--white); color: var(--ink); width: 100%; min-height: 100%; }\n.rule { height: 6px; background: var(--red-500); }\n.in { padding: 48px 56px 64px; max-width: 1040px; }\n.eyebrow { margin: 0 0 12px; font-size: 12px; font-weight: 700; letter-spacing: .3em; text-transform: uppercase; color: var(--grey-500); }\n.eyebrow b { color: var(--red-500); }\nh1 { margin: 0 0 12px; font-size: 44px; font-weight: 800; font-stretch: 115%; line-height: 1; text-transform: uppercase; letter-spacing: -.01em; }\n.type { display: inline-block; margin: 0 0 28px; padding: 6px 10px; background: var(--ink); color: var(--white); font: 700 13px/1 ui-monospace, SFMono-Regular, Menlo, monospace; }\nh3 { margin: 40px 0 14px; padding-top: 24px; border-top: 1px solid var(--line); font-size: 13px; font-weight: 800; letter-spacing: .24em; text-transform: uppercase; }\nh4 { margin: 24px 0 10px; font-size: 16px; font-weight: 700; }\np { margin: 0 0 14px; font-size: 16px; line-height: 1.6; color: var(--grey-700); }\np b, li b, td b { color: var(--ink); }\nul { margin: 0 0 16px; padding-left: 20px; }\nli { margin: 0 0 8px; font-size: 15px; line-height: 1.55; color: var(--grey-700); }\nli::marker { color: var(--red-500); }\ncode { font: 600 13px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace; background: var(--grey-100); color: var(--ink); padding: 2px 6px; border-radius: 2px; }\npre { margin: 0 0 16px; padding: 16px 18px; background: var(--ink); color: #e9e9e7; font: 13px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace; white-space: pre-wrap; overflow-x: auto; }\n.tw { overflow-x: auto; margin: 0 0 16px; }\ntable { width: 100%; border-collapse: collapse; font-size: 14px; }\nth { text-align: left; padding: 0 12px 10px 0; border-bottom: 2px solid var(--ink); font-size: 11px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; white-space: nowrap; }\ntd { padding: 12px 12px 12px 0; border-bottom: 1px solid var(--line); vertical-align: top; line-height: 1.5; color: var(--grey-700); }\ntd:first-child { white-space: nowrap; }\n.note { margin: 0 0 16px; padding: 14px 16px; border-left: 4px solid var(--red-500); background: var(--grey-50); font-size: 14px; line-height: 1.55; color: var(--grey-700); }\n`,\n\n  mounted() {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    return `<div class=\"doc\"><div class=\"rule\"></div><div class=\"in\">\n      <p class=\"eyebrow\"><b>Doc</b> — Componentes UI</p>\n      <h1>${esc(p.heading || 'Componente')}</h1>\n      ${p.typeId ? `<span class=\"type\">${esc(p.typeId)}</span>` : ''}\n      ${md(p.content)}\n    </div></div>`;\n  }\n};"}},"content":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"content"}}}},"heading":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"heading"}}}},"typeId":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"typeId"}}}}}}}}}},{"_id":"6ab5c4bfa44198fd3fbf3e1b","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Logo","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Logo — Loja Lucas Fontana\n// Wordmark em texto vivo: duas barras inclinadas, \"LUCAS FONTANA\" e \"LOJA OFICIAL\".\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\n\nconst TABLET = (p) => `\n${p} .logo { gap: 10px; }\n${p} .bars { gap: 3px; }\n${p} .bars span { width: 6px; height: 26px; }\n${p} .name { font-size: 20px; }\n${p} .tag { font-size: 9px; }\n${p} .dark .bars span { height: 28px; }\n${p} .dark .name { font-size: 20px; }`;\nconst MOBILE = (p) => `\n${p} .logo { gap: 8px; }\n${p} .bars span { width: 5px; height: 22px; }\n${p} .words { gap: 2px; }\n${p} .name { font-size: 17px; }\n${p} .tag { font-size: 8px; }\n${p} .dark { gap: 10px; }\n${p} .dark .bars span { width: 6px; height: 26px; }\n${p} .dark .name { font-size: 19px; }\n${p} .dark .tag { font-size: 9px; }`;\n\nexport default {\n  css: `\n:host { display: block; }\n* { box-sizing: border-box; }\n.wrap { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-500: #6b6e73; --grey-300: #a7a9ad;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  display: flex; align-items: center; height: 100%; padding: 0 8px; }\n.logo { display: inline-flex; align-items: center; gap: 12px; color: var(--ink); text-decoration: none; flex-shrink: 0; }\n.logo:focus-visible { outline: 2px solid var(--red-500); outline-offset: 4px; }\n.bars { display: flex; gap: 4px; }\n.bars span { display: block; width: 7px; height: 30px; transform: skewX(-18deg); background: var(--red-500); }\n.bars span + span { background: var(--ink); }\n.words { display: flex; flex-direction: column; gap: 3px; }\n.name { font-size: 24px; font-weight: 800; font-stretch: 125%; font-style: italic; letter-spacing: .02em; line-height: 1; white-space: nowrap; }\n.tag { font-size: 10px; font-weight: 600; letter-spacing: .44em; color: var(--grey-500); line-height: 1; text-transform: uppercase; white-space: nowrap; }\n.dark { color: var(--white); }\n.dark .bars span + span { background: var(--white); }\n.dark .tag { color: var(--grey-300); }\n.dark .name { font-size: 22px; }\n${TABLET('.l-tablet')}\n${TABLET('.l-mobile')}\n${MOBILE('.l-mobile')}\n@media (max-width: 1199px) { ${TABLET('.l-auto')} }\n@media (max-width: 767px) { ${MOBILE('.l-auto')} }\n`,\n\n  mounted() {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const tone = p.tone === 'dark' ? 'dark' : 'light';\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'auto';\n    const inner = `<span class=\"bars\" aria-hidden=\"true\"><span></span><span></span></span>` +\n      `<span class=\"words\" aria-hidden=\"true\"><span class=\"name\">LUCAS FONTANA</span><span class=\"tag\">Loja oficial</span></span>`;\n    const cls = `logo${tone === 'dark' ? ' dark' : ''}`;\n    const el = truthy(p.noLink)\n      ? `<span class=\"${cls}\" role=\"img\" aria-label=\"Loja Lucas Fontana\">${inner}</span>`\n      : `<a class=\"${cls}\" href=\"${esc(p.href || '/')}\" aria-label=\"Loja Lucas Fontana — início\">${inner}</a>`;\n    return `<div class=\"wrap l-${layout}\">${el}</div>`;\n  }\n};"}},"href":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"href"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"noLink":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"noLink"}}}},"tone":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"tone"}}}}}}}}}},{"_id":"6ab66f325f5a9fd2e7a7bd0c","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Badge","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Badge — Loja Lucas Fontana\n// Selos quadrados em maiúsculas: status, parceria e tópicos.\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst TONES = ['ink', 'red', 'outline'];\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\n\nconst TABLET = (p) => `\n${p} .badge.outline { font-size: 10px; padding: 5px 8px; }`;\nconst MOBILE = (p) => `\n${p} .badge { font-size: 9px; padding: 4px 6px; letter-spacing: .1em; }\n${p} .badge.status { padding: 4px 7px; letter-spacing: .08em; }\n${p} .badge.outline { font-size: 10px; padding: 5px 8px; }\n${p} .long { display: none; }\n${p} .short { display: inline; }`;\n\nexport default {\n  css: `\n:host { display: block; }\n* { box-sizing: border-box; }\n.wrap { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-700: #45474b;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  display: flex; align-items: center; height: 100%; }\n.badge { display: inline-flex; align-items: center; font-size: 10px; font-weight: 800; letter-spacing: .12em; line-height: 1.2;\n  text-transform: uppercase; padding: 5px 8px; color: var(--white); background: var(--ink); white-space: nowrap; }\n.badge.red { background: var(--red-500); }\n.badge.outline { background: transparent; border: 1px solid var(--grey-700); font-weight: 700; font-size: 11px; padding: 5px 9px; }\n.badge.status { font-size: 11px; padding: 6px 10px; letter-spacing: .1em; }\n.short { display: none; }\n${TABLET('.l-tablet')}\n${TABLET('.l-mobile')}\n${MOBILE('.l-mobile')}\n@media (max-width: 1199px) { ${TABLET('.l-auto')} }\n@media (max-width: 767px) { ${MOBILE('.l-auto')} }\n`,\n\n  mounted() {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const label = p.label || 'Badge';\n    const tone = TONES.indexOf(p.tone) >= 0 ? p.tone : 'ink';\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'auto';\n    const cls = `badge${tone !== 'ink' ? ' ' + tone : ''}${truthy(p.isStatus) ? ' status' : ''}`;\n    const text = p.shortLabel\n      ? `<span class=\"long\">${esc(label)}</span><span class=\"short\">${esc(p.shortLabel)}</span>`\n      : esc(label);\n    return `<div class=\"wrap l-${layout}\"><span class=\"${cls}\">${text}</span></div>`;\n  }\n};"}},"isStatus":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"isStatus"}}}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"shortLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"shortLabel"}}}},"tone":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"tone"}}}}}}}}}},{"_id":"6ab6a330b39f683eb1b33564","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Icon","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Icon — Loja Lucas Fontana\n// Os 32 ícones de contorno do design system (grade de 24px, pontas arredondadas).\n// Um componente só: o parâmetro `name` escolhe o desenho. Use name = \"all\" para ver o catálogo.\nconst ICONS = {\n    search: [['circle', { cx: 11, cy: 11, r: 7 }], ['path', { d: 'm20 20-3.5-3.5' }]],\n    user: [['circle', { cx: 12, cy: 8, r: 4 }], ['path', { d: 'M4 21c1.5-4 4.5-6 8-6s6.5 2 8 6' }]],\n    bag: [['path', { d: 'M5 8h14l-1.2 12.2a1 1 0 0 1-1 .8H7.2a1 1 0 0 1-1-.8L5 8Z' }], ['path', { d: 'M9 8V6a3 3 0 0 1 6 0v2' }]],\n    menu: [['path', { d: 'M4 7h16M4 12h16M4 17h10' }]],\n    'arrow-right': [['path', { d: 'M5 12h14M13 6l6 6-6 6' }]],\n    'chevron-left': [['path', { d: 'M15 5l-7 7 7 7' }]],\n    'chevron-right': [['path', { d: 'M9 5l7 7-7 7' }]],\n    image: [['rect', { x: 3, y: 5, width: 18, height: 14, rx: 1 }], ['circle', { cx: 9, cy: 10, r: 2 }], ['path', { d: 'm21 16-5-5-9 8' }]],\n    message: [['path', { d: 'M4 5h16v11H9l-5 4V5Z' }]],\n    briefcase: [['rect', { x: 3, y: 7, width: 18, height: 13, rx: 1 }], ['path', { d: 'M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2' }], ['path', { d: 'M3 13h18' }]],\n    instagram: [['rect', { x: 3, y: 3, width: 18, height: 18, rx: 5 }], ['circle', { cx: 12, cy: 12, r: 4 }], ['circle', { cx: 17.5, cy: 6.5, r: 0.8, fill: 'currentColor' }]],\n    youtube: [['rect', { x: 2.5, y: 5, width: 19, height: 14, rx: 4 }], ['path', { d: 'm10 9 5 3-5 3V9Z' }]],\n    filter: [['path', { d: 'M4 8h9M17 8h3M4 16h3M11 16h9' }], ['circle', { cx: 15, cy: 8, r: 2 }], ['circle', { cx: 9, cy: 16, r: 2 }]],\n    close: [['path', { d: 'M6 6l12 12M18 6 6 18' }]],\n    check: [['path', { d: 'm5 12.5 4.5 4.5L19 7.5' }]],\n    'chevron-down': [['path', { d: 'M6 9l6 6 6-6' }]],\n    'search-x': [['circle', { cx: 11, cy: 11, r: 7 }], ['path', { d: 'm20 20-3.5-3.5M8.5 8.5l5 5M13.5 8.5l-5 5' }]],\n    truck: [['path', { d: 'M3 6h11v10H3zM14 9h4l3 3v4h-7' }], ['circle', { cx: 7, cy: 17.5, r: 1.8 }], ['circle', { cx: 17, cy: 17.5, r: 1.8 }]],\n    card: [['rect', { x: 3, y: 5.5, width: 18, height: 13, rx: 1 }], ['path', { d: 'M3 10h18M7 15h4' }]],\n    swap: [['path', { d: 'M4 8h14l-3-3M20 16H6l3 3' }]],\n    play: [['path', { d: 'M8 5.5v13l10-6.5-10-6.5Z', fill: 'currentColor', stroke: 'none' }]],\n    plus: [['path', { d: 'M12 5v14M5 12h14' }]],\n    minus: [['path', { d: 'M5 12h14' }]],\n    pin: [['path', { d: 'M12 21s-7-6.2-7-11.5A7 7 0 0 1 19 9.5C19 14.8 12 21 12 21Z' }], ['circle', { cx: 12, cy: 9.5, r: 2.5 }]],\n    logout: [['path', { d: 'M10 4H5v16h5M14 8l4 4-4 4M18 12H9' }]],\n    lock: [['rect', { x: 5, y: 10.5, width: 14, height: 10, rx: 1 }], ['path', { d: 'M8.5 10.5V7.5a3.5 3.5 0 0 1 7 0v3' }]],\n    eye: [['path', { d: 'M2.5 12S6 5.5 12 5.5 21.5 12 21.5 12 18 18.5 12 18.5 2.5 12 2.5 12Z' }], ['circle', { cx: 12, cy: 12, r: 3 }]],\n    'eye-off': [['path', { d: 'M4 4l16 16M10.6 5.6c.5-.1.9-.1 1.4-.1 6 0 9.5 6.5 9.5 6.5a17 17 0 0 1-3 3.6M6.5 7.4A16 16 0 0 0 2.5 12S6 18.5 12 18.5c1.6 0 3-.4 4.2-1M9.9 9.9a3 3 0 0 0 4.2 4.2' }]],\n    copy: [['rect', { x: 8.5, y: 8.5, width: 11, height: 11, rx: 1 }], ['path', { d: 'M15.5 8.5v-3a1 1 0 0 0-1-1h-9a1 1 0 0 0-1 1v9a1 1 0 0 0 1 1h3' }]],\n    'arrow-left': [['path', { d: 'M19 12H5M11 6l-6 6 6 6' }]],\n    mail: [['rect', { x: 3, y: 5.5, width: 18, height: 13, rx: 1 }], ['path', { d: 'm3.5 6.5 8.5 7 8.5-7' }]],\n    trash: [['path', { d: 'M4 7h16M9 7V4.5h6V7M6.5 7l.9 12.6a1 1 0 0 0 1 .9h7.2a1 1 0 0 0 1-.9L17.5 7M10 11v6M14 11v6' }]]\n  };\nconst BOLD = { 'arrow-right': 1, 'chevron-left': 1, 'chevron-right': 1, 'chevron-down': 1, close: 1, check: 1, plus: 1, minus: 1, 'arrow-left': 1 };\nconst MEDIUM = { menu: 1, search: 1, 'search-x': 1, filter: 1 };\n\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n\nfunction svg(name, size, stroke) {\n  const parts = ICONS[name] || [];\n  const sw = stroke || (BOLD[name] ? 2 : MEDIUM[name] ? 1.8 : 1.6);\n  const inner = parts.map(([tag, attrs]) =>\n    `<${tag} ${Object.keys(attrs).map((k) => `${k}=\"${esc(attrs[k])}\"`).join(' ')}/>`).join('');\n  return `<svg class=\"ic\" width=\"${size}\" height=\"${size}\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"${sw}\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">${inner}</svg>`;\n}\n\nexport default {\n  css: `\n:host { display: block; }\n* { box-sizing: border-box; }\n.wrap { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; }\n.ic { display: block; flex: none; }\n.all { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 0; background: #ffffff; border-top: 1px solid #e4e4e2; border-left: 1px solid #e4e4e2;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; width: 100%; }\n.cell { background: #ffffff; border-right: 1px solid #e4e4e2; border-bottom: 1px solid #e4e4e2; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 22px 8px 16px; }\n.cell code { font: 600 12px/1.2 ui-monospace, SFMono-Regular, Menlo, monospace; color: #45474b; }\n`,\n\n  render(d2) {\n    const p = d2.params || {};\n    const color = p.iconColor || '#0b0b0c';\n    const size = Number(p.size) > 0 ? Number(p.size) : 24;\n    const stroke = Number(p.strokeWidth) > 0 ? Number(p.strokeWidth) : 0;\n    if (p.name === 'all') {\n      const cells = Object.keys(ICONS).map((n) =>\n        `<div class=\"cell\" data-key=\"${esc(n)}\">${svg(n, size, stroke)}<code>${esc(n)}</code></div>`).join('');\n      return `<div class=\"all\" style=\"color:${esc(color)}\">${cells}</div>`;\n    }\n    const name = ICONS[p.name] ? p.name : 'bag';\n    return `<div class=\"wrap\" style=\"color:${esc(color)}\">${svg(name, size, stroke)}</div>`;\n  }\n};"}},"iconColor":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconColor"}}}},"name":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"name"}}}},"size":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"size"}}}},"strokeWidth":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"strokeWidth"}}}}}}}}}},{"_id":"6ab6a8e0356aa1fc96e964ea","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"SearchBar","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// SearchBar — Loja Lucas Fontana\n// Campo de busca cinza com ícone de lupa e botão \"Buscar\" embutido à direita.\n// Reaproveita os componentes Button e Icon da loja pelos parâmetros `button` e `searchIcon`.\n// `size: \"lg\"` é a busca grande das páginas (FAQ): 56px (52px no tablet/mobile), fundo branco, borda ink de 1,5px, texto 16px.\n// `showButton: false` tira o botão \"Buscar\" (no PageHeader do FAQ a busca filtra enquanto a pessoa digita).\n// `busTopic` avisa outros componentes da página a cada letra digitada (o FaqLayout escuta \"faq:search\").\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\n\n// O parâmetro de componente chega como o componente vivo; o d2.render usa a referência dele.\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\n\nconst COMPACT = (p) => `\n${p} .field { height: 44px; padding: 0 4px 0 14px; gap: 10px; }\n${p} input { height: 40px; }\n${p}.lg .field { height: 52px; padding: 0 4px 0 14px; }\n${p}.lg.nobtn .field { padding-right: 14px; }\n${p}.lg input { height: 48px; }`;\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.sb { --ink: #0b0b0c; --white: #ffffff; --grey-50: #f5f5f3; --grey-500: #6b6e73; --line-strong: #d9d9d6;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  display: flex; align-items: center; width: 100%; height: 100%; }\n.field { display: flex; align-items: center; gap: 12px; width: 100%; height: 48px; padding: 0 4px 0 18px;\n  background: var(--grey-50); border: 1px solid var(--line-strong); border-radius: 2px; min-width: 0; margin: 0; }\n.field:focus-within { border-color: var(--ink); }\ninput { flex: 1; min-width: 0; height: 44px; border: 0; outline: none; background: transparent; margin: 0; padding: 0;\n  font: 400 15px/1.2 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; color: var(--ink); -webkit-appearance: none; appearance: none; }\ninput::placeholder { color: var(--grey-500); }\ninput::-webkit-search-cancel-button { -webkit-appearance: none; }\n.nobtn .field { padding-right: 18px; }\n\n/* Tamanho grande (busca das páginas) */\n.lg .field { height: 56px; background: var(--white); border: 1.5px solid var(--ink); padding: 0 4px 0 18px; }\n.lg.nobtn .field { padding-right: 14px; }\n.lg input { height: 52px; font-size: 16px; }\n${COMPACT('.l-tablet')}\n${COMPACT('.l-mobile')}\n@media (max-width: 1199px) { ${COMPACT('.l-auto')} }\n`,\n\n  mounted(d2, root) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    // Placeholder curto quando o campo fica estreito (menos de 420px), como no design system\n    if (typeof ResizeObserver !== 'undefined') {\n      const ro = new ResizeObserver((e) => {\n        const narrow = e[0].contentRect.width < 420;\n        if (d2.state.narrow !== narrow) d2.state.narrow = narrow;\n      });\n      ro.observe(root);\n      d2.onUnmount(() => ro.disconnect());\n    }\n    d2.on('form', 'submit', (e) => { e.preventDefault(); submit(d2); });\n    d2.on('input', 'keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); submit(d2); } });\n    // Enquanto digita: avisa quem estiver ouvindo (onInput e o tópico do bus), com uma pausa curta\n    let t = null;\n    d2.on('input', 'input', (e, el) => {\n      if (t) clearTimeout(t);\n      t = setTimeout(() => {\n        const q = String(el.value || '').trim();\n        try { d2.emit('onInput', q); } catch (err) { /* nenhum handler ligado */ }\n        const topic = (d2.params || {}).busTopic;\n        if (topic && d2.bus) d2.bus.emit(String(topic), q);\n      }, 150);\n    });\n    d2.onUnmount(() => { if (t) clearTimeout(t); });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'auto';\n    const lg = p.size === 'lg';\n    const withButton = p.showButton == null ? true : truthy(p.showButton);\n    const placeholder = d2.state.narrow\n      ? (p.shortPlaceholder || 'Buscar produto ou marca')\n      : (p.placeholder || 'Busque por produto, categoria ou marca');\n    const compact = layout === 'tablet' || layout === 'mobile';\n\n    const iconRef = refOf(d2.param('searchIcon'));\n    const buttonRef = withButton ? refOf(d2.param('button')) : '';\n    const icon = iconRef\n      ? d2.render(iconRef, { name: 'search', size: lg ? 20 : 18, iconColor: lg ? '#0b0b0c' : '#6b6e73' },\n          { key: 'ic', width: lg ? 20 : 18, height: lg ? 20 : 18, style: 'flex:none' })\n      : '';\n    const button = buttonRef\n      ? d2.render(buttonRef,\n          { label: p.buttonLabel || 'Buscar', variant: 'primary', size: 'inset', fullWidth: 'auto', layout: layout === 'auto' ? '' : layout },\n          { key: 'btn', width: 'auto', height: compact ? 36 : 40, style: 'flex:none', onClick: () => submit(d2) })\n      : '';\n\n    return `<div class=\"sb l-${layout}${lg ? ' lg' : ''}${buttonRef ? '' : ' nobtn'}\">\n      <form class=\"field\" role=\"search\" onsubmit=\"return false\">\n        ${icon}\n        <input type=\"search\" name=\"q\" aria-label=\"${esc(p.ariaLabel || 'Buscar produtos')}\" placeholder=\"${esc(placeholder)}\" autocomplete=\"off\">\n        ${button}\n      </form>\n    </div>`;\n  }\n};\n\nfunction submit(d2) {\n  const el = d2.$('input');\n  const q = el ? String(el.value || '').trim() : '';\n  try { d2.emit('onSearch', q); } catch (err) { /* nenhum handler ligado */ }\n  const topic = (d2.params || {}).busTopic;\n  if (topic && d2.bus) d2.bus.emit(String(topic), q);\n}"}},"ariaLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ariaLabel"}}}},"busTopic":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"busTopic"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"buttonLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"buttonLabel"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onInput":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onInput"}}}},"onSearch":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSearch"}}}},"placeholder":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"placeholder"}}}},"searchIcon":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"searchIcon"}}}},"shortPlaceholder":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"shortPlaceholder"}}}},"showButton":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"showButton"}}}},"size":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"size"}}}}}}}}}},{"_id":"6ab6bcb197b00074cbeff455","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Header","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Header — Loja Lucas Fontana\n// Cabeçalho da loja nas três telas. Não desenha logo, busca, botão nem ícones:\n// reaproveita Logo, SearchBar, Button e Icon pelos parâmetros `logo`, `searchBar`, `button` e `iconComponent`.\n// O número da sacola vem da sacola do navegador (`lf-sacola`) e atualiza sozinho; `cartCount` só vale sem acesso a ela.\n// Logado (`userName`): \"Olá, [Nome]\" no lugar de \"Entre ou cadastre-se\" e o \"Sair\" — no desktop, um link ao lado de\n// \"Minha conta\"; no tablet e no mobile, o ícone de pessoa abre uma barra curta abaixo do topo com \"Minha conta\" e \"Sair\".\n// \"Sair\" avisa `onLogout` (quem liga encerra a sessão e atualiza a página). Sem login, nada disso aparece.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst LISTA = '/lista-de-produtos/q';\nconst DEFAULT_CATS = [\n  { label: 'Performance', href: LISTA + '?categoria=performance' },\n  { label: 'Cuidado automotivo', href: LISTA + '?categoria=cuidado-automotivo' },\n  { label: 'Vestuário', href: LISTA + '?categoria=vestuario' },\n  { label: 'Acessórios', href: LISTA + '?categoria=acessorios' }\n];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst slug = (s) => String(s || '').toLowerCase().normalize('NFD').replace(/[̀-ͯ]/g, '').replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');\n\nlet LOADED = null; let LOADING = null;\nfunction cats(v) {\n  if (LOADED) return LOADED;\n  let list = v;\n  if (typeof list === 'string') list = list.split(',').map((s) => s.trim()).filter(Boolean);\n  if (!Array.isArray(list) || !list.length) return DEFAULT_CATS;\n  return list.map((c) => typeof c === 'string'\n    ? { label: c, href: LISTA + '?categoria=' + slug(c) }\n    : { label: c.label || c.name || '', href: c.href || LISTA + '?categoria=' + slug(c.label || c.name) });\n}\n\n// O parâmetro de componente chega como o componente vivo; o d2.render usa a referência dele.\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\n\nfunction detect(w) { return w >= 1200 ? 'desktop' : w >= 768 ? 'tablet' : 'mobile'; }\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.hd { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-500: #6b6e73; --line: #e4e4e2;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  background: var(--white); color: var(--ink); width: 100%; position: relative; }\n.out { display: inline-flex; align-items: center; gap: 6px; height: 44px; padding: 0 8px 0 14px; margin-left: 2px; border: 0; border-left: 1px solid var(--line);\n  background: transparent; color: var(--grey-500); font-family: inherit; font-size: 12px; font-weight: 700; line-height: 1; letter-spacing: .1em; text-transform: uppercase; cursor: pointer; }\n.out .slot { width: 18px; height: 18px; pointer-events: none; }\n.out:hover { color: var(--red-500); }\n.out:focus-visible, .umenu a:focus-visible, .umenu button:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.umenu { position: absolute; right: 8px; z-index: 5; display: flex; align-items: stretch; height: 44px; background: var(--white);\n  border: 1px solid var(--line); box-shadow: 0 6px 16px rgba(11, 11, 12, .12); }\n.umenu a, .umenu button { display: inline-flex; align-items: center; gap: 8px; padding: 0 16px; border: 0; background: transparent; color: var(--ink);\n  font-family: inherit; font-size: 12px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; text-decoration: none; white-space: nowrap; cursor: pointer; }\n.umenu button { border-left: 1px solid var(--line); }\n.umenu .slot { width: 18px; height: 18px; pointer-events: none; }\n.umenu a:hover, .umenu button:hover { color: var(--red-500); }\n.l-tablet .umenu { top: 72px; right: 40px; }\n.l-mobile .umenu { top: 64px; right: 8px; }\n.row { display: flex; align-items: center; gap: 32px; height: 88px; padding: 0 96px; }\n.logo { flex: none; height: 44px; width: 320px; margin-left: -8px; }\n.search { flex: 1; min-width: 0; height: 48px; max-width: 640px; margin: 0 auto; }\n.actions { display: flex; align-items: center; gap: 8px; flex: none; }\n.ibtn { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px;\n  background: transparent; border: 0; border-radius: 2px; padding: 0; margin: 0; color: var(--ink); cursor: pointer; text-decoration: none; }\n.ibtn:hover { color: var(--red-500); }\n.ibtn:focus-visible, .acct:focus-visible, .nav a:focus-visible, .all:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.ibtn .slot { width: 24px; height: 24px; pointer-events: none; }\n.count { position: absolute; top: 4px; right: 2px; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px;\n  background: var(--red-500); color: var(--white); font-size: 11px; font-weight: 700; line-height: 18px; text-align: center; pointer-events: none; }\n.acct { display: inline-flex; align-items: center; gap: 10px; height: 44px; padding: 0 8px; color: var(--ink); text-decoration: none; background: transparent; border: 0; cursor: pointer; font-family: inherit; }\n.acct .slot { width: 24px; height: 24px; flex: none; pointer-events: none; }\n.acct .txt { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; text-align: left; }\n.acct .hint { font-size: 12px; color: var(--grey-500); line-height: 1; white-space: nowrap; }\n.acct .lbl { font-size: 12px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; line-height: 1; white-space: nowrap; }\n.acct:hover .lbl { color: var(--red-500); }\n.navrow { display: flex; align-items: center; justify-content: space-between; gap: 24px; height: 48px; padding: 0 96px; border-top: 1px solid var(--line); box-shadow: inset 0 -1px 0 var(--line); }\n.nav { display: flex; align-items: center; gap: 32px; height: 100%; min-width: 0; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }\n.nav::-webkit-scrollbar { display: none; }\n.nav a { position: relative; display: inline-flex; align-items: center; height: 100%; flex: none; color: var(--ink); text-decoration: none;\n  font-size: 12px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; white-space: nowrap; }\n.nav a:hover { color: var(--red-500); }\n.nav a.on::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--red-500); }\n.all { display: inline-flex; align-items: center; gap: 8px; flex: none; min-height: 44px; color: var(--ink); text-decoration: none;\n  font-size: 12px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; white-space: nowrap; }\n.all span { border-bottom: 2px solid var(--red-500); padding-bottom: 3px; }\n.all:hover { color: var(--red-500); }\n.all .slot { width: 16px; height: 16px; pointer-events: none; }\n\n/* Tablet: linha de 72px, botão de menu, busca, ícones; nav rola */\n.l-tablet .row { height: 72px; padding: 0 40px; gap: 20px; }\n.l-tablet .row { gap: 12px; }\n.l-tablet .logo { width: 268px; height: 40px; margin-left: 0; }\n.l-tablet .search { height: 44px; max-width: none; }\n.l-tablet .actions { gap: 0; margin-right: -10px; }\n.l-tablet .row > .ibtn:first-child { margin-left: -10px; }\n.l-tablet .navrow { height: 44px; padding: 0 0 0 40px; }\n.l-tablet .nav { gap: 28px; padding-right: 40px; }\n\n/* Mobile: menu · logo central · ícones; busca em linha própria; nav rola */\n.l-mobile .row { display: grid; grid-template-columns: 44px 1fr 88px; height: 64px; padding: 0 8px; gap: 0; }\n.l-mobile .left { justify-self: start; }\n.l-mobile .logo { width: 240px; height: 36px; justify-self: center; margin-left: 0; }\n.l-mobile .actions { justify-self: end; gap: 0; }\n.l-mobile .srow { padding: 0 20px 12px; }\n.l-mobile .srow .search { height: 44px; max-width: none; }\n.l-mobile .navrow { height: 44px; padding: 0 0 0 20px; }\n.l-mobile .nav { gap: 24px; padding-right: 20px; }\n`,\n\n  mounted(d2, root) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    // Sem `layout` fixo, o header mede a própria largura (como a container query do design system)\n    if (typeof ResizeObserver !== 'undefined') {\n      const ro = new ResizeObserver((e) => {\n        const w = detect(e[0].contentRect.width);\n        if (d2.state.auto !== w) d2.state.auto = w;\n      });\n      ro.observe(root);\n      d2.onUnmount(() => ro.disconnect());\n    }\n    const fire = (name, payload) => { try { d2.emit(name, payload); } catch (err) { /* nenhum handler ligado */ } };\n    d2.on('[data-act=\"menu\"]', 'click', () => fire('onMenu'));\n    d2.on('[data-act=\"account\"]', 'click', () => { if (d2.state.um) d2.state.um = false; fire('onAccount'); });\n    d2.on('[data-act=\"umenu\"]', 'click', () => { d2.state.um = !d2.state.um; });\n    d2.on('[data-act=\"logout\"]', 'click', () => { d2.state.um = false; fire('onLogout'); });\n    d2.on('[data-act=\"cart\"]', 'click', () => fire('onCart'));\n    // Contagem real da sacola (localStorage `lf-sacola`), atualizada quando qualquer página mexe nela\n    const readCount = () => { try { const b = JSON.parse(localStorage.getItem('lf-sacola') || '[]'); return Array.isArray(b) ? b.reduce((s, x) => s + (Number(x && x.qty) || 0), 0) : 0; } catch (e) { return null; } };\n    const sync = () => { const n = readCount(); if (n != null && d2.state.bag !== n) d2.state.bag = n; };\n    sync();\n    const onBag = (e) => { const n = e && e.detail && e.detail.count != null ? Number(e.detail.count) : readCount(); if (n != null && d2.state.bag !== n) d2.state.bag = n; };\n    const onStorage = (e) => { if (!e || e.key === 'lf-sacola') sync(); };\n    window.addEventListener('lf-sacola', onBag); window.addEventListener('storage', onStorage);\n    d2.onUnmount(() => { window.removeEventListener('lf-sacola', onBag); window.removeEventListener('storage', onStorage); });\n    d2.on('.nav a', 'click', (e, el) => fire('onCategory', el.dataset.slug));\n    // Menu vem da tabela Categorias (ativas com destaque no menu); se a busca falhar, vale o parâmetro/padrão\n    if (!LOADED) {\n      if (!LOADING) {\n        LOADING = d2.rush('categoriasLoja').invoke({}).then((res) => {\n          const rows = (res && res.data !== undefined ? res.data : res) || [];\n          LOADED = rows.filter((c) => c && c.ativa !== false && Number(c.posicao_menu) > 0).sort((a, b) => Number(a.posicao_menu) - Number(b.posicao_menu)).map((c) => ({ label: c.nome, href: LISTA + '?categoria=' + c.slug }));\n        }).catch(() => { LOADING = null; });\n      }\n      const pr = LOADING;\n      if (pr) pr.then(() => { d2.state.catsTick = Date.now(); });\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    void d2.state.catsTick;\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : (d2.state.auto || 'desktop');\n    const desk = layout === 'desktop';\n    const mob = layout === 'mobile';\n\n    const iconMod = refOf(d2.param('iconComponent'));\n    const logoMod = refOf(d2.param('logo'));\n    const searchMod = refOf(d2.param('searchBar'));\n    const buttonMod = refOf(d2.param('button'));\n\n    const ic = (name, key, size) => iconMod\n      ? d2.render(iconMod, { name, size: size || 24, iconColor: 'currentColor' },\n          { key: 'ic-' + key, width: size || 24, height: size || 24, class: 'slot' })\n      : '';\n\n    const logo = logoMod\n      ? `<div class=\"logo\">${d2.render(logoMod, { layout, href: p.homeHref || '/' }, { key: 'logo' })}</div>` : '';\n\n    const search = searchMod\n      ? `<div class=\"search\">${d2.render(searchMod,\n          { layout, button: buttonMod, searchIcon: iconMod, shortPlaceholder: layout === 'tablet' ? (p.tabletPlaceholder || 'Buscar produto') : undefined },\n          { key: 'search', onSearch: (q) => { try { d2.emit('onSearch', q); } catch (err) { /* sem handler */ } const t = String(q || '').trim(); if (t && typeof window !== 'undefined') window.location.assign(LISTA + '?q=' + encodeURIComponent(t)); } })}</div>`\n      : '';\n\n    const rawCount = d2.state.bag != null ? d2.state.bag : p.cartCount;\n    const count = Number(rawCount) > 0 ? Math.min(Number(rawCount), 99) : 0;\n    const cart = `<button type=\"button\" class=\"ibtn\" data-act=\"cart\" aria-label=\"Sacola${count ? ', ' + count + (count === 1 ? ' item' : ' itens') : ''}\">${ic('bag', 'bag')}${count ? `<span class=\"count\">${count}</span>` : ''}</button>`;\n    const logged = !!p.userName;\n    const userIcon = logged\n      ? `<button type=\"button\" class=\"ibtn\" data-act=\"umenu\" aria-label=\"Minha conta e sair\" aria-expanded=\"${d2.state.um ? 'true' : 'false'}\" aria-controls=\"umenu\">${ic('user', 'user')}</button>`\n      : `<button type=\"button\" class=\"ibtn\" data-act=\"account\" aria-label=\"Entrar na sua conta\">${ic('user', 'user')}</button>`;\n    const menu = `<button type=\"button\" class=\"ibtn\" data-act=\"menu\" aria-label=\"Abrir menu\">${ic('menu', 'menu')}</button>`;\n\n    const hint = p.userName ? 'Olá, ' + p.userName : (p.accountHint || 'Entre ou cadastre-se');\n    const acct = `<button type=\"button\" class=\"acct\" data-act=\"account\">${ic('user', 'user-d')}<span class=\"txt\"><span class=\"hint\">${esc(hint)}</span><span class=\"lbl\">Minha conta</span></span></button>`;\n    const out = logged ? `<button type=\"button\" class=\"out\" data-act=\"logout\">${ic('logout', 'out', 18)}Sair</button>` : '';\n    const umenu = logged && !desk && d2.state.um\n      ? `<div class=\"umenu\" id=\"umenu\" role=\"menu\"><a role=\"menuitem\" href=\"${esc(p.accountHref || '/minha-conta/pedidos')}\" data-act=\"account\">${ic('user', 'um-user', 18)}Minha conta</a><button type=\"button\" role=\"menuitem\" data-act=\"logout\">${ic('logout', 'um-out', 18)}Sair</button></div>`\n      : '';\n\n    const list = cats(p.categories);\n    const active = slug(p.activeCategory);\n    const allLabel = p.allProductsLabel || 'Todos os produtos';\n    const allHref = p.allProductsHref || LISTA;\n    const links = list.map((c) => {\n      const s = slug(c.label);\n      const on = s === active;\n      return `<a href=\"${esc(c.href)}\" data-key=\"${esc(s)}\" data-slug=\"${esc(s)}\" class=\"${on ? 'on' : ''}\"${on ? ' aria-current=\"page\"' : ''}>${esc(c.label)}</a>`;\n    }).join('');\n    const allOn = active === 'todos';\n    const allInNav = `<a href=\"${esc(allHref)}\" data-key=\"todos\" data-slug=\"todos\" class=\"${allOn ? 'on' : ''}\"${allOn ? ' aria-current=\"page\"' : ''}>${esc(allLabel)}</a>`;\n\n    const navrow = desk\n      ? `<div class=\"navrow\"><nav class=\"nav\" aria-label=\"Categorias\">${links}</nav><a class=\"all\" href=\"${esc(allHref)}\"><span>${esc(allLabel)}</span>${ic('arrow-right', 'arrow', 16)}</a></div>`\n      : `<div class=\"navrow\"><nav class=\"nav\" aria-label=\"Categorias\">${allInNav}${links}</nav></div>`;\n\n    let top;\n    if (desk) {\n      top = `<div class=\"row\">${logo}${search}<div class=\"actions\">${acct}${out}${cart}</div></div>`;\n    } else if (mob) {\n      top = `<div class=\"row\"><div class=\"left\">${menu}</div>${logo}<div class=\"actions\">${userIcon}${cart}</div></div><div class=\"srow\">${search}</div>`;\n    } else {\n      top = `<div class=\"row\">${menu}${logo}${search}<div class=\"actions\">${userIcon}${cart}</div></div>`;\n    }\n\n    return `<header class=\"hd l-${layout}\">${top}${navrow}${umenu}</header>`;\n  }\n};"}},"accountHint":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"accountHint"}}}},"accountHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"accountHref"}}}},"activeCategory":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"activeCategory"}}}},"allProductsHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"allProductsHref"}}}},"allProductsLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"allProductsLabel"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"cartCount":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"cartCount"}}}},"categories":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"categories"}}}},"homeHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"homeHref"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"logo":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"logo"}}}},"onAccount":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onAccount"}}}},"onCart":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCart"}}}},"onCategory":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCategory"}}}},"onLogout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onLogout"}}}},"onMenu":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onMenu"}}}},"onSearch":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSearch"}}}},"searchBar":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"searchBar"}}}},"userName":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"userName"}}}}}}}}}},{"_id":"6ab6c6edc37038941e4f0cad","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Hero","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Hero — Loja Lucas Fontana\n// Carrossel de abertura da home. Não desenha botão nem ícones:\n// reaproveita Button (CTA) e Icon (setas e placeholder de foto) pelos parâmetros `button` e `iconComponent`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst DEFAULT_SLIDES = [\n  {\n    eyebrow: 'Loja oficial do canal',\n    title: 'Testado no canal.\\nAprovado na garagem.',\n    shortTitle: 'Testado no canal.\\nAprovado na garagem.',\n    text: 'Os produtos que o Lucas usa nos vídeos, agora direto da garagem para a sua. Assiste primeiro. Compra depois.',\n    shortText: 'O que aparece nos vídeos, tá aqui na loja.',\n    ctaLabel: 'Ver mais vendidos', ctaShortLabel: 'Mais vendidos', ctaHref: '/produtos?ordem=mais-vendidos'\n  },\n  {\n    eyebrow: 'Performance BPower',\n    title: 'Peça boa.\\nEnviada pela BPower.',\n    shortTitle: 'Peça boa.\\nEnviada pela BPower.',\n    text: 'A linha de performance da parceira, com a garantia da loja oficial e parcelamento no cartão.',\n    shortText: 'Linha de performance com a garantia da loja oficial.',\n    ctaLabel: 'Conhecer a linha', ctaShortLabel: 'Conhecer', ctaHref: '/c/performance-bpower'\n  },\n  {\n    eyebrow: 'Limpeza automotiva',\n    title: 'O que não sai\\nda garagem do Lucas.',\n    shortTitle: 'O que não sai\\nda garagem.',\n    text: 'Shampoo, pretinho e tudo o que deixa o carro no ponto de gravação.',\n    shortText: 'Tudo o que deixa o carro no ponto de gravação.',\n    ctaLabel: 'Ver limpeza', ctaShortLabel: 'Ver limpeza', ctaHref: '/c/limpeza-automotiva'\n  }\n];\nconst PHOTO = { desktop: '1440 × 580', tablet: '1536 × 1040', mobile: '780 × 1120' };\n\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst lines = (s) => esc(s).split(/\\n|\\\\n/).join('<br>');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst detect = (w) => (w >= 1200 ? 'desktop' : w >= 768 ? 'tablet' : 'mobile');\nconst pad = (n) => (n < 10 ? '0' + n : String(n));\n\nfunction slidesOf(v) {\n  let list = v;\n  if (typeof list === 'string') { try { list = JSON.parse(list); } catch (e) { list = null; } }\n  return Array.isArray(list) && list.length ? list : DEFAULT_SLIDES;\n}\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.hero { --red-500: #c8102e; --red-300: #f0707f; --ink: #0b0b0c; --white: #ffffff; --graphite-800: #2a2b2e; --graphite-900: #1c1d1f; --graphite-950: #121314;\n  --text-inv-2: #b9bbbe;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  position: relative; width: 100%; height: 580px; overflow: hidden; background: var(--ink); color: var(--white); touch-action: pan-y; }\n.slide { position: absolute; inset: 0; opacity: 0; visibility: hidden; transition: opacity .45s ease, visibility 0s linear .45s; }\n.slide.on { opacity: 1; visibility: visible; transition: opacity .45s ease; }\n\n/* Foto */\n.photo { position: absolute; top: 0; right: 0; bottom: 0; width: 56%; background: var(--graphite-900); overflow: hidden; }\n.photo::before { content: ''; position: absolute; top: 0; bottom: 0; left: 0; width: 240px; z-index: 1; background: linear-gradient(90deg, var(--ink), rgba(11,11,12,0)); pointer-events: none; }\n.photo img { display: block; width: 100%; height: 100%; object-fit: cover; }\n.ph { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; color: #6b6e73;\n  background: repeating-linear-gradient(-18deg, var(--graphite-900) 0 22px, var(--graphite-800) 22px 24px); }\n.ph .slot { width: 40px; height: 40px; }\n.l-desktop .ph { padding-left: 32%; }\n.l-tablet .ph, .l-mobile .ph { justify-content: flex-start; padding-top: 64px; }\n.l-tablet .title .t-long, .l-tablet .title .t-short, .l-mobile .title .t-long, .l-mobile .title .t-short { white-space: normal; }\n.ph span { font-size: 12px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; }\n.checker { position: absolute; top: 0; right: 0; z-index: 2; width: 120px; height: 60px; pointer-events: none;\n  background: repeating-conic-gradient(var(--white) 0 25%, var(--ink) 0 50%) 0 0 / 60px 60px; }\n\n/* Texto */\n.copy { position: absolute; top: 0; bottom: 0; left: 0; width: 62%; padding: 0 48px 0 96px; display: flex; flex-direction: column; justify-content: center; z-index: 1; }\n.title .t-long, .title .t-short { white-space: nowrap; }\n.eyebrow { display: flex; align-items: center; gap: 12px; margin: 0 0 20px; color: var(--red-300); font-size: 12px; font-weight: 700; letter-spacing: .3em; text-transform: uppercase; }\n.eyebrow b { font-weight: 800; letter-spacing: .1em; }\n.eyebrow i { display: block; width: 24px; height: 2px; background: var(--red-500); transform: skewX(-30deg); }\n.title { margin: 0; font-size: 64px; line-height: .98; font-weight: 800; font-style: italic; font-stretch: 118%; letter-spacing: -.005em; text-transform: uppercase; }\n.lead { margin: 20px 0 0; max-width: 460px; font-size: 17px; line-height: 1.5; color: var(--text-inv-2); }\n.cta { margin-top: 32px; height: 56px; width: auto; align-self: flex-start; }\n.t-short, .x-short { display: none; }\n\n/* Controles */\n.ctrl { position: absolute; right: 96px; bottom: 40px; display: flex; align-items: center; gap: 24px; z-index: 2; }\n.dots { display: flex; align-items: center; }\n.dot { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; padding: 0; margin: 0; border: 0; background: transparent; cursor: pointer; }\n.dot span { display: block; width: 24px; height: 3px; background: rgba(255,255,255,.4); transition: width .2s ease, background-color .2s ease; }\n.dot.on span { width: 36px; background: var(--red-500); }\n.dot:hover span { background: var(--white); }\n.dot.on:hover span { background: var(--red-500); }\n.arrows { display: flex; gap: 8px; }\n.arr { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; padding: 0; margin: 0; background: transparent;\n  border: 1.5px solid rgba(255,255,255,.4); border-radius: 2px; color: var(--white); cursor: pointer; }\n.arr:hover { background: var(--white); color: var(--ink); border-color: var(--white); }\n.arr .slot { width: 20px; height: 20px; pointer-events: none; }\n.dot:focus-visible, .arr:focus-visible { outline: 2px solid var(--white); outline-offset: 2px; }\n\n/* Tablet: foto atrás, texto embaixo, sem setas */\n.l-tablet { height: 520px; }\n.l-tablet .photo { width: 100%; left: 0; }\n.l-tablet .photo::before { display: none; }\n.l-tablet .photo::after { content: ''; position: absolute; inset: 0; background: linear-gradient(0deg, rgba(11,11,12,.92) 0%, rgba(11,11,12,.6) 42%, rgba(11,11,12,0) 75%); }\n.l-tablet .copy { top: auto; width: 100%; padding: 0 40px 88px; justify-content: flex-end; }\n.l-tablet .title { font-size: 48px; font-stretch: 104%; }\n.l-tablet .lead { font-size: 16px; margin-top: 16px; max-width: 520px; }\n.l-tablet .eyebrow { margin-bottom: 16px; }\n.l-tablet .cta { margin-top: 24px; height: 52px; }\n.l-tablet .ctrl { left: 30px; right: auto; bottom: 20px; }\n.l-tablet .arrows { display: none; }\n\n/* Mobile: foto atrás, texto embaixo, CTA com largura total */\n.l-mobile { height: 560px; }\n.l-mobile .photo { width: 100%; left: 0; }\n.l-mobile .photo::before { display: none; }\n.l-mobile .photo::after { content: ''; position: absolute; inset: 0; background: linear-gradient(0deg, rgba(11,11,12,.95) 0%, rgba(11,11,12,.7) 45%, rgba(11,11,12,0) 78%); }\n.l-mobile .checker { width: 96px; height: 48px; background-size: 48px 48px; }\n.l-mobile .copy { top: auto; width: 100%; padding: 0 20px 76px; justify-content: flex-end; }\n.l-mobile .eyebrow { margin-bottom: 14px; font-size: 11px; letter-spacing: .24em; gap: 10px; }\n.l-mobile .title { font-size: 34px; line-height: 1; font-stretch: 112%; }\n.l-mobile .lead { font-size: 15px; margin-top: 12px; }\n.l-mobile .cta { margin-top: 20px; height: 52px; width: 100%; align-self: stretch; }\n.l-mobile .t-long, .l-mobile .x-long { display: none; }\n.l-mobile .t-short, .l-mobile .x-short { display: inline; }\n.l-mobile .ctrl { left: 50%; right: auto; transform: translateX(-50%); bottom: 16px; }\n.l-mobile .arrows { display: none; }\n`,\n\n  mounted(d2, root) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    if (typeof ResizeObserver !== 'undefined') {\n      const ro = new ResizeObserver((e) => {\n        const w = detect(e[0].contentRect.width);\n        if (d2.state.auto !== w) d2.state.auto = w;\n      });\n      ro.observe(root);\n      d2.onUnmount(() => ro.disconnect());\n    }\n    const total = () => slidesOf(d2.params && d2.params.slides).length;\n    const go = (i) => {\n      const n = total();\n      const next = ((i % n) + n) % n;\n      if (d2.state.i !== next) {\n        d2.state.i = next;\n        try { d2.emit('onSlideChange', next); } catch (err) { /* sem handler */ }\n      }\n    };\n    const cur = () => d2.state.i || 0;\n    d2.on('.arr.prev', 'click', () => { go(cur() - 1); restart(); });\n    d2.on('.arr.next', 'click', () => { go(cur() + 1); restart(); });\n    d2.on('.dot', 'click', (e, el) => { go(Number(el.dataset.i)); restart(); });\n    d2.on('.hero', 'keydown', (e) => {\n      if (e.key === 'ArrowLeft') { go(cur() - 1); restart(); }\n      if (e.key === 'ArrowRight') { go(cur() + 1); restart(); }\n    });\n\n    // Arrastar para o lado troca o slide (celular e tablet)\n    let x0 = null;\n    d2.on('.hero', 'pointerdown', (e) => { x0 = e.clientX; });\n    d2.on('.hero', 'pointerup', (e) => {\n      if (x0 == null) return;\n      const dx = e.clientX - x0; x0 = null;\n      if (Math.abs(dx) > 48) { go(cur() + (dx < 0 ? 1 : -1)); restart(); }\n    });\n\n    // Troca automática opcional (autoplay em segundos; 0 desliga). Pausa ao passar o mouse.\n    let timer = null;\n    const stop = () => { if (timer) { clearInterval(timer); timer = null; } };\n    const start = () => {\n      stop();\n      const s = Number(d2.params && d2.params.autoplay) || 0;\n      const reduce = typeof matchMedia !== 'undefined' && matchMedia('(prefers-reduced-motion: reduce)').matches;\n      if (s > 0 && !reduce && total() > 1) timer = setInterval(() => go(cur() + 1), s * 1000);\n    };\n    function restart() { start(); }\n    d2.on('.hero', 'mouseover', stop);\n    d2.on('.hero', 'mouseout', (e) => { const h = d2.$('.hero'); if (!h || !e.relatedTarget || !h.contains(e.relatedTarget)) start(); });\n    start();\n    d2.onUnmount(stop);\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : (d2.state.auto || 'desktop');\n    const slides = slidesOf(p.slides);\n    const n = slides.length;\n    const active = Math.min(d2.state.i || 0, n - 1);\n    const iconRef = refOf(d2.param('iconComponent'));\n    const buttonRef = refOf(d2.param('button'));\n    const mob = layout === 'mobile';\n\n    const ic = (name, key, size, color) => iconRef\n      ? d2.render(iconRef, { name, size, iconColor: color || 'currentColor' }, { key, width: size, height: size, class: 'slot' })\n      : '';\n\n    const html = slides.map((s, i) => {\n      const img = (layout === 'mobile' && s.imageMobile) || (layout !== 'desktop' && s.imageTablet) || s.image || '';\n      const photo = img\n        ? `<img src=\"${esc(img)}\" alt=\"${esc(s.imageAlt || '')}\"${i === 0 ? '' : ' loading=\"lazy\"'}>`\n        : `<div class=\"ph\">${ic('image', 'ph-' + i, 40, '#6b6e73')}<span>Foto ${PHOTO[layout]}</span></div>`;\n      const cta = buttonRef && s.ctaLabel\n        ? `<div class=\"cta\">${d2.render(buttonRef, {\n            label: mob && s.ctaShortLabel ? s.ctaShortLabel : s.ctaLabel,\n            variant: 'brand', size: 'hero', fullWidth: 'mobile', arrow: true, layout, href: s.ctaHref || ''\n          }, { key: 'cta-' + i, onClick: () => { try { d2.emit('onCta', { index: i, href: s.ctaHref || '' }); } catch (err) { /* sem handler */ } } })}</div>`\n        : '';\n      const shortT = s.shortTitle || s.title;\n      const shortX = s.shortText || s.text;\n      return `<div class=\"slide${i === active ? ' on' : ''}\" data-key=\"s${i}\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"${i + 1} de ${n}\"${i === active ? '' : ' aria-hidden=\"true\"'}>\n        <div class=\"photo\">${photo}<div class=\"checker\" aria-hidden=\"true\"></div></div>\n        <div class=\"copy\">\n          ${s.eyebrow ? `<p class=\"eyebrow\"><b>${pad(i + 1)}</b><i></i>${esc(s.eyebrow)}</p>` : ''}\n          <h${i === 0 ? 1 : 2} class=\"title\"><span class=\"t-long\">${lines(s.title)}</span><span class=\"t-short\">${lines(shortT)}</span></h${i === 0 ? 1 : 2}>\n          ${s.text ? `<p class=\"lead\"><span class=\"x-long\">${esc(s.text)}</span><span class=\"x-short\">${esc(shortX)}</span></p>` : ''}\n          ${cta}\n        </div>\n      </div>`;\n    }).join('');\n\n    const dots = n > 1 ? `<div class=\"dots\">${slides.map((s, i) =>\n      `<button type=\"button\" class=\"dot${i === active ? ' on' : ''}\" data-i=\"${i}\" data-key=\"d${i}\" aria-label=\"Ir para o slide ${i + 1}\"${i === active ? ' aria-current=\"true\"' : ''}><span></span></button>`).join('')}</div>` : '';\n    const arrows = n > 1 && layout === 'desktop'\n      ? `<div class=\"arrows\"><button type=\"button\" class=\"arr prev\" aria-label=\"Slide anterior\">${ic('chevron-left', 'al', 20)}</button><button type=\"button\" class=\"arr next\" aria-label=\"Próximo slide\">${ic('chevron-right', 'ar', 20)}</button></div>`\n      : '';\n\n    return `<section class=\"hero l-${layout}\" aria-roledescription=\"carrossel\" aria-label=\"Destaques da loja\" tabindex=\"-1\">${html}${n > 1 ? `<div class=\"ctrl\">${dots}${arrows}</div>` : ''}</section>`;\n  }\n};"}},"autoplay":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"autoplay"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onCta":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCta"}}}},"onSlideChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSlideChange"}}}},"slides":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"slides"}}}}}}}}}},{"_id":"6ab6c9e2df879c35ebaf3043","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"CategoryCard","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// CategoryCard — Loja Lucas Fontana\n// Card de categoria da home: fundo escuro, numeral vermelho, nome largo e a seta num quadrado vermelho.\n// Não desenha ícones: reaproveita o Icon da loja pelo parâmetro `iconComponent`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst detect = (w) => (w >= 280 ? 'desktop' : w >= 200 ? 'tablet' : 'mobile');\nconst numeral = (v) => {\n  if (v == null || v === '') return '';\n  const n = Number(v);\n  return Number.isFinite(n) ? (n < 10 ? '0' + n : String(n)) : String(v);\n};\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.card { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --graphite-800: #2a2b2e; --graphite-900: #1c1d1f; --text-inv-2: #b9bbbe;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  position: relative; display: flex; flex-direction: column; justify-content: space-between; width: 100%; height: 100%; min-height: 160px;\n  padding: 28px; overflow: hidden; border-radius: 0; background: var(--graphite-900); color: var(--white); text-decoration: none; cursor: pointer; }\n.card.t-ink { background: var(--ink); }\n.card:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n\n.bg { position: absolute; inset: 0; z-index: 0; }\n.bg img { display: block; width: 100%; height: 100%; object-fit: cover; transition: transform .5s ease; }\n.bg::after { content: ''; position: absolute; inset: 0; background: linear-gradient(0deg, rgba(11,11,12,.92) 0%, rgba(11,11,12,.45) 55%, rgba(11,11,12,.25) 100%); }\n.card:hover .bg img { transform: scale(1.04); }\n\n.num { position: relative; z-index: 1; margin: 0; font-size: 44px; line-height: 1; font-weight: 800; font-style: italic; font-stretch: 125%; color: var(--red-500); }\n.foot { position: relative; z-index: 1; display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; }\n.words { display: flex; flex-direction: column; gap: 8px; min-width: 0; }\n.name { margin: 0; font-size: 22px; line-height: 1.05; font-weight: 800; font-stretch: 108%; text-transform: uppercase; letter-spacing: 0; overflow-wrap: normal; word-break: normal; hyphens: none; }\n.cap { margin: 0; font-size: 14px; line-height: 1.35; color: var(--text-inv-2); }\n.go { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; background: var(--red-500); color: var(--white);\n  transition: background-color .15s ease, color .15s ease; }\n.go .slot { width: 20px; height: 20px; pointer-events: none; }\n.card:hover .go { background: var(--white); color: var(--ink); }\n.card:hover .name { color: var(--white); }\n\n/* Tablet */\n.l-tablet { padding: 24px; }\n.l-tablet .num { font-size: 36px; font-stretch: 120%; }\n.l-tablet .name { font-size: 20px; font-stretch: 108%; }\n.l-tablet .cap { font-size: 13px; }\n\n/* Mobile: seta some, tudo menor */\n.l-mobile { padding: 16px; min-height: 140px; }\n.l-mobile .num { font-size: 26px; font-stretch: 115%; }\n.l-mobile .words { gap: 4px; }\n.l-mobile .name { font-size: 16px; font-stretch: 104%; }\n.l-mobile .cap { font-size: 12px; }\n.l-mobile .go { display: none; }\n`,\n\n  mounted(d2, root) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    // Sem `layout` fixo, o card segue a largura da própria coluna da grade\n    if (typeof ResizeObserver !== 'undefined') {\n      const ro = new ResizeObserver((e) => {\n        const w = detect(e[0].contentRect.width);\n        if (d2.state.auto !== w) d2.state.auto = w;\n      });\n      ro.observe(root);\n      d2.onUnmount(() => ro.disconnect());\n    }\n    d2.on('.card', 'click', (e, el) => {\n      if (el.tagName !== 'A') {\n        try { d2.emit('onSelect', d2.params && d2.params.slug); } catch (err) { /* sem handler */ }\n      }\n    });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : (d2.state.auto || 'desktop');\n    const tone = p.tone === 'ink' ? 'ink' : 'graphite';\n    const label = p.label || 'Limpeza automotiva';\n    const cap = layout === 'mobile' && p.shortCaption ? p.shortCaption : (p.caption == null ? '24 produtos' : p.caption);\n    const num = numeral(p.number == null ? 1 : p.number);\n    const iconRef = refOf(d2.param('iconComponent'));\n    const arrow = iconRef\n      ? `<span class=\"go\" aria-hidden=\"true\">${d2.render(iconRef, { name: 'arrow-right', size: 20, iconColor: 'currentColor' }, { key: 'arrow', width: 20, height: 20, class: 'slot' })}</span>`\n      : '';\n    const bg = p.image ? `<div class=\"bg\"><img src=\"${esc(p.image)}\" alt=\"\" loading=\"lazy\"></div>` : '';\n    const inner = `${bg}${num ? `<p class=\"num\" aria-hidden=\"true\">${esc(num)}</p>` : '<span></span>'}\n      <div class=\"foot\"><div class=\"words\"><p class=\"name\">${esc(label)}</p>${cap ? `<p class=\"cap\">${esc(cap)}</p>` : ''}</div>${arrow}</div>`;\n    const cls = `card t-${tone} l-${layout}`;\n    return p.href\n      ? `<a class=\"${cls}\" href=\"${esc(p.href)}\" aria-label=\"${esc(label)}${cap ? ', ' + esc(cap) : ''}\">${inner}</a>`\n      : `<button type=\"button\" class=\"${cls}\" style=\"border:0;text-align:left;font:inherit\" aria-label=\"${esc(label)}${cap ? ', ' + esc(cap) : ''}\">${inner}</button>`;\n  }\n};"}},"caption":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"caption"}}}},"href":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"href"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"image":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"image"}}}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"number":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"number"}}}},"onSelect":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSelect"}}}},"shortCaption":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"shortCaption"}}}},"slug":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"slug"}}}},"tone":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"tone"}}}}}}}}}},{"_id":"6ab6ca7fff43b91b61b9b044","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Price","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Price — Loja Lucas Fontana\n// Bloco de preço: preço cheio grande, valor no Pix e parcelamento no cartão.\n// Dois tamanhos: `card` (ProductCard) e `buybox` (página de produto).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst SIZES = ['card', 'buybox'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst num = (v) => { const n = typeof v === 'string' ? Number(v.replace(/\\./g, '').replace(',', '.')) : Number(v); return Number.isFinite(n) ? n : 0; };\nconst brl = (n) => 'R$\\u00a0' + n.toFixed(2).replace('.', ',').replace(/\\B(?=(\\d{3})+(?!\\d))/g, '.');\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.pr { --red-500: #c8102e; --ink: #0b0b0c; --grey-500: #6b6e73; --grey-700: #45474b;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  display: flex; flex-direction: column; gap: 4px; color: var(--ink); }\np { margin: 0; }\n.old { font-size: 13px; color: var(--grey-500); text-decoration: line-through; line-height: 1.2; }\n.main { font-size: 22px; line-height: 1.1; font-weight: 800; font-stretch: 110%; letter-spacing: -.005em; white-space: nowrap; }\n.sub { font-size: 13px; line-height: 1.4; color: var(--grey-700); }\n.sub b { font-weight: 700; color: var(--ink); }\n.sub .br { display: none; }\n.muted .main, .muted .sub b { color: var(--grey-500); }\n\n/* card: tablet e mobile */\n.s-card.l-tablet .main { font-size: 20px; }\n.s-card.l-mobile .main { font-size: 17px; font-stretch: 106%; }\n.s-card.l-mobile .sub { font-size: 12px; line-height: 1.35; }\n.s-card.l-mobile .dot { display: none; }\n.s-card.l-mobile .sub .br { display: block; }\n\n/* buybox */\n.s-buybox { gap: 6px; }\n.s-buybox .old { font-size: 15px; }\n.s-buybox .main { font-size: 36px; }\n.s-buybox .pix { font-size: 17px; font-weight: 700; color: var(--ink); line-height: 1.3; margin-top: 4px; }\n.s-buybox .pix span { color: var(--red-500); }\n.s-buybox .inst { font-size: 14px; color: var(--grey-700); line-height: 1.4; }\n.s-buybox.l-tablet .main { font-size: 32px; }\n.s-buybox.l-mobile .main { font-size: 28px; font-stretch: 106%; }\n.s-buybox.l-mobile .pix { font-size: 16px; }\n.s-buybox.l-mobile .inst { font-size: 13px; }\n`,\n\n  mounted() {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const size = SIZES.indexOf(p.size) >= 0 ? p.size : 'card';\n    const price = num(p.price == null ? 89.9 : p.price);\n    const disc = p.pixDiscount == null || p.pixDiscount === '' ? 10 : num(p.pixDiscount);\n    const pix = p.pixPrice != null && p.pixPrice !== '' ? num(p.pixPrice) : Math.round(price * (100 - disc)) / 100;\n    const n = Math.max(1, Math.round(num(p.installments == null ? 3 : p.installments)));\n    const old = num(p.oldPrice);\n    const showPix = pix > 0 && pix < price;\n    const cls = `pr s-${size} l-${layout}${truthy(p.muted) ? ' muted' : ''}`;\n    const oldHtml = old > price ? `<p class=\"old\"><span class=\"sr\" style=\"position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)\">De </span>${brl(old)}</p>` : '';\n\n    if (size === 'buybox') {\n      return `<div class=\"${cls}\">${oldHtml}\n        <p class=\"main\">${brl(price)}</p>\n        ${showPix ? `<p class=\"pix\"><span>${brl(pix)}</span> no Pix</p>` : ''}\n        ${n > 1 ? `<p class=\"inst\">ou ${n}x de ${brl(Math.floor((price / n) * 100) / 100)} sem juros no cartão</p>` : ''}\n      </div>`;\n    }\n    const card = n > 1 ? `ou ${n}x no cartão` : 'no cartão';\n    return `<div class=\"${cls}\">${oldHtml}\n      <p class=\"main\">${brl(price)}</p>\n      <p class=\"sub\">${showPix ? `<b>${brl(pix)} no Pix</b><span class=\"dot\"> · </span><span class=\"br\"></span>` : ''}${esc(card)}</p>\n    </div>`;\n  }\n};"}},"installments":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"installments"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"muted":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"muted"}}}},"oldPrice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"oldPrice"}}}},"pixDiscount":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"pixDiscount"}}}},"pixPrice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"pixPrice"}}}},"price":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"price"}}}},"size":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"size"}}}}}}}}}},{"_id":"6ab6caa02283ab0cf1c3c187","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"ProductCard","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// ProductCard — Loja Lucas Fontana\n// Card de produto: foto quadrada, selos, nome, preço e o botão de compra.\n// Não desenha preço, botão, selos nem ícones: reaproveita Price, Button, Badge e Icon\n// pelos parâmetros `priceComponent`, `button`, `badge` e `iconComponent`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst detect = (w) => (w >= 290 ? 'desktop' : w >= 200 ? 'tablet' : 'mobile');\nconst fire = (d2, name, payload) => { try { d2.emit(name, payload); } catch (err) { /* sem handler */ } };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.pc { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-50: #f5f5f3; --grey-100: #ececea; --grey-500: #6b6e73; --line: #e4e4e2;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  display: flex; flex-direction: column; width: 100%; height: 100%; background: var(--white); color: var(--ink); border-radius: 0; }\n.pc.outlined { border: 1px solid var(--line); transition: border-color .15s ease; }\n.pc.outlined:hover { border-color: var(--ink); }\n\n.media { position: relative; display: block; width: 100%; flex: 1 1 0; min-height: 120px; background: var(--grey-100); overflow: hidden; }\n.media img { display: block; width: 100%; height: 100%; object-fit: cover; transition: transform .4s ease; }\n.pc:hover .media img { transform: scale(1.03); }\n.media:focus-visible, .name a:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.ph { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: #a7a9ad; }\n.ph .slot { width: 40px; height: 40px; }\n.oos .media img, .oos .ph { opacity: .45; }\n.tags { position: absolute; top: 12px; left: 12px; right: 12px; display: flex; flex-wrap: wrap; gap: 6px; pointer-events: none; }\n.tag { height: 24px; }\n.soon { position: absolute; left: 0; right: 0; bottom: 0; padding: 10px 12px; background: var(--ink); color: var(--white);\n  font-size: 12px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; text-align: center; }\n\n.body { display: flex; flex-direction: column; flex: none; padding: 16px 0 0; }\n.outlined .body { padding: 16px; }\n.brand { margin: 0 0 6px; font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--grey-500); }\n.name { margin: 0; font-size: 15px; line-height: 1.35; font-weight: 600; min-height: calc(1.35em * 2);\n  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }\n.name a { color: inherit; text-decoration: none; }\n.name a:hover { color: var(--red-500); }\n.price { margin-top: 12px; }\n.act { margin-top: auto; padding-top: 16px; height: 60px; flex: none; }\n\n/* Tablet */\n.l-tablet .name { font-size: 15px; }\n\n/* Mobile */\n.l-mobile .tags { top: 8px; left: 8px; right: 8px; gap: 4px; }\n.l-mobile .tag { height: 20px; }\n.l-mobile .soon { padding: 8px; font-size: 10px; letter-spacing: .1em; }\n.l-mobile .body { padding-top: 12px; }\n.l-mobile.outlined .body { padding: 12px; }\n.l-mobile .brand { font-size: 10px; margin-bottom: 4px; }\n.l-mobile .name { font-size: 13px; }\n.l-mobile .price { margin-top: 8px; }\n.l-mobile .act { padding-top: 12px; height: 56px; }\n`,\n\n  mounted(d2, root) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    // Sem `layout` fixo, o card segue a largura da própria coluna da grade\n    if (typeof ResizeObserver !== 'undefined') {\n      const ro = new ResizeObserver((e) => {\n        const w = detect(e[0].contentRect.width);\n        if (d2.state.auto !== w) d2.state.auto = w;\n      });\n      ro.observe(root);\n      d2.onUnmount(() => ro.disconnect());\n    }\n    d2.on('.media, .name a', 'click', () => fire(d2, 'onOpen', d2.params && d2.params.sku));\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : (d2.state.auto || 'desktop');\n    const mob = layout === 'mobile';\n    const oos = truthy(p.outOfStock);\n    const outlined = p.variant === 'outlined';\n    const name = p.name || 'Shampoo automotivo neutro';\n    const href = p.href || '#';\n    const sku = p.sku || '';\n\n    const priceRef = refOf(d2.param('priceComponent'));\n    const buttonRef = refOf(d2.param('button'));\n    const badgeRef = refOf(d2.param('badge'));\n    const iconRef = refOf(d2.param('iconComponent'));\n\n    const photo = p.image\n      ? `<img src=\"${esc(p.image)}\" alt=\"${esc(p.imageAlt || name)}\" loading=\"lazy\">`\n      : `<div class=\"ph\">${iconRef ? d2.render(iconRef, { name: 'image', size: 40, iconColor: '#a7a9ad' }, { key: 'ph', width: 40, height: 40, class: 'slot' }) : ''}</div>`;\n\n    // Selos: parceiro (preto) + selo livre (vermelho). Sem estoque, o selo livre sai.\n    const tags = [];\n    if (p.partner) tags.push({ k: 'partner', label: p.partner, tone: 'ink' });\n    if (p.tag && !oos) tags.push({ k: 'tag', label: p.tag, tone: 'red' });\n    const tagHtml = badgeRef && tags.length\n      ? `<div class=\"tags\">${tags.map((t) => `<div class=\"tag\">${d2.render(badgeRef, { label: t.label, tone: t.tone, layout }, { key: 'b-' + t.k, width: 'auto', height: mob ? 20 : 24 })}</div>`).join('')}</div>`\n      : '';\n\n    const price = priceRef\n      ? `<div class=\"price\">${d2.render(priceRef, {\n          price: p.price, pixPrice: p.pixPrice, pixDiscount: p.pixDiscount, installments: p.installments, oldPrice: p.oldPrice,\n          size: 'card', layout, muted: oos\n        }, { key: 'price', height: 'auto' })}</div>`\n      : '';\n\n    const btn = buttonRef\n      ? `<div class=\"act\">${d2.render(buttonRef, oos\n          ? { label: p.notifyLabel || 'Me avise quando chegar', shortLabel: 'Avise-me', variant: 'outline', size: 'sm', fullWidth: 'always', layout }\n          : { label: p.addLabel || 'Adicionar à sacola', shortLabel: 'Adicionar', variant: 'primary', size: 'sm', fullWidth: 'always', layout },\n          { key: oos ? 'notify' : 'add', height: 44, onClick: () => fire(d2, oos ? 'onNotify' : 'onAdd', sku) })}</div>`\n      : '';\n\n    return `<article class=\"pc l-${layout}${outlined ? ' outlined' : ''}${oos ? ' oos' : ''}\">\n      <a class=\"media\" href=\"${esc(href)}\" tabindex=\"-1\" aria-hidden=\"true\">${photo}${tagHtml}${oos ? `<span class=\"soon\">${esc(p.soonLabel || 'Volta já já')}</span>` : ''}</a>\n      <div class=\"body\">\n        ${p.brand ? `<p class=\"brand\">${esc(p.brand)}</p>` : ''}\n        <h3 class=\"name\"><a href=\"${esc(href)}\">${esc(name)}</a></h3>\n        ${price}\n        ${btn}\n      </div>\n    </article>`;\n  }\n};"}},"addLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"addLabel"}}}},"badge":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"badge"}}}},"brand":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"brand"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"href":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"href"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"image":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"image"}}}},"imageAlt":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"imageAlt"}}}},"installments":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"installments"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"name":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"name"}}}},"notifyLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notifyLabel"}}}},"oldPrice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"oldPrice"}}}},"onAdd":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onAdd"}}}},"onNotify":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onNotify"}}}},"onOpen":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onOpen"}}}},"outOfStock":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"outOfStock"}}}},"partner":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"partner"}}}},"pixDiscount":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"pixDiscount"}}}},"pixPrice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"pixPrice"}}}},"price":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"price"}}}},"priceComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"priceComponent"}}}},"sku":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"sku"}}}},"soonLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"soonLabel"}}}},"tag":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"tag"}}}},"variant":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"variant"}}}}}}}}}},{"_id":"6ab6cd8b97b00074cbf00e09","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"FeaturePanel","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// FeaturePanel — Loja Lucas Fontana\n// Painel escuro de destaque (ex.: parceria BPower): eyebrow numerado, título largo, texto,\n// lista de vantagens, CTA e foto com o xadrez no canto inferior direito.\n// Não desenha botão nem ícones: reaproveita Button e Icon pelos parâmetros `button` e `iconComponent`.\n// O texto de apoio chega por `body` (o nome `text` é reservado do bloco base do Data2).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst DEFAULT_POINTS = ['Enviado direto pela BPower', 'Garantia da loja oficial', 'Até 6x sem juros no cartão'];\nconst PHOTO = { desktop: '624 × 520', tablet: '688 × 387', mobile: '350 × 262' };\n\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst lines = (s) => esc(s).split(/\\n|\\\\n/).join('<br>');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst detect = (w) => (w >= 1000 ? 'desktop' : w >= 600 ? 'tablet' : 'mobile');\nconst pad = (v) => { const n = Number(v); return Number.isFinite(n) && v !== '' && v != null ? (n < 10 ? '0' + n : String(n)) : String(v || ''); };\nfunction listOf(v) {\n  let l = v;\n  if (typeof l === 'string') l = l.split('\\n').map((s) => s.trim()).filter(Boolean);\n  return Array.isArray(l) ? l : DEFAULT_POINTS;\n}\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.fp { --red-500: #c8102e; --red-400: #e23a52; --ink: #0b0b0c; --white: #ffffff; --graphite-800: #2a2b2e; --graphite-900: #1c1d1f; --graphite-950: #121314;\n  --text-inv-2: #b9bbbe;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: minmax(0, 1fr); width: 100%; height: 100%; min-height: 520px; background: var(--graphite-900); color: var(--white); border-radius: 0; overflow: hidden; }\n.fp.t-ink { background: var(--ink); }\n.fp.rev .photo { order: -1; }\np, h2, ul { margin: 0; }\n\n.copy { display: flex; flex-direction: column; justify-content: center; padding: 48px 56px; min-width: 0; }\n.eyebrow { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; color: var(--red-400); font-size: 12px; font-weight: 700; letter-spacing: .3em; text-transform: uppercase; }\n.eyebrow b { font-weight: 800; letter-spacing: .1em; }\n.eyebrow i { display: block; width: 24px; height: 2px; background: var(--red-500); transform: skewX(-30deg); }\n.title { font-size: 44px; line-height: .98; font-weight: 800; font-style: italic; font-stretch: 118%; text-transform: uppercase; letter-spacing: -.005em; }\n.t-short { display: none; }\n.text { margin-top: 18px; max-width: 480px; font-size: 16px; line-height: 1.5; color: var(--text-inv-2); }\n.points { list-style: none; padding: 0; margin-top: 20px; display: flex; flex-direction: column; gap: 10px; }\n.points li { display: flex; align-items: center; gap: 12px; font-size: 15px; font-weight: 600; line-height: 1.3; }\n.points .slot { flex: none; width: 20px; height: 20px; }\n.cta { margin-top: 28px; height: 52px; align-self: flex-start; }\n\n.photo { position: relative; min-height: 0; height: 100%; background: var(--graphite-800); overflow: hidden; }\n.photo img { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: cover; }\n.ph { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; color: #6b6e73;\n  background: repeating-linear-gradient(-18deg, var(--graphite-800) 0 22px, #34353a 22px 24px); }\n.ph .slot { width: 40px; height: 40px; }\n.ph span { font-size: 12px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; }\n.checker { position: absolute; right: 0; bottom: 0; width: 120px; height: 60px; pointer-events: none;\n  background: repeating-conic-gradient(var(--white) 0 25%, var(--ink) 0 50%) 0 0 / 60px 60px; }\n\n/* Tablet: foto em cima, texto embaixo */\n.l-tablet { grid-template-columns: 1fr; grid-template-rows: auto 1fr; min-height: 0; }\n.l-tablet .photo { order: -1; aspect-ratio: 16 / 9; height: auto; }\n.l-tablet .copy { padding: 40px; justify-content: flex-start; }\n.l-tablet .title { font-size: 40px; font-stretch: 112%; }\n.l-tablet .text { max-width: 560px; }\n.l-tablet .cta { margin-top: 28px; }\n\n/* Mobile: empilhado, CTA com largura total */\n.l-mobile { grid-template-columns: 1fr; grid-template-rows: auto 1fr; min-height: 0; }\n.l-mobile .photo { order: -1; aspect-ratio: 4 / 3; height: auto; }\n.l-mobile .checker { width: 96px; height: 48px; background-size: 48px 48px; }\n.l-mobile .copy { padding: 28px 20px 32px; justify-content: flex-start; }\n.l-mobile .eyebrow { margin-bottom: 14px; font-size: 11px; letter-spacing: .24em; gap: 10px; }\n.l-mobile .title { font-size: 30px; line-height: 1; font-stretch: 110%; }\n.l-mobile .t-long { display: none; }\n.l-mobile .t-short { display: inline; }\n.l-mobile .text { margin-top: 14px; font-size: 15px; }\n.l-mobile .points { margin-top: 20px; gap: 10px; }\n.l-mobile .points li { font-size: 14px; }\n.l-mobile .cta { margin-top: 24px; width: 100%; align-self: stretch; }\n`,\n\n  mounted(d2, root) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    if (typeof ResizeObserver !== 'undefined') {\n      const ro = new ResizeObserver((e) => {\n        const w = detect(e[0].contentRect.width);\n        if (d2.state.auto !== w) d2.state.auto = w;\n      });\n      ro.observe(root);\n      d2.onUnmount(() => ro.disconnect());\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : (d2.state.auto || 'desktop');\n    const mob = layout === 'mobile';\n    const tone = p.tone === 'ink' ? 'ink' : 'graphite';\n    const iconRef = refOf(d2.param('iconComponent'));\n    const buttonRef = refOf(d2.param('button'));\n\n    const eyebrow = p.eyebrow == null ? 'Parceria oficial' : p.eyebrow;\n    const num = p.number == null ? '02' : pad(p.number);\n    const title = p.title || 'Peça de pista.\\nNa sua garagem.';\n    const shortTitle = p.shortTitle || title;\n    const body = p.body == null ? 'A linha de performance da BPower Motorsport. Produtos enviados diretamente pela BPower, com a garantia da loja oficial.' : p.body;\n    const points = listOf(p.points);\n    const ctaLabel = p.ctaLabel == null ? 'Conhecer a linha BPower' : p.ctaLabel;\n\n    const ic = (name, key, size, color) => iconRef\n      ? d2.render(iconRef, { name, size, iconColor: color }, { key, width: size, height: size, class: 'slot' })\n      : '';\n\n    const photo = p.image\n      ? `<img src=\"${esc(p.image)}\" alt=\"${esc(p.imageAlt || '')}\" loading=\"lazy\">`\n      : `<div class=\"ph\">${ic('image', 'ph', 40, '#6b6e73')}<span>Foto ${PHOTO[layout]}</span></div>`;\n\n    const cta = buttonRef && ctaLabel\n      ? `<div class=\"cta\">${d2.render(buttonRef, {\n          label: mob && p.ctaShortLabel ? p.ctaShortLabel : ctaLabel,\n          variant: p.ctaVariant === 'light' ? 'light' : 'brand', size: 'lg', fullWidth: 'mobile', arrow: true, layout, href: p.ctaHref || ''\n        }, { key: 'cta', onClick: () => { try { d2.emit('onCta', p.ctaHref || ''); } catch (err) { /* sem handler */ } } })}</div>`\n      : '';\n\n    return `<section class=\"fp l-${layout} t-${tone}${truthy(p.reverse) ? ' rev' : ''}\">\n      <div class=\"copy\">\n        ${eyebrow ? `<p class=\"eyebrow\">${num ? `<b>${esc(num)}</b><i></i>` : ''}${esc(eyebrow)}</p>` : ''}\n        <h2 class=\"title\"><span class=\"t-long\">${lines(title)}</span><span class=\"t-short\">${lines(shortTitle)}</span></h2>\n        ${body ? `<p class=\"text\">${esc(body)}</p>` : ''}\n        ${points.length ? `<ul class=\"points\">${points.map((t, i) => `<li data-key=\"pt${i}\">${ic('check', 'ck' + i, 20, '#e23a52')}<span>${esc(t)}</span></li>`).join('')}</ul>` : ''}\n        ${cta}\n      </div>\n      <div class=\"photo\">${photo}<div class=\"checker\" aria-hidden=\"true\"></div></div>\n    </section>`;\n  }\n};"}},"body":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"body"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"ctaHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ctaHref"}}}},"ctaLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ctaLabel"}}}},"ctaShortLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ctaShortLabel"}}}},"ctaVariant":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ctaVariant"}}}},"eyebrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"eyebrow"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"image":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"image"}}}},"imageAlt":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"imageAlt"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"number":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"number"}}}},"onCta":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCta"}}}},"points":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"points"}}}},"reverse":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"reverse"}}}},"shortTitle":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"shortTitle"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}},"tone":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"tone"}}}}}}}}}},{"_id":"6ab6ce10cf6e94d42983237c","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"InfoCard","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// InfoCard — Loja Lucas Fontana\n// Card de informação (frete, troca, atendimento…): ícone, título, texto e CTA opcional.\n// Claro (cinza) ou escuro (preto, com o xadrez no canto). Um card só, tudo por parâmetro.\n// Não desenha botão, link nem ícones: reaproveita Button, TextLink e Icon pelos parâmetros `button`, `link` e `iconComponent`.\n// `ctaKind` escolhe o CTA: \"button\" (padrão, botão com contorno/branco) ou \"link\" (TextLink sublinhado, como na página Sobre).\n// O texto de apoio chega por `body` (o nome `text` é reservado do bloco base do Data2).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.ic { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-50: #f5f5f3; --grey-700: #45474b; --text-inv-2: #b9bbbe;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  position: relative; display: flex; flex-direction: column; width: 100%; height: 100%; padding: 36px; overflow: hidden;\n  background: var(--grey-50); color: var(--ink); border-radius: 0; }\n.ic.dark { background: var(--ink); color: var(--white); }\np, h3 { margin: 0; }\n.glyph { width: 32px; height: 32px; flex: none; margin-bottom: 28px; }\n.title { font-size: 24px; line-height: 1.08; font-weight: 800; font-stretch: 115%; text-transform: uppercase; letter-spacing: .005em; }\n.text { margin-top: 12px; font-size: 15px; line-height: 1.55; color: var(--grey-700); max-width: 440px; }\n.dark .text { color: var(--text-inv-2); }\n.cta { margin-top: auto; padding-top: 28px; height: 72px; align-self: flex-start; }\n.cta.as-link { padding-top: 24px; height: 68px; }\n.checker { position: absolute; top: 0; right: 0; width: 60px; height: 60px; pointer-events: none;\n  background: repeating-conic-gradient(var(--white) 0 25%, var(--ink) 0 50%) 0 0 / 60px 60px; }\n.dark .checker { background: repeating-conic-gradient(var(--white) 0 25%, #2a2b2e 0 50%) 0 0 / 60px 60px; }\n\n/* Tablet */\n.l-tablet { padding: 32px; }\n.l-tablet .glyph { margin-bottom: 24px; }\n.l-tablet .title { font-size: 22px; font-stretch: 112%; }\n\n/* Card largo do tablet: ícone e texto à esquerda, CTA à direita */\n.wide.l-tablet { flex-direction: row; align-items: center; gap: 28px; }\n.wide.l-tablet .glyph { margin: 0; }\n.wide.l-tablet .words { flex: 1; min-width: 0; }\n.wide.l-tablet .cta { margin: 0; padding: 0; height: 48px; flex: none; align-self: center; }\n.wide.l-tablet .cta.as-link { height: 44px; }\n.wide.l-tablet .checker { width: 48px; height: 48px; background-size: 48px 48px; }\n\n/* Mobile: botão com largura total; o link continua do tamanho do texto */\n.l-mobile { padding: 28px 24px; }\n.l-mobile .glyph { width: 28px; height: 28px; margin-bottom: 20px; }\n.l-mobile .title { font-size: 20px; font-stretch: 108%; }\n.l-mobile .text { font-size: 14px; margin-top: 10px; }\n.l-mobile .cta { width: 100%; align-self: stretch; padding-top: 24px; height: 68px; }\n.l-mobile .cta.as-link { width: auto; align-self: flex-start; padding-top: 20px; height: 64px; }\n.l-mobile .checker { width: 48px; height: 48px; background-size: 48px 48px; }\n`,\n\n  mounted() {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const mob = layout === 'mobile';\n    const dark = p.tone === 'dark';\n    const wide = truthy(p.wide);\n    const iconRef = refOf(d2.param('iconComponent'));\n    const buttonRef = refOf(d2.param('button'));\n    const linkRef = refOf(d2.param('link'));\n    const asLink = p.ctaKind === 'link' && !!linkRef;\n\n    const glyphName = p.glyph || 'truck';\n    const title = p.title || 'Frete para todo o Brasil';\n    const body = p.body == null ? 'A gente envia para qualquer CEP. Você vê o prazo e o valor antes de fechar o pedido.' : p.body;\n    const ctaLabel = p.ctaLabel || '';\n    const label = mob && p.ctaShortLabel ? p.ctaShortLabel : ctaLabel;\n    const size = mob ? 28 : 32;\n    const fire = () => { try { d2.emit('onCta', p.ctaHref || ''); } catch (err) { /* sem handler */ } };\n\n    const glyph = iconRef\n      ? `<div class=\"glyph\">${d2.render(iconRef, { name: glyphName, size, iconColor: 'currentColor' }, { key: 'glyph', width: size, height: size })}</div>`\n      : '';\n\n    let cta = '';\n    if (ctaLabel && asLink) {\n      cta = `<div class=\"cta as-link\">${d2.render(linkRef, {\n        label, href: p.ctaHref || '', tone: dark ? 'light' : 'dark', layout\n      }, { key: 'cta-link', onClick: fire })}</div>`;\n    } else if (ctaLabel && buttonRef) {\n      cta = `<div class=\"cta\">${d2.render(buttonRef, {\n        label, variant: dark ? 'light' : 'outline', size: 'sm', fullWidth: 'mobile', arrow: true, layout, href: p.ctaHref || ''\n      }, { key: 'cta', onClick: fire })}</div>`;\n    }\n\n    return `<article class=\"ic l-${layout}${dark ? ' dark' : ''}${wide ? ' wide' : ''}\">\n      ${dark ? '<div class=\"checker\" aria-hidden=\"true\"></div>' : ''}\n      ${glyph}\n      <div class=\"words\"><h3 class=\"title\">${esc(title)}</h3>${body ? `<p class=\"text\">${esc(body)}</p>` : ''}</div>\n      ${cta}\n    </article>`;\n  }\n};"}},"body":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"body"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"ctaHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ctaHref"}}}},"ctaKind":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ctaKind"}}}},"ctaLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ctaLabel"}}}},"ctaShortLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ctaShortLabel"}}}},"glyph":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"glyph"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"link":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"link"}}}},"onCta":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCta"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}},"tone":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"tone"}}}},"wide":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"wide"}}}}}}}}}},{"_id":"6ab6d0c42086c2e4341913c7","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"SectionHeader","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// SectionHeader — Loja Lucas Fontana\n// Cabeçalho das seções: eyebrow numerado (\"01 — Categorias\") ou kicker vermelho (\"— Por que comprar aqui\"),\n// título largo em caixa alta e um link opcional à direita (\"Ver tudo\"). No mobile o link some (a seção mostra um botão embaixo).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst pad = (v) => { const n = Number(v); return v !== '' && v != null && Number.isFinite(n) ? (n < 10 ? '0' + n : String(n)) : String(v || ''); };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.sh { --red-500: #c8102e; --ink: #0b0b0c; --grey-500: #6b6e73;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  display: flex; align-items: flex-end; justify-content: space-between; gap: 32px; width: 100%; color: var(--ink); }\np, h2 { margin: 0; }\n.words { min-width: 0; }\n.eyebrow { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; font-size: 12px; font-weight: 700; letter-spacing: .3em; text-transform: uppercase; color: var(--grey-500); }\n.eyebrow b { color: var(--red-500); font-weight: 800; letter-spacing: .1em; }\n.eyebrow i { font-style: normal; color: var(--grey-500); letter-spacing: 0; }\n.eyebrow .dash { display: block; width: 20px; height: 2px; background: var(--red-500); }\n.kicker { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; font-size: 12px; font-weight: 700; letter-spacing: .3em; line-height: 1.3; text-transform: uppercase; color: var(--red-500); }\n.kicker::before { content: ''; width: 22px; height: 3px; background: var(--red-500); flex: none; }\n.title { font-size: 44px; line-height: 1; font-weight: 800; font-stretch: 115%; letter-spacing: -.01em; text-transform: uppercase; }\n.link { flex: none; display: inline-flex; align-items: center; min-height: 44px; color: var(--ink); text-decoration: none;\n  font-size: 12px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; white-space: nowrap; }\n.link span { border-bottom: 2px solid var(--red-500); padding-bottom: 3px; }\n.link:hover { color: var(--red-500); }\n.link:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.l-tablet .title { font-size: 36px; }\n.l-mobile .eyebrow { font-size: 11px; letter-spacing: .26em; margin-bottom: 12px; }\n.l-mobile .kicker { font-size: 11px; letter-spacing: .26em; margin-bottom: 12px; }\n.l-mobile .title { font-size: 28px; line-height: 1.02; font-stretch: 112%; }\n.l-mobile .link { display: none; }\n`,\n\n  mounted(d2) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    d2.on('.link', 'click', () => { try { d2.emit('onAction', d2.params && d2.params.actionHref); } catch (err) { /* sem handler */ } });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const num = pad(p.number);\n    const eyebrow = p.eyebrow == null ? 'Categorias' : p.eyebrow;\n    const title = p.title || 'Por onde a gente começa?';\n    const lead = num ? `<b>${esc(num)}</b><i>—</i>` : '<span class=\"dash\"></span>';\n    const top = !eyebrow ? ''\n      : truthy(p.kicker) ? `<p class=\"kicker\">${esc(eyebrow)}</p>`\n      : `<p class=\"eyebrow\">${lead}${esc(eyebrow)}</p>`;\n    return `<div class=\"sh l-${layout}\">\n      <div class=\"words\">\n        ${top}\n        <h2 class=\"title\">${esc(title)}</h2>\n      </div>\n      ${p.actionLabel ? `<a class=\"link\" href=\"${esc(p.actionHref || '#')}\"><span>${esc(p.actionLabel)}</span></a>` : ''}\n    </div>`;\n  }\n};"}},"actionHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"actionHref"}}}},"actionLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"actionLabel"}}}},"eyebrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"eyebrow"}}}},"kicker":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"kicker"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"number":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"number"}}}},"onAction":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onAction"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}}}}}}}},{"_id":"6ab6e5dee92b0a717903157e","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"docCreateOrder","package":"babi-lf","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    .doc { box-sizing:border-box; font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,sans-serif; background:#f5f5f3; color:#0f172a; min-height:100%; height:100%; overflow-y:auto; padding:48px 24px; }\n    .doc *{ box-sizing:border-box; }\n    .wrap{ max-width:920px; margin:0 auto; }\n    .h1{ font-size:34px; font-weight:800; letter-spacing:-0.02em; margin:0 0 8px; }\n    .sub{ font-size:16px; color:#475569; line-height:1.55; margin:0 0 14px; }\n    .badge{ display:inline-flex; align-items:center; gap:6px; font-size:12px; font-weight:700; color:#b45309; background:#fef3c7; border:1px solid #fde68a; padding:5px 12px; border-radius:999px; text-transform:uppercase; letter-spacing:.05em; }\n    .card{ background:#fff; border:1px solid #e7e7e4; border-radius:16px; padding:22px 26px; margin-top:20px; box-shadow:0 1px 2px rgba(15,23,42,.04); }\n    .card h2{ font-size:19px; font-weight:700; margin:0 0 12px; }\n    .card p{ font-size:14px; line-height:1.6; color:#475569; margin:0 0 4px; }\n    .flow{ font-size:14px; font-weight:600; color:#0f172a; line-height:1.6; margin:0 0 12px; }\n    .chip{ display:inline-block; background:#eef2ff; color:#4338ca; border-radius:6px; padding:1px 7px; font-weight:600; font-family:\"Roboto Mono\",ui-monospace,monospace; font-size:12.5px; }\n    ul{ margin:8px 0 0; padding-left:20px; }\n    li{ font-size:14px; line-height:1.6; color:#475569; margin:4px 0; }\n    code.k{ font-family:\"Roboto Mono\",ui-monospace,monospace; background:#f1f5f9; padding:1px 6px; border-radius:5px; font-size:13px; color:#0f172a; }\n    pre{ background:#0f172a; color:#e2e8f0; border-radius:10px; padding:18px 20px; overflow-x:auto; font-family:\"Roboto Mono\",ui-monospace,SFMono-Regular,monospace; font-size:12.5px; line-height:1.6; margin:12px 0 0; white-space:pre; }\n    table{ width:100%; border-collapse:collapse; margin-top:6px; }\n    th,td{ text-align:left; padding:8px 10px; font-size:13px; border-bottom:1px solid #eef0f2; vertical-align:top; }\n    th{ color:#64748b; font-weight:600; font-size:11px; text-transform:uppercase; letter-spacing:.04em; }\n    td .kk{ font-family:\"Roboto Mono\",ui-monospace,monospace; color:#0f172a; font-weight:600; }\n    .req{ color:#dc2626; font-size:10px; font-weight:700; margin-left:4px; }\n    .warn{ color:#b45309; background:#fffbeb; border:1px solid #fde68a; border-radius:8px; padding:10px 12px; font-size:13px; font-weight:600; margin-top:12px; }\n    .muted{ color:#64748b; font-size:13px; line-height:1.6; margin-top:12px; }\n  `,\n  render() {\n    return `\n      <div class=\"doc\"><div class=\"wrap\">\n        <div class=\"h1\">Criar Order — Mercado Pago</div>\n        <p class=\"sub\">Guia de integração do endpoint interno de criação de pedidos (Checkout Pro Orders). Use como referência para chamar essa criação de qualquer lugar do app.</p>\n        <span class=\"badge\">● Ambiente de TESTE (sandbox)</span>\n\n        <div class=\"card\">\n          <h2>Arquitetura</h2>\n          <p class=\"flow\">Cliente &rarr; Rush Listener (<span class=\"chip\">createOrderHandler</span>) &rarr; HTTP Request (<span class=\"chip\">createOrder</span>) &rarr; API Mercado Pago (POST /v1/orders)</p>\n          <p>Componentes no workspace <b>Mercado Pago</b>:</p>\n          <ul>\n            <li><b>Key Vault</b> <code class=\"k\">mercado-pago-test</code> — guarda <code class=\"k\">ACCESS_TOKEN</code> (token da API) e <code class=\"k\">CreateOrderRush</code> (chave de acesso ao endpoint).</li>\n            <li><b>HTTP Client</b> <code class=\"k\">mercadoPago</code> — base <code class=\"k\">https://api.mercadopago.com</code></li>\n            <li><b>HTTP Request</b> <code class=\"k\">createOrder</code> — POST /v1/orders (dinâmico: recebe data + headers).</li>\n            <li><b>Rush Listener</b> <code class=\"k\">createOrderHandler</code> — ponto de entrada: valida a chave, gera a idempotência, monta o body e chama a API.</li>\n          </ul>\n        </div>\n\n        <div class=\"card\">\n          <h2>Endpoint</h2>\n          <table>\n            <tr><td class=\"kk\">Método</td><td>POST</td></tr>\n            <tr><td class=\"kk\">URL</td><td>https://babi-lf.data2apis.com/rush/createOrderHandler</td></tr>\n            <tr><td class=\"kk\">Content-Type</td><td>application/json</td></tr>\n            <tr><td class=\"kk\">Authorization</td><td>&lt;chave CreateOrderRush&gt;</td></tr>\n          </table>\n        </div>\n\n        <div class=\"card\">\n          <h2>Autenticação</h2>\n          <p>O handler valida a chave <b>antes</b> de criar qualquer order:</p>\n          <ul>\n            <li>Lê o valor de <code class=\"k\">CreateOrderRush</code> no Key Vault (resolvido em runtime dentro do handler).</li>\n            <li>Compara com o header <code class=\"k\">Authorization</code> enviado na chamada.</li>\n            <li>Se não bater (ou faltar) &rarr; responde <code class=\"k\">{ \"error\": \"Unauthorized\" }</code> e <b>não cria order</b>.</li>\n          </ul>\n          <p class=\"muted\">Aceita o header nos dois formatos: <code class=\"k\">Authorization: &lt;chave&gt;</code> ou <code class=\"k\">Authorization: Bearer &lt;chave&gt;</code>. Nunca coloque a chave no front-end público — ela deve vir do backend/vault.</p>\n        </div>\n\n        <div class=\"card\">\n          <h2>Corpo da requisição (body)</h2>\n          <table>\n            <tr><th>Campo</th><th>Tipo</th><th>Descrição</th></tr>\n            <tr><td class=\"kk\">total_amount<span class=\"req\">OBRIGATÓRIO</span></td><td>string</td><td>Valor total do pedido. Ex: \"1000.00\"</td></tr>\n            <tr><td class=\"kk\">external_reference</td><td>string</td><td>Seu identificador do pedido.</td></tr>\n            <tr><td class=\"kk\">payer_email</td><td>string</td><td>E-mail do comprador.</td></tr>\n            <tr><td class=\"kk\">items[]<span class=\"req\">OBRIGATÓRIO</span></td><td>array</td><td>Cada item: title (string), unit_price (string), quantity (número).</td></tr>\n          </table>\n          <p class=\"muted\">Definidos automaticamente pelo handler (não enviar): <code class=\"k\">type=\"online\"</code>, <code class=\"k\">processing_mode=\"manual\"</code>, <code class=\"k\">X-Idempotency-Key</code> (único por chamada) e o Authorization do token da API.</p>\n          <div class=\"warn\">⚠️ NÃO envie <code class=\"k\">unit_measure</code> nem <code class=\"k\">total_amount</code> DENTRO de items — a API rejeita (erro unsupported_properties).</div>\n        </div>\n\n        <div class=\"card\">\n          <h2>Exemplo de chamada</h2>\n          <pre>curl -X POST 'https://babi-lf.data2apis.com/rush/createOrderHandler' \\\\\n  -H 'Content-Type: application/json' \\\\\n  -H 'Authorization: SUA_CHAVE_CreateOrderRush' \\\\\n  -d '{\n    \"total_amount\": \"1000.00\",\n    \"external_reference\": \"order_pro_123\",\n    \"payer_email\": \"buyer@email.com\",\n    \"items\": [\n      { \"title\": \"Meu produto\", \"unit_price\": \"1000.00\", \"quantity\": 1 }\n    ]\n  }'</pre>\n        </div>\n\n        <div class=\"card\">\n          <h2>Resposta de sucesso</h2>\n          <p>Retorna <code class=\"k\">{ \"data\": { \"idempotency_key\": \"...\", \"status\": 201, \"order\": { ... } } }</code>:</p>\n          <table>\n            <tr><th>Campo</th><th>Descrição</th></tr>\n            <tr><td class=\"kk\">idempotency_key</td><td>Chave única gerada pelo handler para esta criação.</td></tr>\n            <tr><td class=\"kk\">status</td><td>Status HTTP devolvido pelo Mercado Pago. <b>201</b> = order criada; 4xx/5xx = erro (os detalhes vêm em <code class=\"k\">order</code>).</td></tr>\n            <tr><td class=\"kk\">order</td><td>A order completa retornada pelo Mercado Pago (ou o corpo do erro).</td></tr>\n          </table>\n          <p style=\"margin-top:12px\">Campos úteis em <code class=\"k\">order</code>:</p>\n          <pre>{\n  \"id\": \"ORDTST01M3D5S9EW932A8S9MNXGYW775\",\n  \"status\": \"created\",\n  \"total_amount\": \"1000.00\",\n  \"checkout_url\": \"https://www.mercadopago.com.br/checkout/v1/redirect?order_id=...\"\n}</pre>\n          <p class=\"muted\">Redirecione o comprador para o <code class=\"k\">checkout_url</code> para concluir o pagamento. Guarde o <code class=\"k\">order.id</code> para consultar o status depois (endpoint <code class=\"k\">getOrderHandler</code>).</p>\n          <div class=\"warn\">⚠️ Mudança de formato: antes a order vinha em <code class=\"k\">order.data</code>, junto com dados internos da chamada. Agora vem direto em <code class=\"k\">order</code> (ex.: <code class=\"k\">order.id</code>, <code class=\"k\">order.checkout_url</code>). Ajuste quem lia <code class=\"k\">order.data.*</code>.</div>\n        </div>\n\n        <div class=\"card\">\n          <h2>Erros comuns</h2>\n          <ul>\n            <li><code class=\"k\">Unauthorized</code> — chave ausente/errada no header Authorization. Nenhuma order é criada.</li>\n            <li><code class=\"k\">unsupported_properties</code> — campos não suportados no body (ex.: unit_measure / total_amount dentro de items).</li>\n            <li><code class=\"k\">idempotency_key_already_used</code> — não deve ocorrer: o handler gera uma chave única por chamada.</li>\n            <li><code class=\"k\">status: 401</code> — problema com o ACCESS_TOKEN do vault (credencial inválida ou vencida).</li>\n            <li>Sempre confira o campo <code class=\"k\">status</code>: se não for 201, a order não foi criada e <code class=\"k\">order</code> traz o erro do Mercado Pago.</li>\n          </ul>\n        </div>\n\n        <div class=\"card\">\n          <h2>Como reutilizar em outros lugares</h2>\n          <p>De um botão no app (onClick) ou de outro Rush handler, chame o listener diretamente:</p>\n          <pre>@createOrderHandler.invoke({\n  body: { total_amount, external_reference, payer_email, items },\n  headers: { Authorization: &lt;chave CreateOrderRush&gt; }\n})</pre>\n          <p class=\"muted\">Endpoints relacionados (mesma chave): <code class=\"k\">getOrderHandler</code> (consultar uma order pelo ID) e <code class=\"k\">searchOrdersHandler</code> (buscar orders por período e filtros).</p>\n          <p class=\"muted\">De um serviço externo (backend/curl): use a URL do endpoint com o header Authorization. Regra de ouro: a chave <code class=\"k\">CreateOrderRush</code> vem do vault/backend, nunca hardcoded no front público.</p>\n        </div>\n\n      </div></div>\n    `\n  }\n}"}}}}}}}},{"_id":"6ab6ee94449a23c1c1376d4f","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"docGetOrder","package":"babi-lf","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    .doc { box-sizing:border-box; font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,sans-serif; background:#f5f5f3; color:#0f172a; min-height:100%; height:100%; overflow-y:auto; padding:48px 24px; }\n    .doc *{ box-sizing:border-box; }\n    .wrap{ max-width:920px; margin:0 auto; }\n    .h1{ font-size:34px; font-weight:800; letter-spacing:-0.02em; margin:0 0 8px; }\n    .sub{ font-size:16px; color:#475569; line-height:1.55; margin:0 0 14px; }\n    .badge{ display:inline-flex; align-items:center; gap:6px; font-size:12px; font-weight:700; color:#b45309; background:#fef3c7; border:1px solid #fde68a; padding:5px 12px; border-radius:999px; text-transform:uppercase; letter-spacing:.05em; }\n    .card{ background:#fff; border:1px solid #e7e7e4; border-radius:16px; padding:22px 26px; margin-top:20px; box-shadow:0 1px 2px rgba(15,23,42,.04); }\n    .card h2{ font-size:19px; font-weight:700; margin:0 0 12px; }\n    .card p{ font-size:14px; line-height:1.6; color:#475569; margin:0 0 4px; }\n    .flow{ font-size:14px; font-weight:600; color:#0f172a; line-height:1.6; margin:0 0 12px; }\n    .chip{ display:inline-block; background:#eef2ff; color:#4338ca; border-radius:6px; padding:1px 7px; font-weight:600; font-family:\"Roboto Mono\",ui-monospace,monospace; font-size:12.5px; }\n    ul{ margin:8px 0 0; padding-left:20px; }\n    li{ font-size:14px; line-height:1.6; color:#475569; margin:4px 0; }\n    code.k{ font-family:\"Roboto Mono\",ui-monospace,monospace; background:#f1f5f9; padding:1px 6px; border-radius:5px; font-size:13px; color:#0f172a; }\n    pre{ background:#0f172a; color:#e2e8f0; border-radius:10px; padding:18px 20px; overflow-x:auto; font-family:\"Roboto Mono\",ui-monospace,SFMono-Regular,monospace; font-size:12.5px; line-height:1.6; margin:12px 0 0; white-space:pre; }\n    table{ width:100%; border-collapse:collapse; margin-top:6px; }\n    th,td{ text-align:left; padding:8px 10px; font-size:13px; border-bottom:1px solid #eef0f2; vertical-align:top; }\n    th{ color:#64748b; font-weight:600; font-size:11px; text-transform:uppercase; letter-spacing:.04em; }\n    td .kk, td.kk{ font-family:\"Roboto Mono\",ui-monospace,monospace; color:#0f172a; font-weight:600; }\n    .req{ color:#dc2626; font-size:10px; font-weight:700; margin-left:4px; }\n    .warn{ color:#b45309; background:#fffbeb; border:1px solid #fde68a; border-radius:8px; padding:10px 12px; font-size:13px; font-weight:600; margin-top:12px; }\n    .muted{ color:#64748b; font-size:13px; line-height:1.6; margin-top:12px; }\n  `,\n  render() {\n    return `\n      <div class=\"doc\"><div class=\"wrap\">\n        <div class=\"h1\">Consultar Order — Mercado Pago</div>\n        <p class=\"sub\">Guia de integração do endpoint interno de consulta de pedidos (Checkout Pro Orders). Use para buscar todos os dados e o status atual de uma order a partir do ID retornado na criação.</p>\n        <span class=\"badge\">● Ambiente de TESTE (sandbox)</span>\n\n        <div class=\"card\">\n          <h2>Arquitetura</h2>\n          <p class=\"flow\">Cliente &rarr; Rush Listener (<span class=\"chip\">getOrderHandler</span>) &rarr; HTTP Request (<span class=\"chip\">getOrder</span>) &rarr; API Mercado Pago (GET /v1/orders/{order_id})</p>\n          <p>Componentes no workspace <b>Mercado Pago</b>:</p>\n          <ul>\n            <li><b>Key Vault</b> <code class=\"k\">mercado-pago-test</code> — guarda <code class=\"k\">ACCESS_TOKEN</code> (token da API) e <code class=\"k\">CreateOrderRush</code> (chave de acesso ao endpoint, a mesma do Criar Order).</li>\n            <li><b>HTTP Client</b> <code class=\"k\">mercadoPago</code> — base <code class=\"k\">https://api.mercadopago.com</code></li>\n            <li><b>HTTP Request</b> <code class=\"k\">getOrder</code> — GET /v1/orders/{order_id} (dinâmico: recebe url + headers).</li>\n            <li><b>Rush Listener</b> <code class=\"k\">getOrderHandler</code> — ponto de entrada: valida a chave, valida o order_id, injeta o token e chama a API.</li>\n          </ul>\n        </div>\n\n        <div class=\"card\">\n          <h2>Endpoint</h2>\n          <table>\n            <tr><td class=\"kk\">Método</td><td>GET (também aceita POST com o order_id no body)</td></tr>\n            <tr><td class=\"kk\">URL</td><td>https://babi-lf.data2apis.com/rush/getOrderHandler?order_id=&lt;ID&gt;</td></tr>\n            <tr><td class=\"kk\">Authorization</td><td>&lt;chave CreateOrderRush&gt;</td></tr>\n          </table>\n        </div>\n\n        <div class=\"card\">\n          <h2>Autenticação</h2>\n          <p>O handler valida a chave <b>antes</b> de consultar qualquer order:</p>\n          <ul>\n            <li>Lê o valor de <code class=\"k\">CreateOrderRush</code> no Key Vault (resolvido em runtime dentro do handler).</li>\n            <li>Compara com o header <code class=\"k\">Authorization</code> enviado na chamada.</li>\n            <li>Se não bater (ou faltar) &rarr; responde <code class=\"k\">{ \"error\": \"Unauthorized\" }</code> e <b>não chama o Mercado Pago</b>.</li>\n          </ul>\n          <p class=\"muted\">Aceita o header nos dois formatos: <code class=\"k\">Authorization: &lt;chave&gt;</code> ou <code class=\"k\">Authorization: Bearer &lt;chave&gt;</code>. Nunca coloque a chave no front-end público — ela deve vir do backend/vault. A resposta traz dados do comprador e do pagamento, por isso o endpoint é protegido.</p>\n        </div>\n\n        <div class=\"card\">\n          <h2>Parâmetros</h2>\n          <table>\n            <tr><th>Campo</th><th>Onde</th><th>Descrição</th></tr>\n            <tr><td class=\"kk\">order_id<span class=\"req\">OBRIGATÓRIO</span></td><td>query (ou body)</td><td>ID da order retornado no <code class=\"k\">order.id</code> da criação. Ex: \"ORDTST01M3D7PXZ6XEYQFCMY7HY9VSA4\"</td></tr>\n          </table>\n          <p class=\"muted\">Definido automaticamente pelo handler (não enviar): o Authorization com o <code class=\"k\">ACCESS_TOKEN</code> da API do Mercado Pago.</p>\n          <div class=\"warn\">⚠️ O order_id só pode ter letras e números. Qualquer outro caractere (/, espaço, ?, etc.) é recusado com Bad Request antes de chamar a API.</div>\n        </div>\n\n        <div class=\"card\">\n          <h2>Exemplo de chamada</h2>\n          <pre>curl -X GET 'https://babi-lf.data2apis.com/rush/getOrderHandler?order_id=ORDTST01M3D7PXZ6XEYQFCMY7HY9VSA4' \\\\\n  -H 'Authorization: SUA_CHAVE_CreateOrderRush'</pre>\n        </div>\n\n        <div class=\"card\">\n          <h2>Resposta de sucesso</h2>\n          <p>Retorna <code class=\"k\">{ \"data\": { \"status\": 200, \"order\": { ... } } }</code>, com a order completa do Mercado Pago. Campos mais úteis em <code class=\"k\">order</code>:</p>\n          <pre>{\n  \"id\": \"ORDTST01M3D7PXZ6XEYQFCMY7HY9VSA4\",\n  \"status\": \"created\",\n  \"status_detail\": \"...\",\n  \"external_reference\": \"order_auth_test\",\n  \"total_amount\": \"1000.00\",\n  \"checkout_url\": \"https://www.mercadopago.com.br/checkout/v1/redirect?order_id=...\",\n  \"items\": [ { \"title\": \"Meu produto\", \"unit_price\": \"1000.00\", \"quantity\": 1 } ]\n}</pre>\n          <p class=\"muted\">Use <code class=\"k\">order.status</code> para saber em que pé está o pedido: <code class=\"k\">created</code> (criada, aguardando pagamento), <code class=\"k\">processed</code> (pagamento processado) ou <code class=\"k\">action_required</code> (precisa de ação do integrador). O campo <code class=\"k\">status</code> fora da order é o status HTTP devolvido pelo Mercado Pago.</p>\n        </div>\n\n        <div class=\"card\">\n          <h2>Erros comuns</h2>\n          <ul>\n            <li><code class=\"k\">Unauthorized</code> — chave ausente/errada no header Authorization. O Mercado Pago não é chamado.</li>\n            <li><code class=\"k\">Bad Request</code> — order_id ausente ou com caracteres inválidos.</li>\n            <li><code class=\"k\">status: 404</code> / <code class=\"k\">order_not_found</code> — o ID não existe (ou é de outro ambiente/conta).</li>\n            <li><code class=\"k\">status: 401</code> — problema com o ACCESS_TOKEN do vault (credencial inválida ou vencida).</li>\n          </ul>\n        </div>\n\n        <div class=\"card\">\n          <h2>Como reutilizar em outros lugares</h2>\n          <p>De um botão no app (onClick) ou de outro Rush handler, chame o listener diretamente:</p>\n          <pre>@getOrderHandler.invoke({\n  body: { order_id },\n  headers: { Authorization: &lt;chave CreateOrderRush&gt; }\n})</pre>\n          <p class=\"muted\">Fluxo típico: guarde o <code class=\"k\">order.id</code> retornado pelo Criar Order e use este endpoint para checar o status depois que o comprador volta do checkout. Regra de ouro: a chave <code class=\"k\">CreateOrderRush</code> vem do vault/backend, nunca hardcoded no front público.</p>\n        </div>\n\n      </div></div>\n    `\n  }\n}"}}}}}}}},{"_id":"6ab6ef326b9804cbc48b26d3","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"docSearchOrders","package":"babi-lf","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    .doc { box-sizing:border-box; font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,sans-serif; background:#f5f5f3; color:#0f172a; min-height:100%; height:100%; overflow-y:auto; padding:48px 24px; }\n    .doc *{ box-sizing:border-box; }\n    .wrap{ max-width:920px; margin:0 auto; }\n    .h1{ font-size:34px; font-weight:800; letter-spacing:-0.02em; margin:0 0 8px; }\n    .sub{ font-size:16px; color:#475569; line-height:1.55; margin:0 0 14px; }\n    .badge{ display:inline-flex; align-items:center; gap:6px; font-size:12px; font-weight:700; color:#b45309; background:#fef3c7; border:1px solid #fde68a; padding:5px 12px; border-radius:999px; text-transform:uppercase; letter-spacing:.05em; }\n    .card{ background:#fff; border:1px solid #e7e7e4; border-radius:16px; padding:22px 26px; margin-top:20px; box-shadow:0 1px 2px rgba(15,23,42,.04); }\n    .card h2{ font-size:19px; font-weight:700; margin:0 0 12px; }\n    .card p{ font-size:14px; line-height:1.6; color:#475569; margin:0 0 4px; }\n    .flow{ font-size:14px; font-weight:600; color:#0f172a; line-height:1.6; margin:0 0 12px; }\n    .chip{ display:inline-block; background:#eef2ff; color:#4338ca; border-radius:6px; padding:1px 7px; font-weight:600; font-family:\"Roboto Mono\",ui-monospace,monospace; font-size:12.5px; }\n    ul{ margin:8px 0 0; padding-left:20px; }\n    li{ font-size:14px; line-height:1.6; color:#475569; margin:4px 0; }\n    code.k{ font-family:\"Roboto Mono\",ui-monospace,monospace; background:#f1f5f9; padding:1px 6px; border-radius:5px; font-size:13px; color:#0f172a; }\n    pre{ background:#0f172a; color:#e2e8f0; border-radius:10px; padding:18px 20px; overflow-x:auto; font-family:\"Roboto Mono\",ui-monospace,SFMono-Regular,monospace; font-size:12.5px; line-height:1.6; margin:12px 0 0; white-space:pre; }\n    table{ width:100%; border-collapse:collapse; margin-top:6px; }\n    th,td{ text-align:left; padding:8px 10px; font-size:13px; border-bottom:1px solid #eef0f2; vertical-align:top; }\n    th{ color:#64748b; font-weight:600; font-size:11px; text-transform:uppercase; letter-spacing:.04em; }\n    td .kk, td.kk{ font-family:\"Roboto Mono\",ui-monospace,monospace; color:#0f172a; font-weight:600; }\n    .req{ color:#dc2626; font-size:10px; font-weight:700; margin-left:4px; }\n    .warn{ color:#b45309; background:#fffbeb; border:1px solid #fde68a; border-radius:8px; padding:10px 12px; font-size:13px; font-weight:600; margin-top:12px; }\n    .muted{ color:#64748b; font-size:13px; line-height:1.6; margin-top:12px; }\n  `,\n  render() {\n    return `\n      <div class=\"doc\"><div class=\"wrap\">\n        <div class=\"h1\">Buscar Orders — Mercado Pago</div>\n        <p class=\"sub\">Guia de integração do endpoint interno de busca de pedidos (Checkout Pro Orders). Use para listar orders por período de criação, com filtros opcionais e paginação.</p>\n        <span class=\"badge\">● Ambiente de TESTE (sandbox)</span>\n\n        <div class=\"card\">\n          <h2>Arquitetura</h2>\n          <p class=\"flow\">Cliente &rarr; Rush Listener (<span class=\"chip\">searchOrdersHandler</span>) &rarr; HTTP Request (<span class=\"chip\">searchOrders</span>) &rarr; API Mercado Pago (GET /v1/orders)</p>\n          <p>Componentes no workspace <b>Mercado Pago</b>:</p>\n          <ul>\n            <li><b>Key Vault</b> <code class=\"k\">mercado-pago-test</code> — guarda <code class=\"k\">ACCESS_TOKEN</code> (token da API) e <code class=\"k\">CreateOrderRush</code> (chave de acesso ao endpoint, a mesma do Criar Order).</li>\n            <li><b>HTTP Client</b> <code class=\"k\">mercadoPago</code> — base <code class=\"k\">https://api.mercadopago.com</code></li>\n            <li><b>HTTP Request</b> <code class=\"k\">searchOrders</code> — GET /v1/orders (dinâmico: recebe url + headers).</li>\n            <li><b>Rush Listener</b> <code class=\"k\">searchOrdersHandler</code> — ponto de entrada: valida a chave, valida os filtros, monta a URL de busca, injeta o token e chama a API.</li>\n          </ul>\n        </div>\n\n        <div class=\"card\">\n          <h2>Endpoint</h2>\n          <table>\n            <tr><td class=\"kk\">Método</td><td>GET (também aceita POST com os filtros no body)</td></tr>\n            <tr><td class=\"kk\">URL</td><td>https://babi-lf.data2apis.com/rush/searchOrdersHandler?begin_date=...&amp;end_date=...</td></tr>\n            <tr><td class=\"kk\">Authorization</td><td>&lt;chave CreateOrderRush&gt;</td></tr>\n          </table>\n        </div>\n\n        <div class=\"card\">\n          <h2>Autenticação</h2>\n          <p>O handler valida a chave <b>antes</b> de buscar qualquer order:</p>\n          <ul>\n            <li>Lê o valor de <code class=\"k\">CreateOrderRush</code> no Key Vault (resolvido em runtime dentro do handler).</li>\n            <li>Compara com o header <code class=\"k\">Authorization</code> enviado na chamada.</li>\n            <li>Se não bater (ou faltar) &rarr; responde <code class=\"k\">{ \"error\": \"Unauthorized\" }</code> e <b>não chama o Mercado Pago</b>.</li>\n          </ul>\n          <p class=\"muted\">Aceita o header nos dois formatos: <code class=\"k\">Authorization: &lt;chave&gt;</code> ou <code class=\"k\">Authorization: Bearer &lt;chave&gt;</code>. Nunca coloque a chave no front-end público — a busca devolve orders de todos os compradores.</p>\n        </div>\n\n        <div class=\"card\">\n          <h2>Filtros</h2>\n          <table>\n            <tr><th>Campo</th><th>Formato</th><th>Descrição</th></tr>\n            <tr><td class=\"kk\">begin_date<span class=\"req\">OBRIGATÓRIO</span></td><td>RFC 3339</td><td>Início do período de criação. Ex: \"2026-09-25T00:00:00Z\"</td></tr>\n            <tr><td class=\"kk\">end_date<span class=\"req\">OBRIGATÓRIO</span></td><td>RFC 3339</td><td>Fim do período de criação. Ex: \"2026-09-26T00:00:00Z\"</td></tr>\n            <tr><td class=\"kk\">external_reference</td><td>string</td><td>Seu identificador do pedido (o mesmo enviado no Criar Order). Letras, números, _ ou -, até 64.</td></tr>\n            <tr><td class=\"kk\">status</td><td>string</td><td>Status da order: <code class=\"k\">created</code>, <code class=\"k\">processed</code>, <code class=\"k\">action_required</code>…</td></tr>\n            <tr><td class=\"kk\">limit</td><td>número</td><td>Quantidade por página.</td></tr>\n            <tr><td class=\"kk\">offset</td><td>número</td><td>A partir de qual resultado (paginação).</td></tr>\n          </table>\n          <p class=\"muted\">Pode enviar os filtros na query (GET) ou no body (POST). O handler cuida do encoding das datas e injeta o Authorization com o <code class=\"k\">ACCESS_TOKEN</code> — não enviar.</p>\n          <div class=\"warn\">⚠️ Qualquer filtro fora do formato é recusado com Bad Request antes de chamar a API. Datas precisam do horário e do fuso (Z ou ±hh:mm).</div>\n        </div>\n\n        <div class=\"card\">\n          <h2>Exemplo de chamada</h2>\n          <pre>curl -X GET 'https://babi-lf.data2apis.com/rush/searchOrdersHandler?begin_date=2026-09-25T00:00:00Z&amp;end_date=2026-09-26T00:00:00Z&amp;status=created&amp;limit=10' \\\\\n  -H 'Authorization: SUA_CHAVE_CreateOrderRush'</pre>\n        </div>\n\n        <div class=\"card\">\n          <h2>Resposta de sucesso</h2>\n          <p>Retorna <code class=\"k\">{ \"data\": { \"status\": 200, \"result\": { \"data\": [ ... ], \"paging\": { ... } } } }</code>:</p>\n          <table>\n            <tr><th>Campo</th><th>Descrição</th></tr>\n            <tr><td class=\"kk\">status</td><td>Status HTTP devolvido pelo Mercado Pago. <b>200</b> = busca ok; 4xx/5xx = erro (detalhes em <code class=\"k\">result</code>).</td></tr>\n            <tr><td class=\"kk\">result.data[]</td><td>Lista de orders encontradas.</td></tr>\n            <tr><td class=\"kk\">result.paging</td><td>total, total_pages, offset e limit.</td></tr>\n          </table>\n          <pre>{\n  \"status\": 200,\n  \"result\": {\n    \"data\": [\n      {\n        \"id\": \"ORDTST01M3D7PXZ6XEYQFCMY7HY9VSA4\",\n        \"external_reference\": \"order_auth_test\",\n        \"status\": \"created\",\n        \"total_amount\": \"1000.00\",\n        \"created_date\": \"2026-09-25T21:31:59.86Z\",\n        \"items\": [ { \"title\": \"Meu produto\", \"unit_price\": \"1000.00\", \"quantity\": 1 } ]\n      }\n    ],\n    \"paging\": { \"total\": \"3\", \"total_pages\": \"1\", \"offset\": \"0\", \"limit\": \"20\" }\n  }\n}</pre>\n        </div>\n\n        <div class=\"card\">\n          <h2>Erros comuns</h2>\n          <ul>\n            <li><code class=\"k\">Unauthorized</code> — chave ausente/errada no header Authorization. O Mercado Pago não é chamado.</li>\n            <li><code class=\"k\">Bad Request</code> — begin_date/end_date ausentes ou algum filtro fora do formato.</li>\n            <li><code class=\"k\">status: 400</code> / <code class=\"k\">invalid_parameter</code> — o Mercado Pago recusou algum valor (ex.: período inválido).</li>\n            <li><code class=\"k\">status: 401</code> — problema com o ACCESS_TOKEN do vault (credencial inválida ou vencida).</li>\n          </ul>\n        </div>\n\n        <div class=\"card\">\n          <h2>Como reutilizar em outros lugares</h2>\n          <p>De um botão no app (onClick) ou de outro Rush handler, chame o listener diretamente:</p>\n          <pre>@searchOrdersHandler.invoke({\n  body: { begin_date, end_date, status, external_reference, limit, offset },\n  headers: { Authorization: &lt;chave CreateOrderRush&gt; }\n})</pre>\n          <p class=\"muted\">Usos típicos: relatório de vendas do dia, conciliação por <code class=\"k\">external_reference</code> e listar orders pendentes (<code class=\"k\">status=created</code>). Para detalhes completos de uma order, use o <code class=\"k\">getOrderHandler</code> com o <code class=\"k\">id</code>. Regra de ouro: a chave <code class=\"k\">CreateOrderRush</code> vem do vault/backend, nunca hardcoded no front público.</p>\n        </div>\n\n      </div></div>\n    `\n  }\n}"}}}}}}}},{"_id":"6ab92bb295248f62d4cc596d","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"TextLink","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// TextLink — Loja Lucas Fontana\n// O link em caixa alta com o sublinhado vermelho de 2px (\"Ver tudo\", \"Deixar uma mensagem\", \"Conheça a história\").\n// A área de toque tem no mínimo 44px de altura; só o texto é sublinhado.\n// `variant: inline` é o link discreto em caixa normal para ações utilitárias (\"Limpar tudo\", \"Limpar filtros\").\nconst LAYOUTS = ['desktop', 'tablet', 'mobile', 'auto'];\nconst TONES = ['dark', 'light', 'red'];\nconst VARIANTS = ['default', 'inline'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst pick = (v, list, fb) => (list.indexOf(String(v)) >= 0 ? String(v) : fb);\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst ARROW = '<svg class=\"ic\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M5 12h14M13 6l6 6-6 6\"/></svg>';\n\nexport default {\n  css: `\n:host { display: block; }\n* { box-sizing: border-box; }\n.wrap { --red-500: #c8102e; --red-300: #ff4d62; --ink: #0b0b0c; --white: #ffffff;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased; display: block; }\n.lk { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; margin: 0; padding: 0; background: none; border: 0; cursor: pointer;\n  font-family: inherit; font-size: 13px; font-weight: 700; letter-spacing: .1em; line-height: 1.2; text-transform: uppercase;\n  color: var(--ink); text-decoration: none; white-space: nowrap; transition: color .15s ease; }\n.lk > span { border-bottom: 2px solid var(--red-500); padding-bottom: 4px; }\n.lk .ic { width: 16px; height: 16px; flex: none; }\n.lk:hover { color: var(--red-500); }\n.lk:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.t-light { color: var(--white); }\n.t-light:hover { color: var(--red-300); }\n.t-light:focus-visible { outline-color: var(--white); }\n.t-red { color: var(--red-500); }\n.t-red > span { border: 0; padding: 0; }\n.t-red:hover { color: var(--ink); }\n.v-inline { min-height: 32px; font-size: 14px; font-weight: 600; letter-spacing: 0; text-transform: none; }\n.v-inline > span { border-bottom: 1.5px solid currentColor; padding-bottom: 1px; }\n.l-tablet .lk:not(.v-inline), .l-mobile .lk:not(.v-inline) { font-size: 12px; }\n@media (max-width: 1199px) { .l-auto .lk:not(.v-inline) { font-size: 12px; } }\n`,\n\n  mounted(d2) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    d2.on('.lk', 'click', (e, el) => {\n      if (el.tagName === 'BUTTON') { try { d2.emit('onClick'); } catch (err) { /* sem handler */ } }\n    });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = pick(p.layout, LAYOUTS, 'auto');\n    const tone = pick(p.tone, TONES, 'dark');\n    const variant = pick(p.variant, VARIANTS, 'default');\n    const label = p.label || 'Ver tudo';\n    const href = p.href ? String(p.href) : '';\n    const cls = `lk t-${tone} v-${variant}`;\n    const inner = `<span>${esc(label)}</span>${truthy(p.arrow) ? ARROW : ''}`;\n    const el = href\n      ? `<a class=\"${cls}\" href=\"${esc(href)}\"${truthy(p.newTab) ? ' target=\"_blank\" rel=\"noopener\"' : ''}>${inner}</a>`\n      : `<button type=\"button\" class=\"${cls}\">${inner}</button>`;\n    return `<div class=\"wrap l-${layout}\">${el}</div>`;\n  }\n};"}},"arrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"arrow"}}}},"href":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"href"}}}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"newTab":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"newTab"}}}},"onClick":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onClick"}}}},"tone":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"tone"}}}},"variant":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"variant"}}}}}}}}}},{"_id":"6ab92bdae69f22645a56e5a3","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Breadcrumb","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Breadcrumb — Loja Lucas Fontana\n// A trilha acima do título da página: \"Início / Cuidado automotivo\".\n// Passos anteriores são links cinza; a página atual é preta, 600, e não é link.\n// No mobile fica numa linha só e rola para o lado (nomes de produto longos); `scroll: false` deixa quebrar.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst norm = (it) => (it && typeof it === 'object' ? { label: it.label || '', href: it.href || '' } : { label: String(it || ''), href: '' });\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.bc { --red-500: #c8102e; --ink: #0b0b0c; --grey-500: #6b6e73;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased; width: 100%; }\nol { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: 14px; line-height: 1.4; }\nli { display: flex; align-items: center; gap: 8px; color: var(--grey-500); }\nli + li::before { content: '/'; color: var(--grey-500); }\na { color: var(--grey-500); text-decoration: none; }\na:hover { color: var(--red-500); }\na:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n[aria-current] { color: var(--ink); font-weight: 600; }\n.l-mobile ol { font-size: 13px; }\n.scroll ol { flex-wrap: nowrap; overflow-x: auto; white-space: nowrap; scrollbar-width: thin; padding-bottom: 6px; }\n.scroll li { flex-shrink: 0; }\n`,\n\n  mounted(d2) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    d2.on('a', 'click', (e, el) => { try { d2.emit('onNavigate', el.getAttribute('href')); } catch (err) { /* sem handler */ } });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    let items = list(p.items).map(norm).filter((i) => i.label);\n    if (!items.length) items = [{ label: 'Início', href: '/' }, { label: 'Página atual', href: '' }];\n    const scroll = layout === 'mobile' && !(p.scroll === false || p.scroll === 'false');\n    const last = items.length - 1;\n    const lis = items.map((it, i) => {\n      if (i === last) return `<li><span aria-current=\"page\">${esc(it.label)}</span></li>`;\n      return it.href ? `<li><a href=\"${esc(it.href)}\">${esc(it.label)}</a></li>` : `<li><span>${esc(it.label)}</span></li>`;\n    }).join('');\n    return `<nav class=\"bc l-${layout}${scroll ? ' scroll' : ''}\" aria-label=\"Você está em\"><ol>${lis}</ol></nav>`;\n  }\n};"}},"items":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"items"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onNavigate":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onNavigate"}}}},"scroll":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"scroll"}}}}}}}}}},{"_id":"6ab92bf97a2786dc7b34d7f6","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"AboutHero","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// AboutHero — Loja Lucas Fontana\n// A abertura de \"Sobre o Lucas\": breadcrumb, kicker vermelho, título em duas linhas com a segunda em\n// vermelho itálico (\"Prazer, / Lucas Fontana.\"), apresentação curta e dois botões, ao lado de um retrato\n// com a régua vermelha embaixo. Não desenha breadcrumb nem botão: usa Breadcrumb e Button por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst IMG = '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"1\"/><circle cx=\"9\" cy=\"10\" r=\"2\"/><path d=\"m21 16-5-5-9 8\"/></svg>';\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.ah { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-300: #a7a9ad; --grey-700: #45474b; --graphite-900: #1c1d1f;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  width: 100%; height: 100%; background: var(--white); color: var(--ink); }\np, h1 { margin: 0; }\n.in { padding: 56px 96px 88px; display: grid; grid-template-columns: minmax(0, 1fr) 560px; gap: 64px; align-items: center; }\n.copy { display: flex; flex-direction: column; gap: 16px; min-width: 0; }\n.crumb { height: 24px; margin-bottom: 8px; }\n.kicker { display: flex; align-items: center; gap: 12px; font-size: 12px; font-weight: 700; letter-spacing: .3em; line-height: 1.3; text-transform: uppercase; color: var(--red-500); }\n.kicker::before { content: ''; width: 22px; height: 3px; background: var(--red-500); flex: none; }\n.title { margin: 4px 0 8px; font-size: 54px; font-weight: 800; font-stretch: 118%; line-height: .98; letter-spacing: -.015em; text-transform: uppercase; }\n.title em { display: block; font-style: italic; color: var(--red-500); }\n.text { max-width: 640px; font-size: 18px; line-height: 1.6; color: var(--grey-700); }\n.actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 12px; }\n.act { flex: none; height: 52px; }\n.media { position: relative; aspect-ratio: 560 / 600; background: var(--graphite-900); border-bottom: 6px solid var(--red-500);\n  display: flex; align-items: center; justify-content: center; overflow: hidden; }\n.media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }\n.ph { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 0 24px; text-align: center;\n  color: var(--grey-300); font-size: 12px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; }\n.ph svg { width: 28px; height: 28px; }\n\n.l-tablet .in { padding: 40px 40px 64px; grid-template-columns: minmax(0, 1fr) 300px; gap: 40px; }\n.l-tablet .title { font-size: 40px; font-stretch: 115%; letter-spacing: -.01em; }\n.l-tablet .text { font-size: 17px; }\n.l-tablet .media { border-bottom-width: 5px; }\n\n.l-mobile .in { padding: 24px 20px 48px; grid-template-columns: minmax(0, 1fr); gap: 32px; }\n.l-mobile .crumb { height: 30px; margin-bottom: 4px; }\n.l-mobile .kicker { font-size: 11px; letter-spacing: .26em; }\n.l-mobile .title { font-size: 34px; font-stretch: 110%; line-height: 1; }\n.l-mobile .text { font-size: 15px; }\n.l-mobile .actions { flex-direction: column; }\n.l-mobile .act { width: 100%; }\n.l-mobile .media { aspect-ratio: 4 / 5; border-bottom-width: 5px; }\n`,\n\n  mounted() {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const mob = layout === 'mobile';\n    const bcRef = refOf(d2.param('breadcrumb'));\n    const btnRef = refOf(d2.param('button'));\n\n    const crumbs = list(p.crumbs).length ? list(p.crumbs) : [{ label: 'Início', href: '/' }, { label: 'Sobre o Lucas Fontana' }];\n    const eyebrow = p.eyebrow == null ? 'Sobre o Lucas' : p.eyebrow;\n    const title = p.title || 'Prazer,';\n    const accent = p.titleAccent == null ? 'Lucas Fontana.' : p.titleAccent;\n    const body = p.body == null ? '[Apresentação curta do Lucas em 2 ou 3 frases: quem é, o que faz no canal e o jeito dele de falar de carro.]' : p.body;\n    const pLabel = p.primaryLabel == null ? 'Assistir no YouTube' : p.primaryLabel;\n    const sLabel = p.secondaryLabel == null ? 'Ver a loja' : p.secondaryLabel;\n\n    const btn = (key, label, variant, glyph, href, evt) => d2.render(btnRef, {\n      label, variant, size: 'lg', glyph: glyph || '', fullWidth: mob ? 'always' : 'auto', layout, href: href || '', newTab: /^https?:/.test(href || '')\n    }, { key, onClick: () => { try { d2.emit(evt, href || ''); } catch (err) { /* sem handler */ } } });\n\n    const actions = btnRef && (pLabel || sLabel) ? `<div class=\"actions\">\n        ${pLabel ? `<div class=\"act\">${btn('primary', pLabel, 'brand', p.primaryGlyph == null ? 'youtube' : p.primaryGlyph, p.primaryHref, 'onPrimary')}</div>` : ''}\n        ${sLabel ? `<div class=\"act\">${btn('secondary', sLabel, 'outline', '', p.secondaryHref || '/', 'onSecondary')}</div>` : ''}\n      </div>` : '';\n\n    const crumb = bcRef ? `<div class=\"crumb\">${d2.render(bcRef, { items: crumbs, layout }, { key: 'bc' })}</div>` : '';\n    const media = p.image\n      ? `<img src=\"${esc(p.image)}\" alt=\"${esc(p.imageAlt || 'Lucas Fontana')}\">`\n      : `<div class=\"ph\">${IMG}<span>${esc(p.placeholder || 'Retrato do Lucas')}</span></div>`;\n\n    return `<section class=\"ah l-${layout}\"><div class=\"in\">\n      <div class=\"copy\">\n        ${crumb}\n        ${eyebrow ? `<p class=\"kicker\">${esc(eyebrow)}</p>` : ''}\n        <h1 class=\"title\">${esc(title)}${accent ? `<em>${esc(accent)}</em>` : ''}</h1>\n        ${body ? `<p class=\"text\">${esc(body)}</p>` : ''}\n        ${actions}\n      </div>\n      <div class=\"media\">${media}</div>\n    </div></section>`;\n  }\n};"}},"body":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"body"}}}},"breadcrumb":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"breadcrumb"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"crumbs":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"crumbs"}}}},"eyebrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"eyebrow"}}}},"image":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"image"}}}},"imageAlt":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"imageAlt"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onPrimary":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onPrimary"}}}},"onSecondary":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSecondary"}}}},"placeholder":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"placeholder"}}}},"primaryGlyph":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"primaryGlyph"}}}},"primaryHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"primaryHref"}}}},"primaryLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"primaryLabel"}}}},"secondaryHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"secondaryHref"}}}},"secondaryLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"secondaryLabel"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}},"titleAccent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"titleAccent"}}}}}}}}}},{"_id":"6ab92c098b1ad6cc3e92d8e2","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"StatBand","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// StatBand — Loja Lucas Fontana\n// Faixa preta com os números do canal: cada número tem uma régua vermelha de 3px à esquerda,\n// o valor em display itálico largo e um rótulo cinza. Xadrez discreto no canto superior direito.\n// 4 lado a lado no desktop; 2 × 2 no tablet e no mobile.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst DEFAULTS = [\n  { value: '[000 mil]', label: 'inscritos no YouTube' },\n  { value: '[000 mil]', label: 'seguidores no Instagram' },\n  { value: '[00 mi]', label: 'de visualizações' },\n  { value: '[000]', label: 'vídeos publicados' }\n];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.sb { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-300: #a7a9ad;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  position: relative; width: 100%; height: 100%; background: var(--ink); color: var(--white); overflow: hidden; }\n.checker { position: absolute; top: 0; right: 0; width: 180px; height: 60px; pointer-events: none;\n  background: repeating-conic-gradient(rgba(255,255,255,.06) 0 25%, transparent 0 50%) 0 0 / 30px 30px; }\n.in { position: relative; padding: 56px 96px; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 32px; margin: 0; list-style: none; }\n.stat { display: flex; flex-direction: column; gap: 6px; padding-left: 16px; border-left: 3px solid var(--red-500); min-width: 0; }\n.stat b { font-size: 40px; font-weight: 800; font-style: italic; font-stretch: 125%; line-height: 1; white-space: nowrap; }\n.stat span { font-size: 14px; line-height: 1.35; color: var(--grey-300); }\n.l-tablet .in { padding: 48px 40px; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px 24px; }\n.l-mobile .in { padding: 40px 20px; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px 16px; }\n.l-mobile .stat { padding-left: 12px; }\n.l-mobile .stat b { font-size: 26px; font-stretch: 115%; }\n.l-mobile .stat span { font-size: 13px; }\n.l-mobile .checker { width: 96px; height: 48px; background-size: 24px 24px; }\n`,\n\n  mounted() {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const given = list(p.items).filter((i) => i && typeof i === 'object');\n    const items = (given.length ? given : DEFAULTS).slice(0, 4);\n    return `<section class=\"sb l-${layout}\" aria-label=\"O canal em números\">\n      <div class=\"checker\" aria-hidden=\"true\"></div>\n      <ul class=\"in\">${items.map((s) => `<li class=\"stat\"><b>${esc(s.value)}</b><span>${esc(s.label)}</span></li>`).join('')}</ul>\n    </section>`;\n  }\n};"}},"items":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"items"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}}}}}}}},{"_id":"6ab92c21b6119616261ffb00","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"MediaText","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// MediaText — Loja Lucas Fontana\n// Uma foto ao lado de um kicker vermelho, um título em caixa alta e um ou dois parágrafos\n// (\"A história / Da garagem pro canal. Do canal pra sua garagem.\").\n// Duas colunas iguais no desktop e no tablet (`flip` põe a foto à direita); empilhado, foto primeiro, no mobile.\n// O bloco ocupa só a largura do conteúdo: posicione-o no gutter da página (96 / 40 / 20px).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : [v]; } catch (e) { return [v]; } }\n  return [];\n};\nconst IMG = '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"1\"/><circle cx=\"9\" cy=\"10\" r=\"2\"/><path d=\"m21 16-5-5-9 8\"/></svg>';\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.mt { --red-500: #c8102e; --ink: #0b0b0c; --grey-100: #ececea; --grey-500: #6b6e73; --grey-700: #45474b;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  width: 100%; height: 100%; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 64px; align-items: center; color: var(--ink); background: #ffffff; }\np, h2 { margin: 0; }\n.media { position: relative; aspect-ratio: 592 / 460; background: var(--grey-100); display: flex; align-items: center; justify-content: center; overflow: hidden; }\n.media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }\n.ph { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 0 24px; text-align: center;\n  color: var(--grey-500); font-size: 12px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; }\n.ph svg { width: 28px; height: 28px; }\n.copy { display: flex; flex-direction: column; gap: 16px; min-width: 0; }\n.kicker { display: flex; align-items: center; gap: 12px; font-size: 12px; font-weight: 700; letter-spacing: .3em; line-height: 1.3; text-transform: uppercase; color: var(--red-500); }\n.kicker::before { content: ''; width: 22px; height: 3px; background: var(--red-500); flex: none; }\n.title { margin: 0 0 4px; font-size: 44px; font-weight: 800; font-stretch: 115%; line-height: 1; letter-spacing: -.01em; text-transform: uppercase; }\n.copy p.body { font-size: 17px; line-height: 1.65; color: var(--grey-700); }\n.flip .media { order: 2; }\n.l-tablet { gap: 40px; }\n.l-tablet .title { font-size: 32px; }\n.l-tablet .copy p.body { font-size: 16px; }\n.l-mobile { grid-template-columns: minmax(0, 1fr); gap: 28px; align-items: start; align-content: start; }\n.l-mobile.flip .media { order: 0; }\n.l-mobile .kicker { font-size: 11px; letter-spacing: .26em; }\n.l-mobile .title { font-size: 28px; font-stretch: 112%; letter-spacing: 0; }\n.l-mobile .copy p.body { font-size: 15px; }\n`,\n\n  mounted() {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const eyebrow = p.eyebrow == null ? 'A história' : p.eyebrow;\n    const title = p.title || 'Da garagem pro canal. Do canal pra sua garagem.';\n    let paras = list(p.paragraphs).map((x) => String(x || '')).filter(Boolean);\n    if (!paras.length && p.paragraphs == null) paras = ['[Primeiro parágrafo]', '[Segundo parágrafo]'];\n    const media = p.image\n      ? `<img src=\"${esc(p.image)}\" alt=\"${esc(p.imageAlt || '')}\">`\n      : `<div class=\"ph\">${IMG}<span>${esc(p.placeholder || 'Foto')}</span></div>`;\n    return `<div class=\"mt l-${layout}${truthy(p.flip) ? ' flip' : ''}\">\n      <div class=\"media\">${media}</div>\n      <div class=\"copy\">\n        ${eyebrow ? `<p class=\"kicker\">${esc(eyebrow)}</p>` : ''}\n        <h2 class=\"title\">${esc(title)}</h2>\n        ${paras.map((t) => `<p class=\"body\">${esc(t)}</p>`).join('')}\n      </div>\n    </div>`;\n  }\n};"}},"eyebrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"eyebrow"}}}},"flip":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"flip"}}}},"image":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"image"}}}},"imageAlt":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"imageAlt"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"paragraphs":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"paragraphs"}}}},"placeholder":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"placeholder"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}}}}}}}},{"_id":"6ab92c2fd638cff4260db230","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"ValueCard","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// ValueCard — Loja Lucas Fontana\n// Um motivo numerado para comprar aqui: numeral vermelho em itálico (\"01\"), título em caixa alta e um texto curto,\n// num card branco com borda fina. Use três lado a lado sobre uma Section cinza (tone \"alt\").\n// O texto chega por `body` (o nome `text` é reservado do bloco base do Data2).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst pad = (v) => { const n = Number(v); return v !== '' && v != null && Number.isFinite(n) ? (n < 10 ? '0' + n : String(n)) : String(v || ''); };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.vc { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-700: #45474b; --line: #e4e4e2;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  display: flex; flex-direction: column; gap: 10px; width: 100%; height: 100%; padding: 28px;\n  background: var(--white); border: 1px solid var(--line); color: var(--ink); }\np, h3 { margin: 0; }\n.num { font-size: 34px; font-weight: 800; font-style: italic; font-stretch: 125%; line-height: 1; color: var(--red-500); }\n.title { margin: 4px 0 0; font-size: 20px; font-weight: 800; font-stretch: 112%; line-height: 1.1; text-transform: uppercase; }\n.text { font-size: 15px; line-height: 1.6; color: var(--grey-700); }\n.l-tablet { padding: 22px; }\n.l-tablet .num, .l-mobile .num { font-size: 28px; }\n.l-tablet .title, .l-mobile .title { font-size: 17px; }\n.l-tablet .text, .l-mobile .text { font-size: 14px; }\n.l-mobile { padding: 22px 20px; }\n`,\n\n  mounted() {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const num = pad(p.number == null ? '1' : p.number);\n    const title = p.title || 'Testado de verdade';\n    const body = p.body == null ? 'O que entra na loja é o que o Lucas usa, testa e mostra nos vídeos.' : p.body;\n    return `<article class=\"vc l-${layout}\">\n      ${num ? `<p class=\"num\" aria-hidden=\"true\">${esc(num)}</p>` : ''}\n      <h3 class=\"title\">${esc(title)}</h3>\n      ${body ? `<p class=\"text\">${esc(body)}</p>` : ''}\n    </article>`;\n  }\n};"}},"body":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"body"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"number":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"number"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}}}}}}}},{"_id":"6ab92c3be69f22645a56e5fa","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Section","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Section — Loja Lucas Fontana\n// A faixa de uma seção de página: aplica o fundo (branco ou cinza \"alt\"), o gutter (96 / 40 / 20px),\n// o respiro de topo (120 / 88 / 64px; na faixa cinza 96 / 64 / 48px) e desenha o SectionHeader no lugar certo.\n// O conteúdo (cards, grids…) é posicionado por cima, na página, logo abaixo do cabeçalho — veja o Doc.\n// Não desenha o cabeçalho: usa o SectionHeader pelo parâmetro `sectionHeader`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst TOP = { desktop: 120, tablet: 88, mobile: 64 };\nconst TOP_ALT = { desktop: 96, tablet: 64, mobile: 48 };\nconst GUTTER = { desktop: 96, tablet: 40, mobile: 20 };\nconst HEAD = { desktop: 80, tablet: 72, mobile: 90 };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.sec { width: 100%; height: 100%; background: #ffffff; }\n.sec.alt { background: #f5f5f3; }\n.head { width: 100%; }\n`,\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const alt = p.tone === 'alt';\n    const top = truthy(p.flush) ? 0 : (alt ? TOP_ALT[layout] : TOP[layout]);\n    const gutter = GUTTER[layout];\n    const h = Number(p.headerHeight) > 0 ? Number(p.headerHeight) : HEAD[layout];\n    const shRef = refOf(d2.param('sectionHeader'));\n    const header = shRef && (p.title || p.eyebrow)\n      ? `<div class=\"head\" style=\"height:${h}px\">${d2.render(shRef, {\n          number: p.number || '', eyebrow: p.eyebrow || '', title: p.title || '', kicker: truthy(p.kicker),\n          actionLabel: p.actionLabel || '', actionHref: p.actionHref || '', layout\n        }, { key: 'sh', onAction: () => { try { d2.emit('onAction', p.actionHref || ''); } catch (err) { /* sem handler */ } } })}</div>`\n      : '';\n    return `<section class=\"sec${alt ? ' alt' : ''}\" style=\"padding:${top}px ${gutter}px 0\">${header}</section>`;\n  }\n};"}},"actionHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"actionHref"}}}},"actionLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"actionLabel"}}}},"eyebrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"eyebrow"}}}},"flush":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"flush"}}}},"headerHeight":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"headerHeight"}}}},"kicker":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"kicker"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"number":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"number"}}}},"onAction":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onAction"}}}},"sectionHeader":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"sectionHeader"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}},"tone":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"tone"}}}}}}}}}},{"_id":"6aba776d6c715c0b701ea1e0","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Accordion","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Accordion — Loja Lucas Fontana\n// Linhas de pergunta e resposta do FAQ (e, depois, das abas da página de produto no mobile).\n// Pergunta 17px bold com um quadrado de 28px à direita: \"+\" em ink fechado, \"−\" em vermelho aberto.\n// Resposta em 15px cinza, hairline entre as linhas. Cada pergunta é um botão dentro de um título, com aria-expanded.\n// Não desenha ícone: usa o Icon pelo parâmetro `iconComponent` (sem ele, cai num traço próprio igual).\n// `query` filtra as perguntas (sem acento, sem maiúscula) e abre as que batem — é o que a busca do FAQ usa.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst nums = (v) => {\n  if (Array.isArray(v)) return v.map(Number).filter((n) => !isNaN(n));\n  if (typeof v === 'number') return [v];\n  if (typeof v === 'string' && v.trim()) {\n    try { const j = JSON.parse(v); if (Array.isArray(j)) return j.map(Number).filter((n) => !isNaN(n)); if (typeof j === 'number') return [j]; } catch (e) { /* lista separada por vírgula */ }\n    return v.split(',').map((s) => Number(s.trim())).filter((n) => !isNaN(n));\n  }\n  return [];\n};\nconst fold = (s) => String(s == null ? '' : s).normalize('NFD').replace(/[\\u0300-\\u036f]/g, '').toLowerCase().trim();\nconst paras = (t) => String(t == null ? '' : t).split(/\\n\\s*\\n/).map((x) => x.trim()).filter(Boolean)\n  .map((x) => `<p>${esc(x).replace(/\\n/g, '<br>')}</p>`).join('');\nconst SVG = {\n  plus: '<svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" aria-hidden=\"true\"><path d=\"M12 5v14M5 12h14\"/></svg>',\n  minus: '<svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" aria-hidden=\"true\"><path d=\"M5 12h14\"/></svg>'\n};\nconst DEMO = [\n  { question: 'Quais formas de pagamento vocês aceitam?', answer: 'Pix e cartão de crédito, com parcelamento em até [N]x. Não trabalhamos com boleto.' },\n  { question: 'É seguro comprar aqui?', answer: '[Resposta]' },\n  { question: 'Preciso ter conta para comprar?', answer: '[Resposta]' }\n];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.acc { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-700: #45474b; --grey-500: #6b6e73; --line: #e4e4e2;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  width: 100%; color: var(--ink); }\nh3, h4, p { margin: 0; }\n.item { border-bottom: 1px solid var(--line); }\n.q { display: flex; width: 100%; align-items: center; justify-content: space-between; gap: 16px; min-height: 60px; padding: 14px 0; margin: 0;\n  border: 0; background: transparent; font: 700 17px/1.35 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;\n  color: var(--ink); text-align: left; cursor: pointer; transition: color .15s ease; }\n.q:hover { color: var(--red-500); }\n.q:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.tg { flex: none; width: 28px; height: 28px; background: var(--ink); color: var(--white); display: flex; align-items: center; justify-content: center; }\n.q[aria-expanded=\"true\"] .tg { background: var(--red-500); }\n.tg svg { display: block; }\n.a { padding: 0 44px 20px 0; font-size: 15px; line-height: 1.65; color: var(--grey-700); }\n.a[hidden] { display: none; }\n.a p { margin: 0 0 10px; }\n.a p:last-child { margin: 0; }\n.none { padding: 20px 0; font-size: 15px; color: var(--grey-500); }\n.l-mobile .q { font-size: 16px; }\n.l-mobile .a { padding-right: 0; }\n`,\n\n  mounted(d2) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    d2.on('.q', 'click', (e, el) => {\n      const k = Number(el.dataset.i);\n      const p = d2.params || {};\n      const searching = !!fold(p.query);\n      const isOpen = el.getAttribute('aria-expanded') === 'true';\n      if (searching) {\n        // Durante a busca tudo que bate começa aberto; guardamos só o que a pessoa fechou.\n        const q = fold(p.query);\n        const st = d2.state.closedQ;\n        const closed = st && st.q === q ? st.list.slice() : [];\n        d2.state.closedQ = { q, list: isOpen ? closed.concat([k]) : closed.filter((x) => x !== k) };\n      } else {\n        const cur = (d2.state.open || nums(p.defaultOpen)).slice();\n        d2.state.open = isOpen ? cur.filter((x) => x !== k) : (truthy(p.single) ? [k] : cur.concat([k]));\n      }\n      try { d2.emit('onToggle', { index: k, open: !isOpen }); } catch (err) { /* sem handler */ }\n    });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const all = (list(p.items).length ? list(p.items) : DEMO)\n      .map((it) => ({ question: (it && it.question) || '', answer: (it && it.answer) || '' }))\n      .filter((it) => it.question);\n    const hl = Number(p.headingLevel) === 4 ? 'h4' : 'h3';\n    const iconMod = refOf(d2.param('iconComponent'));\n    const uid = 'acc'; // ids vivem no shadow root de cada instância, não colidem\n\n    // Linhas abertas: o que a pessoa abriu/fechou, ou `defaultOpen` enquanto ninguém mexeu.\n    const opened = d2.state.open || nums(p.defaultOpen);\n    const q = fold(p.query);\n    const st = d2.state.closedQ;\n    const closedQ = st && st.q === q ? st.list : [];\n\n    const rows = all.map((it, k) => ({ it, k }))\n      .filter(({ it }) => !q || fold(it.question).indexOf(q) >= 0 || fold(it.answer).indexOf(q) >= 0);\n    if (!rows.length) {\n      return `<div class=\"acc l-${layout}\"><p class=\"none\">${esc(p.emptyLabel || 'Nenhuma pergunta por aqui.')}</p></div>`;\n    }\n    const openSet = q ? rows.map((r) => r.k).filter((k) => closedQ.indexOf(k) < 0) : opened;\n\n    const html = rows.map(({ it, k }) => {\n      const isOpen = openSet.indexOf(k) >= 0;\n      const glyph = iconMod\n        ? d2.render(iconMod, { name: isOpen ? 'minus' : 'plus', size: 14, iconColor: 'currentColor' }, { key: 'ic-' + k + (isOpen ? '-m' : '-p'), width: 14, height: 14 })\n        : SVG[isOpen ? 'minus' : 'plus'];\n      return `<div class=\"item\" data-key=\"${k}\">\n        <${hl}><button type=\"button\" class=\"q\" data-i=\"${k}\" aria-expanded=\"${isOpen ? 'true' : 'false'}\" aria-controls=\"${uid}-${k}\">\n          <span>${esc(it.question)}</span><span class=\"tg\" aria-hidden=\"true\">${glyph}</span>\n        </button></${hl}>\n        <div class=\"a\" id=\"${uid}-${k}\"${isOpen ? '' : ' hidden'}>${paras(it.answer)}</div>\n      </div>`;\n    }).join('');\n    return `<div class=\"acc l-${layout}\">${html}</div>`;\n  }\n};"}},"defaultOpen":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"defaultOpen"}}}},"emptyLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"emptyLabel"}}}},"headingLevel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"headingLevel"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"items":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"items"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onToggle":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onToggle"}}}},"query":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"query"}}}},"single":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"single"}}}}}}}}}},{"_id":"6aba777c976d61457441e04f","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"FaqGroup","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// FaqGroup — Loja Lucas Fontana\n// Um tema do FAQ: título em caixa alta (24px, 20px no mobile) sobre uma régua ink de 2px, e o Accordion logo abaixo.\n// `anchor` é o id do tema: o menu \"Temas\" do FaqLayout usa para pular até ele.\n// Não desenha as perguntas: usa o Accordion pelo parâmetro `accordion` (e repassa o Icon por `iconComponent`).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst DEMO = [\n  { question: 'Quais formas de pagamento vocês aceitam?', answer: 'Pix e cartão de crédito, com parcelamento em até [N]x. Não trabalhamos com boleto.' },\n  { question: 'É seguro comprar aqui?', answer: '[Resposta]' },\n  { question: 'Preciso ter conta para comprar?', answer: '[Resposta]' }\n];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.grp { --ink: #0b0b0c;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  display: flex; flex-direction: column; width: 100%; color: var(--ink); scroll-margin-top: 24px; }\n.gt { margin: 0; padding-bottom: 12px; border-bottom: 2px solid var(--ink); font-size: 24px; font-weight: 800; font-stretch: 115%;\n  line-height: 1.05; letter-spacing: .005em; text-transform: uppercase; color: var(--ink); overflow-wrap: break-word; }\n.l-mobile .gt { font-size: 20px; font-stretch: 112%; }\n`,\n\n  mounted() {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const accMod = refOf(d2.param('accordion'));\n    const iconMod = refOf(d2.param('iconComponent'));\n    const items = list(p.items).length ? list(p.items) : DEMO;\n    const title = p.title == null ? 'Compras e pagamento' : p.title;\n    const anchor = p.anchor ? String(p.anchor) : '';\n    const tid = anchor ? anchor + '-t' : 'faq-group-t';\n\n    const acc = accMod\n      ? d2.render(accMod, {\n          items, defaultOpen: p.defaultOpen == null ? [] : p.defaultOpen, single: truthy(p.single),\n          query: p.query || '', layout, headingLevel: 3, iconComponent: iconMod\n        }, { key: 'acc' + (p.query ? '-q-' + String(p.query).toLowerCase() : ''), style: 'height:auto', onToggle: (e) => { try { d2.emit('onToggle', e); } catch (err) { /* sem handler */ } } })\n      : '';\n\n    return `<section class=\"grp l-${layout}\"${anchor ? ` id=\"${esc(anchor)}\"` : ''} aria-labelledby=\"${esc(tid)}\">\n      <h2 class=\"gt\" id=\"${esc(tid)}\">${esc(title)}</h2>\n      ${acc}\n    </section>`;\n  }\n};"}},"accordion":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"accordion"}}}},"anchor":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"anchor"}}}},"defaultOpen":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"defaultOpen"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"items":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"items"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onToggle":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onToggle"}}}},"query":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"query"}}}},"single":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"single"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}}}}}}}},{"_id":"6aba778f6c715c0b701ea228","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"SupportCard","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// SupportCard — Loja Lucas Fontana\n// O card escuro \"Não achou sua resposta?\" do FAQ: xadrez discreto no canto, título, uma linha apontando o SAC,\n// botão vermelho (WhatsApp do SAC), botão de contorno branco (e-mail) e uma nota pequena com link no rodapé.\n// Não desenha botão: usa o Button pelo parâmetro `button` (variantes `brand` e `ghost`).\n// O texto de apoio chega por `body` (o nome `text` é reservado do bloco base do Data2).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst dflt = (v, d) => (v == null ? d : v);\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.sc { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-200: #c9cacd; --grey-300: #a7a9ad;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  position: relative; display: flex; flex-direction: column; gap: 14px; width: 100%; height: 100%; padding: 28px 24px;\n  background: var(--ink); color: var(--white); overflow: hidden; }\nh2, p { margin: 0; position: relative; }\n.checker { position: absolute; top: 0; right: 0; width: 72px; height: 48px; pointer-events: none;\n  background: repeating-conic-gradient(rgba(255,255,255,.08) 0 25%, transparent 0 50%) 0 0 / 16px 16px; }\n.title { font-size: 22px; font-weight: 800; font-stretch: 112%; line-height: 1.05; text-transform: uppercase; padding-right: 48px; }\n.body { font-size: 14px; line-height: 1.55; color: var(--grey-200); }\n.btns { position: relative; display: flex; flex-direction: column; gap: 10px; margin-top: 2px; }\n.btn { width: 100%; height: 48px; }\n.foot { font-size: 13px; line-height: 1.5; color: var(--grey-300); }\n.foot a { display: inline-block; color: var(--white); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }\n.foot a:hover { color: var(--red-500); }\n.foot a:focus-visible { outline: 2px solid var(--white); outline-offset: 2px; }\n\n/* Tablet: o card vai para o fim da página, largo; os botões ficam lado a lado */\n.l-tablet { padding: 32px; }\n.l-tablet .body { max-width: 520px; }\n.l-tablet .btns { flex-direction: row; }\n.l-tablet .btn { flex: 1 1 0; }\n\n/* Mobile: igual ao desktop, empilhado */\n.l-mobile .title { font-size: 20px; }\n`,\n\n  mounted(d2) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    d2.on('.foot a', 'click', (e, el) => { try { d2.emit('onFootLink', el.getAttribute('href')); } catch (err) { /* sem handler */ } });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const btnMod = refOf(d2.param('button'));\n\n    const title = dflt(p.title, 'Não achou sua resposta?');\n    const body = dflt(p.body, 'Fala com o SAC — é o caminho mais rápido para dúvidas sobre pedido, troca ou entrega.');\n    const pLabel = dflt(p.primaryLabel, 'WhatsApp do SAC');\n    const sLabel = dflt(p.secondaryLabel, '[E-mail do SAC]');\n    const footText = dflt(p.footText, 'Quer mandar um recado pro Lucas?');\n    const footLink = dflt(p.footLinkLabel, 'Fale com o Lucas');\n    const footHref = p.footLinkHref || '/fale-com-o-lucas';\n\n    const btn = (key, label, variant, glyph, href, evt) => `<div class=\"btn\">${d2.render(btnMod, {\n      label, variant, size: 'md', fullWidth: 'always', glyph: glyph || '', layout, href: href || '', newTab: /^https?:/.test(href || '')\n    }, { key, height: 48, onClick: () => { try { d2.emit(evt, href || ''); } catch (err) { /* sem handler */ } } })}</div>`;\n\n    const btns = btnMod && (pLabel || sLabel) ? `<div class=\"btns\">\n        ${pLabel ? btn('primary', pLabel, 'brand', dflt(p.primaryGlyph, 'message'), p.primaryHref, 'onPrimary') : ''}\n        ${sLabel ? btn('secondary', sLabel, 'ghost', '', p.secondaryHref, 'onSecondary') : ''}\n      </div>` : '';\n\n    const foot = footText || footLink\n      ? `<p class=\"foot\">${esc(footText)}${footText && footLink ? '<br>' : ''}${footLink ? `<a href=\"${esc(footHref)}\">${esc(footLink)}</a>` : ''}</p>`\n      : '';\n\n    return `<section class=\"sc l-${layout}\">\n      <span class=\"checker\" aria-hidden=\"true\"></span>\n      ${title ? `<h2 class=\"title\">${esc(title)}</h2>` : ''}\n      ${body ? `<p class=\"body\">${esc(body)}</p>` : ''}\n      ${btns}\n      ${foot}\n    </section>`;\n  }\n};"}},"body":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"body"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"footLinkHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"footLinkHref"}}}},"footLinkLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"footLinkLabel"}}}},"footText":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"footText"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onFootLink":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onFootLink"}}}},"onPrimary":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onPrimary"}}}},"onSecondary":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSecondary"}}}},"primaryGlyph":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"primaryGlyph"}}}},"primaryHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"primaryHref"}}}},"primaryLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"primaryLabel"}}}},"secondaryHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"secondaryHref"}}}},"secondaryLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"secondaryLabel"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}}}}}}}},{"_id":"6aba77a6f7e943b8aee8e432","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"PageHeader","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// PageHeader — Loja Lucas Fontana\n// A faixa de título que abre as páginas de listagem e as institucionais (categoria, busca, FAQ):\n// breadcrumb, kicker vermelho com régua curta (\"— Ajuda\"), título 44/36/28px, uma linha de descrição\n// e, no desktop, a contagem à direita (`meta`). Uma hairline fecha a faixa.\n// Com `showSearch`, põe o SearchBar grande embaixo da descrição (é o FAQ), sem o botão \"Buscar\".\n// Não desenha breadcrumb nem busca: usa Breadcrumb e SearchBar por parâmetro (e repassa Icon e Button para a busca).\n// A descrição chega por `description` (o nome `text` é reservado do bloco base do Data2).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst PAD = { desktop: '32px 96px 40px', tablet: '28px 40px 32px', mobile: '24px 20px 28px' };\nconst CRUMB_H = { desktop: 24, tablet: 24, mobile: 30 };\nconst SEARCH_H = { desktop: 56, tablet: 52, mobile: 52 };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.pgh { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-500: #6b6e73; --grey-700: #45474b; --line: #e4e4e2;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  width: 100%; height: 100%; background: var(--white); border-bottom: 1px solid var(--line); color: var(--ink); }\np, h1 { margin: 0; }\n.in { display: flex; flex-direction: column; gap: 16px; }\n.crumb { width: 100%; }\n.row { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; }\n.txt { display: flex; flex-direction: column; gap: 10px; min-width: 0; }\n.kicker { display: flex; align-items: center; gap: 12px; font-size: 12px; font-weight: 700; letter-spacing: .3em; line-height: 1.3; text-transform: uppercase; color: var(--red-500); }\n.kicker::before { content: ''; width: 22px; height: 3px; background: var(--red-500); flex: none; }\n.title { font-size: 44px; font-weight: 800; font-stretch: 115%; line-height: 1; letter-spacing: -.01em; text-transform: uppercase; color: var(--ink); overflow-wrap: break-word; }\n.desc { margin-top: 6px; font-size: 17px; line-height: 1.5; color: var(--grey-700); max-width: 640px; }\n.meta { flex-shrink: 0; font-size: 14px; color: var(--grey-500); padding-bottom: 2px; }\n.search { width: 100%; max-width: 656px; margin-top: 8px; }\n\n.l-tablet .in { gap: 14px; }\n.l-tablet .title { font-size: 36px; }\n.l-tablet .desc { font-size: 16px; }\n\n.l-mobile .in { gap: 12px; }\n.l-mobile .kicker { font-size: 11px; letter-spacing: .26em; }\n.l-mobile .title { font-size: 28px; font-stretch: 112%; line-height: 1.02; letter-spacing: 0; }\n.l-mobile .desc { font-size: 15px; }\n`,\n\n  mounted(d2) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const bcRef = refOf(d2.param('breadcrumb'));\n    const sbRef = refOf(d2.param('searchBar'));\n    const iconRef = refOf(d2.param('searchIcon'));\n    const btnRef = refOf(d2.param('button'));\n\n    const crumbs = list(p.crumbs).length ? list(p.crumbs) : [{ label: 'Início', href: '/' }, { label: p.title || 'Perguntas frequentes' }];\n    const eyebrow = p.eyebrow == null ? 'Ajuda' : p.eyebrow;\n    const title = p.title || 'Perguntas frequentes';\n    const desc = p.description == null ? 'As dúvidas que mais chegam por aqui, respondidas sem enrolação.' : p.description;\n    const showSearch = p.showSearch == null ? true : truthy(p.showSearch);\n\n    const crumb = bcRef\n      ? `<div class=\"crumb\" style=\"height:${CRUMB_H[layout]}px\">${d2.render(bcRef, { items: crumbs, layout }, {\n          key: 'bc', onNavigate: (h) => { try { d2.emit('onNavigate', h); } catch (err) { /* sem handler */ } } })}</div>`\n      : '';\n\n    const search = showSearch && sbRef\n      ? `<div class=\"search\" style=\"height:${SEARCH_H[layout]}px\">${d2.render(sbRef, {\n          layout, size: 'lg', showButton: false, searchIcon: iconRef, button: btnRef,\n          placeholder: p.searchPlaceholder || 'Busque sua dúvida: frete, troca, pagamento...',\n          shortPlaceholder: p.searchShortPlaceholder || 'Busque sua dúvida',\n          ariaLabel: p.searchLabel || 'Buscar nas perguntas frequentes',\n          busTopic: p.searchTopic == null ? 'faq:search' : p.searchTopic\n        }, { key: 'search', onSearch: (q) => { try { d2.emit('onSearch', q); } catch (err) { /* sem handler */ } } })}</div>`\n      : '';\n\n    const meta = layout === 'desktop' && p.meta ? `<span class=\"meta\">${esc(p.meta)}</span>` : '';\n\n    return `<div class=\"pgh l-${layout}\"><div class=\"in\" style=\"padding:${PAD[layout]}\">\n      ${crumb}\n      <div class=\"row\">\n        <div class=\"txt\">\n          ${eyebrow ? `<p class=\"kicker\">${esc(eyebrow)}</p>` : ''}\n          <h1 class=\"title\">${esc(title)}</h1>\n          ${desc ? `<p class=\"desc\">${esc(desc)}</p>` : ''}\n        </div>\n        ${meta}\n      </div>\n      ${search}\n    </div></div>`;\n  }\n};"}},"breadcrumb":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"breadcrumb"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"crumbs":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"crumbs"}}}},"description":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"description"}}}},"eyebrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"eyebrow"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"meta":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"meta"}}}},"onNavigate":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onNavigate"}}}},"onSearch":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSearch"}}}},"searchBar":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"searchBar"}}}},"searchIcon":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"searchIcon"}}}},"searchLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"searchLabel"}}}},"searchPlaceholder":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"searchPlaceholder"}}}},"searchShortPlaceholder":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"searchShortPlaceholder"}}}},"searchTopic":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"searchTopic"}}}},"showSearch":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"showSearch"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}}}}}}}},{"_id":"6aba77d12c4424598ddc5a99","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"FaqLayout","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// FaqLayout — Loja Lucas Fontana\n// O corpo da página de perguntas frequentes.\n// Desktop: coluna de 264px à esquerda, presa no scroll, com o menu \"Temas\" (tema atual preenchido em ink)\n// e o SupportCard embaixo; as perguntas (FaqGroups) à direita.\n// Tablet e mobile: os temas viram uma fileira de chips que rola para o lado, acima das perguntas,\n// e o SupportCard vai para o fim.\n// O tema atual acompanha a rolagem da página; clicar num tema rola até ele.\n// Busca: escuta o tópico `searchTopic` (padrão \"faq:search\", o mesmo que o PageHeader manda) ou recebe `query`,\n// mostra só os temas e perguntas que batem e, se nada bater, a mensagem de \"não achamos\".\n// Não desenha tema, pergunta nem card: usa FaqGroup, Accordion, Icon, SupportCard e Button por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\nconst fold = (s) => String(s == null ? '' : s).normalize('NFD').replace(/[\\u0300-\\u036f]/g, '').toLowerCase().trim();\nconst PAD = { desktop: '40px 96px 120px', tablet: '32px 40px 88px', mobile: '24px 20px 64px' };\n\nconst DEMO = [\n  { id: 'compras', title: 'Compras e pagamento', open: [0], items: [\n    { question: 'Quais formas de pagamento vocês aceitam?', answer: 'Pix e cartão de crédito, com parcelamento em até [N]x. Não trabalhamos com boleto.' },\n    { question: 'É seguro comprar aqui?', answer: '[Resposta]' },\n    { question: 'Preciso ter conta para comprar?', answer: '[Resposta]' }] },\n  { id: 'entrega', title: 'Entrega e rastreio', items: [\n    { question: 'Vocês entregam para todo o Brasil?', answer: '[Resposta]' },\n    { question: 'Como acompanho meu pedido?', answer: '[Resposta]' },\n    { question: 'Por que meu pedido veio em mais de uma entrega?', answer: '[Resposta]' }] },\n  { id: 'trocas', title: 'Trocas e devoluções', items: [\n    { question: 'Posso desistir da compra?', answer: '[Resposta]' },\n    { question: 'O produto chegou com defeito. E agora?', answer: '[Resposta]' }] },\n  { id: 'produtos', title: 'Produtos', items: [\n    { question: 'O produto que eu quero está esgotado. Vai voltar?', answer: '[Resposta]' },\n    { question: 'Como sei se a peça serve no meu carro?', answer: '[Resposta]' }] },\n  { id: 'conta', title: 'Minha conta', items: [\n    { question: 'Esqueci minha senha. Como faço?', answer: '[Resposta]' },\n    { question: 'Como altero meus dados ou endereço?', answer: '[Resposta]' }] }\n];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.faq { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-50: #f5f5f3; --grey-500: #6b6e73; --grey-700: #45474b;\n  --line: #e4e4e2; --line-strong: #d9d9d6;\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased;\n  width: 100%; background: var(--white); color: var(--ink); }\np, h2 { margin: 0; }\n.in { display: grid; grid-template-columns: 264px minmax(0, 1fr); gap: 56px; align-items: start; }\n.side { position: sticky; top: 24px; display: flex; flex-direction: column; gap: 32px; }\n.nav { display: flex; flex-direction: column; }\n.nt { margin: 0 0 12px; font-size: 12px; font-weight: 800; letter-spacing: .24em; text-transform: uppercase; color: var(--ink); }\n.topic { display: flex; align-items: center; width: 100%; min-height: 48px; padding: 0 16px; margin: 0; border: 0; background: transparent;\n  font: 700 15px/1.25 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; color: var(--ink); text-align: left; cursor: pointer; }\n.topic:hover { background: var(--grey-50); }\n.topic[aria-current=\"true\"] { background: var(--ink); color: var(--white); }\n.topic:focus-visible, .chip:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.main { display: flex; flex-direction: column; gap: 32px; min-width: 0; }\n.chips { display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none; padding-bottom: 4px; }\n.chips::-webkit-scrollbar { display: none; }\n.chip { flex: none; display: inline-flex; align-items: center; height: 44px; padding: 0 16px; margin: 0; border: 1px solid var(--line-strong);\n  border-radius: 0; background: var(--white); font: 700 14px/1 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;\n  color: var(--ink); white-space: nowrap; cursor: pointer; }\n.chip:hover { border-color: var(--ink); }\n.chip[aria-current=\"true\"] { background: var(--ink); border-color: var(--ink); color: var(--white); }\n.groups { display: flex; flex-direction: column; gap: 48px; }\n.g { scroll-margin-top: 24px; }\n.help-m { margin-top: 16px; }\n.empty { display: flex; flex-direction: column; gap: 10px; padding: 32px 0 8px; border-top: 2px solid var(--ink); }\n.empty .k { display: flex; align-items: center; gap: 12px; font-size: 12px; font-weight: 700; letter-spacing: .3em; text-transform: uppercase; color: var(--red-500); }\n.empty .k::before { content: ''; width: 22px; height: 3px; background: var(--red-500); flex: none; }\n.empty h2 { font-size: 24px; font-weight: 800; font-stretch: 115%; line-height: 1.1; text-transform: uppercase; overflow-wrap: anywhere; }\n.empty p { font-size: 15px; line-height: 1.6; color: var(--grey-700); max-width: 520px; }\n\n.l-tablet .in, .l-mobile .in { grid-template-columns: minmax(0, 1fr); gap: 32px; }\n.l-mobile .in { gap: 28px; }\n.l-mobile .main { gap: 28px; }\n.l-mobile .groups { gap: 40px; }\n.l-mobile .empty h2 { font-size: 20px; }\n`,\n\n  mounted(d2) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font';\n      l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    // Busca vinda do PageHeader (ou de qualquer SearchBar com o mesmo busTopic)\n    const topic = (d2.params || {}).searchTopic;\n    const t = topic == null ? 'faq:search' : String(topic);\n    if (t && d2.bus && typeof d2.bus.on === 'function') d2.bus.on(t, (q) => { const v = String(q == null ? '' : q); if (d2.state.q !== v) d2.state.q = v; });\n\n    // Clique num tema: marca e rola até ele (a rolagem suspende o acompanhamento por um instante)\n    d2.on('[data-topic]', 'click', (e, el) => {\n      const id = el.getAttribute('data-topic');\n      d2.state.active = id;\n      if (d2.root) d2.root.__lfLock = Date.now() + 900;\n      const target = d2.$(`.g[data-g=\"${id}\"]`);\n      if (target && typeof target.scrollIntoView === 'function') target.scrollIntoView({ behavior: 'smooth', block: 'start' });\n      try { d2.emit('onTopic', id); } catch (err) { /* sem handler */ }\n    });\n\n    // Tema atual acompanha a rolagem: o tema cujo topo passou da faixa de cima da tela\n    if (typeof IntersectionObserver !== 'undefined') {\n      const io = new IntersectionObserver((entries) => {\n        if (d2.root && d2.root.__lfLock && Date.now() < d2.root.__lfLock) return;\n        const hit = entries.filter((en) => en.isIntersecting)\n          .sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)[0];\n        if (hit) {\n          const id = hit.target.getAttribute('data-g');\n          if (id && d2.state.active !== id) d2.state.active = id;\n        }\n      }, { rootMargin: '-15% 0px -70% 0px', threshold: 0 });\n      const watch = () => { io.disconnect(); d2.$$('.g[data-g]').forEach((el) => io.observe(el)); };\n      d2.onUnmount(() => io.disconnect());\n      // guarda o \"watch\" fora do estado reativo\n      d2.root.__lfWatch = watch;\n      watch();\n    }\n\n    // Link direto para um tema: /perguntas-frequentes#trocas abre a página já no tema\n    try {\n      const h = typeof location !== 'undefined' ? decodeURIComponent(String(location.hash || '').replace(/^#/, '')) : '';\n      if (h) {\n        setTimeout(() => {\n          const el = d2.$(`.g[data-g=\"${h.replace(/\"/g, '')}\"]`);\n          if (el) { d2.state.active = h; if (d2.root) d2.root.__lfLock = Date.now() + 900; el.scrollIntoView({ block: 'start' }); }\n        }, 300);\n      }\n    } catch (err) { /* sem hash */ }\n  },\n\n  updated(d2) {\n    if (d2.root && typeof d2.root.__lfWatch === 'function') d2.root.__lfWatch();\n    // mantém o chip do tema atual visível na fileira\n    const chip = d2.$('.chip[aria-current=\"true\"]');\n    const row = d2.$('.chips');\n    if (chip && row) {\n      const l = chip.offsetLeft, r = l + chip.offsetWidth;\n      if (l < row.scrollLeft || r > row.scrollLeft + row.clientWidth) row.scrollLeft = Math.max(0, l - 20);\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const desk = layout === 'desktop';\n    const fgMod = refOf(d2.param('faqGroup'));\n    const accMod = refOf(d2.param('accordion'));\n    const iconMod = refOf(d2.param('iconComponent'));\n    const scMod = refOf(d2.param('supportCard'));\n    const btnMod = refOf(d2.param('button'));\n\n    const groups = (list(p.groups).length ? list(p.groups) : DEMO)\n      .map((g, i) => ({ id: String((g && g.id) || 'tema-' + (i + 1)), title: (g && g.title) || '', items: list(g && g.items), open: g && g.open }))\n      .filter((g) => g.title);\n    const labels = {};\n    list(p.topics).forEach((t) => { if (t && t.id) labels[String(t.id)] = t.label; });\n\n    const q = fold(p.query != null && p.query !== '' ? p.query : d2.state.q);\n    const rawQ = String(p.query != null && p.query !== '' ? p.query : (d2.state.q || '')).trim();\n    const hits = (g) => !q || g.items.some((it) => fold(it && it.question).indexOf(q) >= 0 || fold(it && it.answer).indexOf(q) >= 0);\n    const visible = groups.filter(hits);\n\n    const current = d2.state.active && visible.some((g) => g.id === d2.state.active)\n      ? d2.state.active\n      : (p.current && visible.some((g) => g.id === String(p.current)) ? String(p.current) : (visible[0] && visible[0].id));\n\n    const topicBtn = (g, cls) => `<button type=\"button\" class=\"${cls}\" data-topic=\"${esc(g.id)}\" data-key=\"${cls}-${esc(g.id)}\"${g.id === current ? ' aria-current=\"true\"' : ''}>${esc(labels[g.id] || g.title)}</button>`;\n\n    const groupHtml = visible.map((g) => `<div class=\"g\" data-g=\"${esc(g.id)}\" data-key=\"g-${esc(g.id)}\">${fgMod\n      ? d2.render(fgMod, {\n          anchor: g.id, title: g.title, items: g.items, defaultOpen: g.open == null ? [] : g.open, single: truthy(p.single),\n          query: q ? rawQ : '', layout, accordion: accMod, iconComponent: iconMod\n        }, { key: 'fg-' + g.id + (q ? '-q-' + q : ''), style: 'height:auto' })\n      : ''}</div>`).join('');\n\n    const empty = !visible.length ? `<div class=\"empty\" role=\"status\">\n        <p class=\"k\">${esc(p.emptyEyebrow || 'Busca')}</p>\n        <h2>Não achamos nada para “${esc(rawQ)}”</h2>\n        <p>${esc(p.emptyBody || 'Nem o Lucas achou isso na garagem. Tenta outra palavra ou fala com o SAC, que a gente resolve.')}</p>\n      </div>` : '';\n\n    const showSupport = p.showSupport == null ? true : truthy(p.showSupport);\n    const sup = obj(p.support);\n    const support = showSupport && scMod\n      ? d2.render(scMod, Object.assign({}, sup, { layout, button: btnMod }), {\n          key: 'sup-' + (desk ? 'side' : 'end'), style: 'height:auto',\n          onPrimary: (h) => { try { d2.emit('onSupport', { action: 'primary', href: h }); } catch (err) { /* sem handler */ } },\n          onSecondary: (h) => { try { d2.emit('onSupport', { action: 'secondary', href: h }); } catch (err) { /* sem handler */ } },\n          onFootLink: (h) => { try { d2.emit('onSupport', { action: 'foot', href: h }); } catch (err) { /* sem handler */ } }\n        })\n      : '';\n\n    const navTitle = p.navTitle || 'Temas';\n    const body = desk\n      ? `<aside class=\"side\">\n          <nav class=\"nav\" aria-label=\"${esc(navTitle)}\"><p class=\"nt\">${esc(navTitle)}</p>${visible.map((g) => topicBtn(g, 'topic')).join('')}</nav>\n          ${support}\n        </aside>\n        <div class=\"main\"><div class=\"groups\">${groupHtml}</div>${empty}</div>`\n      : `<div class=\"main\">\n          ${visible.length > 1 ? `<nav class=\"chips\" aria-label=\"${esc(navTitle)}\">${visible.map((g) => topicBtn(g, 'chip')).join('')}</nav>` : ''}\n          <div class=\"groups\">${groupHtml}</div>${empty}\n          ${support ? `<div class=\"help-m\">${support}</div>` : ''}\n        </div>`;\n\n    return `<div class=\"faq l-${layout}\"><div class=\"in\" style=\"padding:${PAD[layout]}\">${body}</div></div>`;\n  }\n};"}},"accordion":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"accordion"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"current":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"current"}}}},"emptyBody":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"emptyBody"}}}},"emptyEyebrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"emptyEyebrow"}}}},"faqGroup":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"faqGroup"}}}},"groups":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"groups"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"navTitle":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"navTitle"}}}},"onSupport":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSupport"}}}},"onTopic":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onTopic"}}}},"query":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"query"}}}},"searchTopic":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"searchTopic"}}}},"showSupport":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"showSupport"}}}},"single":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"single"}}}},"support":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"support"}}}},"supportCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"supportCard"}}}},"topics":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"topics"}}}}}}}}}},{"_id":"6ababb354a99aba9ee08d7f7","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"QuantityStepper","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// QuantityStepper — Loja Lucas Fontana\n// Controle − / número / + de 52px de altura (120px de largura; 96px no mobile), borda line-strong.\n// O \"−\" desativa no mínimo e o \"+\" no máximo. Fica à esquerda do \"Adicionar à sacola\" na BuyBox.\n// `size: \"sm\"`: 110 × 44px (botões de 38px), usado em cada item da sacola (CartItem).\n// Não desenha ícone: usa o Icon pelo parâmetro `iconComponent`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst ic = (d2, ref, name, size, color, key) => ref\n  ? d2.render(ref, { name, size, iconColor: color || 'currentColor' }, { key, width: size, height: size, style: 'flex:none' })\n  : '';\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\n\nexport default {\n  css: `\n:host { display: block; }\n* { box-sizing: border-box; }\n.qty { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-400: #8e9095; --line-strong: #d9d9d6;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: inline-flex; align-items: center; justify-content: space-between; width: 120px; height: 52px;\n  border: 1px solid var(--line-strong); background: var(--white); }\nbutton { width: 40px; height: 100%; margin: 0; padding: 0; border: 0; background: transparent; color: var(--ink);\n  display: flex; align-items: center; justify-content: center; cursor: pointer; }\nbutton:disabled { color: var(--grey-400); cursor: not-allowed; }\nbutton:focus-visible { outline: 2px solid var(--red-500); outline-offset: -2px; }\ninput { width: 36px; border: 0; padding: 0; margin: 0; text-align: center; font: 700 17px/1 ${FF}; color: var(--ink);\n  background: transparent; -moz-appearance: textfield; appearance: textfield; outline: none; }\ninput::-webkit-outer-spin-button, input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }\n.l-mobile { width: 96px; }\n.l-mobile button { width: 32px; }\n.l-mobile input { width: 28px; }\n.qty.sm { width: 110px; height: 44px; }\n.qty.sm button { width: 38px; }\n.qty.sm input { width: 32px; font-size: 16px; }\n`,\n\n  mounted(d2) {\n    FONT();\n    const bounds = () => {\n      const p = d2.params || {};\n      const min = p.min == null || p.min === '' ? 1 : Number(p.min);\n      const max = p.max == null || p.max === '' ? 99 : Number(p.max);\n      return { min, max };\n    };\n    const set = (v) => {\n      const { min, max } = bounds();\n      const n = Math.max(min, Math.min(max, Number.isFinite(v) ? v : min));\n      d2.state.v = n;\n      emit(d2, 'onChange', n);\n    };\n    const cur = () => {\n      const p = d2.params || {};\n      return d2.state.v != null ? d2.state.v : Number(p.value || p.defaultValue || bounds().min);\n    };\n    d2.on('.dec', 'click', () => set(cur() - 1));\n    d2.on('.inc', 'click', () => set(cur() + 1));\n    d2.on('input', 'change', (e, el) => set(parseInt(el.value, 10)));\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const min = p.min == null || p.min === '' ? 1 : Number(p.min);\n    const max = p.max == null || p.max === '' ? 99 : Number(p.max);\n    const v = d2.state.v != null ? d2.state.v : Math.max(min, Math.min(max, Number(p.value || p.defaultValue || min)));\n    const iconRef = refOf(d2.param('iconComponent'));\n    const sm = p.size === 'sm';\n    const minus = iconRef ? ic(d2, iconRef, 'minus', sm ? 16 : 18, 'currentColor', 'm') : '−';\n    const plus = iconRef ? ic(d2, iconRef, 'plus', sm ? 16 : 18, 'currentColor', 'p') : '+';\n    return `<div class=\"qty l-${layout}${sm ? ' sm' : ''}\" role=\"group\" aria-label=\"${esc(p.ariaLabel || 'Quantidade')}\">\n      <button type=\"button\" class=\"dec\" aria-label=\"Diminuir quantidade\"${v <= min ? ' disabled' : ''}>${minus}</button>\n      <input type=\"number\" inputmode=\"numeric\" min=\"${min}\" max=\"${max}\" value=\"${v}\" aria-label=\"Quantidade\">\n      <button type=\"button\" class=\"inc\" aria-label=\"Aumentar quantidade\"${v >= max ? ' disabled' : ''}>${plus}</button>\n    </div>`;\n  }\n};"}},"ariaLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ariaLabel"}}}},"defaultValue":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"defaultValue"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"max":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"max"}}}},"min":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"min"}}}},"onChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChange"}}}},"size":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"size"}}}},"value":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"value"}}}}}}}}}},{"_id":"6ababb42f281aa28d4cc4577","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"CheckList","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// CheckList — Loja Lucas Fontana\n// Benefícios com um check branco num quadrado vermelho de 20px. Texto de 15px, 12px entre as linhas.\n// De três a cinco itens curtos, uma ideia cada. Usado no ProductDetails (aba Descrição) e no PromoCard.\n// Não desenha ícone: usa o Icon pelo parâmetro `iconComponent`.\n// `tone: \"dark\"` deixa o texto branco, para fundo escuro (PromoCard).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst ic = (d2, ref, name, size, color, key) => ref\n  ? d2.render(ref, { name, size, iconColor: color || 'currentColor' }, { key, width: size, height: size, style: 'flex:none' })\n  : '';\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst DEMO = ['[Benefício principal do produto]', '[Segundo benefício — ex.: rendimento, proteção, cheiro]', '[Terceiro benefício — ex.: seguro para a pintura]'];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\nul { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }\nli { display: flex; gap: 12px; align-items: flex-start; font-size: 15px; line-height: 1.45; color: var(--ink); }\n.tone-dark li { color: var(--white); }\ni { flex: none; width: 20px; height: 20px; margin-top: 1px; background: var(--red-500); color: var(--white);\n  display: flex; align-items: center; justify-content: center; font-style: normal; }\n`,\n  mounted() { FONT(); },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const items = list(p.items).length ? list(p.items) : DEMO;\n    const iconRef = refOf(d2.param('iconComponent'));\n    return `<ul class=\"l-${layout}${p.tone === 'dark' ? ' tone-dark' : ''}\">${items.map((t, k) => `<li><i aria-hidden=\"true\">${ic(d2, iconRef, 'check', 13, '#ffffff', 'c' + k)}</i><span>${esc(t)}</span></li>`).join('')}</ul>`;\n  }\n};"}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"items":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"items"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"tone":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"tone"}}}}}}}}}},{"_id":"6ababb53440fbc0d402d13aa","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"BenefitList","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// BenefitList — Loja Lucas Fontana\n// As linhas de garantia abaixo dos botões de compra: ícone, título em negrito e uma linha cinza ou um link,\n// separadas por hairlines. Três linhas, fatos e não slogans.\n// Padrão: \"Enviamos para todo o Brasil\" (truck), \"Pix ou cartão em até [N]x\" (card), \"Troca e devolução\" + link (swap).\n// Não desenha ícone: usa o Icon pelo parâmetro `iconComponent`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst ic = (d2, ref, name, size, color, key) => ref\n  ? d2.render(ref, { name, size, iconColor: color || 'currentColor' }, { key, width: size, height: size, style: 'flex:none' })\n  : '';\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst DEFAULTS = [\n  { icon: 'truck', title: 'Enviamos para todo o Brasil', text: 'O frete é calculado no fechamento do pedido.' },\n  { icon: 'card', title: 'Pix ou cartão em até [N]x', text: 'Pagamento seguro, com antifraude em todas as compras.' },\n  { icon: 'swap', title: 'Troca e devolução', link: { label: 'Ver política de trocas', href: '/politicas/trocas-e-devolucoes' } }\n];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\nul { --red-500: #c8102e; --ink: #0b0b0c; --grey-700: #45474b; --line: #e4e4e2;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }\nli { display: flex; gap: 14px; align-items: flex-start; padding: 14px 0; border-bottom: 1px solid var(--line); color: var(--ink); }\n.ic { flex: none; width: 20px; height: 20px; margin-top: 2px; display: flex; }\nb { display: block; font-size: 15px; font-weight: 700; color: var(--ink); line-height: 1.35; }\nspan.t { display: block; font-size: 14px; line-height: 1.45; color: var(--grey-700); }\na { display: inline-block; font-size: 14px; font-weight: 600; line-height: 1.45; color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }\na:hover { color: var(--red-500); }\na:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n`,\n  mounted(d2) {\n    FONT();\n    d2.on('a', 'click', (e, el) => emit(d2, 'onLink', el.getAttribute('href')));\n  },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const items = list(p.items).length ? list(p.items) : DEFAULTS;\n    const iconRef = refOf(d2.param('iconComponent'));\n    return `<ul class=\"l-${layout}\">${items.map((b, k) => `<li>\n      <span class=\"ic\" aria-hidden=\"true\">${ic(d2, iconRef, (b && b.icon) || 'check', 20, '#0b0b0c', 'b' + k + (b && b.icon || ''))}</span>\n      <div><b>${esc(b && b.title)}</b>${b && b.text ? `<span class=\"t\">${esc(b.text)}</span>` : ''}${b && b.link && b.link.label ? `<a href=\"${esc(b.link.href || '#')}\">${esc(b.link.label)}</a>` : ''}</div>\n    </li>`).join('')}</ul>`;\n  }\n};"}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"items":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"items"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onLink":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onLink"}}}}}}}}}},{"_id":"6ababb5f80008124dcffddb4","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"QuoteCard","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// QuoteCard — Loja Lucas Fontana\n// A palavra do Lucas sobre o produto: card preto com xadrez no canto, eyebrow vermelho \"Por que o Lucas recomenda\",\n// a frase em 22px itálico (20px no mobile) e \"— Lucas Fontana\". Use uma fala real do vídeo, com menos de 30 palavras.\n// A frase chega por `quote`, sem aspas (o card coloca).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\nfigure { --ink: #0b0b0c; --white: #ffffff; --red-300: #ff4d62; --grey-300: #a7a9ad;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  position: relative; margin: 0; padding: 28px 28px 30px; background: var(--ink); color: var(--white); overflow: hidden; }\n.checker { position: absolute; top: 0; right: 0; width: 96px; height: 48px; pointer-events: none;\n  background: repeating-conic-gradient(rgba(255,255,255,.08) 0 25%, transparent 0 50%) 0 0 / 16px 16px; }\n.eb { position: relative; display: block; margin-bottom: 14px; padding-right: 88px; font-size: 11px; font-weight: 700; letter-spacing: .3em; line-height: 1.4; text-transform: uppercase; color: var(--red-300); }\nblockquote { position: relative; margin: 0; font-size: 22px; font-weight: 800; font-style: italic; font-stretch: 105%; line-height: 1.3; }\nfigcaption { position: relative; margin-top: 16px; font-size: 14px; color: var(--grey-300); }\n.l-mobile { padding: 24px 22px 26px; }\n.l-mobile blockquote { font-size: 20px; }\n`,\n  mounted() { FONT(); },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const q = String(p.quote == null || p.quote === '' ? '[Comentário do Lucas sobre o produto — pode vir de uma fala do vídeo.]' : p.quote).replace(/^[\"“”]+|[\"“”]+$/g, '');\n    return `<figure class=\"l-${layout}\">\n      <span class=\"checker\" aria-hidden=\"true\"></span>\n      <span class=\"eb\">${esc(p.eyebrow || 'Por que o Lucas recomenda')}</span>\n      <blockquote>“${esc(q)}”</blockquote>\n      <figcaption>— ${esc(p.author || 'Lucas Fontana')}</figcaption>\n    </figure>`;\n  }\n};"}},"author":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"author"}}}},"eyebrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"eyebrow"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"quote":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"quote"}}}}}}}}}},{"_id":"6ababb8130fdedf71ec851a4","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"ProductGallery","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// ProductGallery — Loja Lucas Fontana\n// Fotos e vídeo do produto.\n// Desktop: coluna de miniaturas de 88px (a selecionada contornada em preto) ao lado da imagem quadrada,\n// com anterior/próximo no canto inferior direito.\n// Tablet: miniaturas em linha embaixo da imagem (72px de altura), imagem em 4:3,2.\n// Mobile: só a imagem, de ponta a ponta, com o contador \"1/5\" e tracinhos vermelhos embaixo; arraste para trocar.\n// Um item de vídeo mostra um quadrado vermelho de play na miniatura. Coloque o vídeo por último.\n// Não desenha ícone: usa o Icon pelo parâmetro `iconComponent`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst ic = (d2, ref, name, size, color, key) => ref\n  ? d2.render(ref, { name, size, iconColor: color || 'currentColor' }, { key, width: size, height: size, style: 'flex:none' })\n  : '';\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst DEMO = [{ label: 'Foto 1' }, { label: 'Foto 2' }, { label: 'Foto 3' }, { label: 'Foto 4' }, { video: true, label: 'Vídeo' }];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.gal { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-100: #ececea; --grey-500: #6b6e73; --line: #e4e4e2; --line-strong: #d9d9d6;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: grid; grid-template-columns: 88px minmax(0, 1fr); gap: 16px; align-items: start; width: 100%; }\n.thumbs { display: flex; flex-direction: column; gap: 12px; }\n.thumb { position: relative; width: 88px; height: 88px; margin: 0; padding: 0; border: 2px solid transparent; background: var(--grey-100); cursor: pointer;\n  display: flex; align-items: center; justify-content: center; overflow: hidden; }\n.thumb img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }\n.thumb[aria-current=\"true\"] { border-color: var(--ink); }\n.thumb:focus-visible, .arrows button:focus-visible, .dots button:focus-visible, .play-big:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.ph { font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--grey-500); text-align: center; }\n.thumb .ph { font-size: 10px; }\n.play { position: relative; width: 32px; height: 32px; background: var(--red-500); color: var(--white); display: flex; align-items: center; justify-content: center; }\n.main { position: relative; aspect-ratio: 1 / 1; background: var(--grey-100); display: flex; align-items: center; justify-content: center; overflow: hidden; touch-action: pan-y; user-select: none; }\n.main img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }\n.main .ph { font-size: 12px; }\n.play-big { position: relative; width: 64px; height: 64px; margin: 0; padding: 0; border: 0; background: var(--red-500); color: var(--white); display: flex; align-items: center; justify-content: center; cursor: pointer; }\n.arrows { position: absolute; right: 16px; bottom: 16px; display: flex; gap: 8px; }\n.arrows button { width: 48px; height: 48px; margin: 0; padding: 0; border: 1px solid var(--line); background: var(--white); color: var(--ink); display: flex; align-items: center; justify-content: center; cursor: pointer; }\n.arrows button:hover { border-color: var(--ink); }\n.count { display: none; position: absolute; right: 12px; bottom: 12px; padding: 5px 8px; background: var(--white); font-size: 12px; font-weight: 700; color: var(--ink); }\n.dots { display: none; justify-content: center; gap: 4px; }\n.dots button { width: 38px; height: 32px; margin: 0; padding: 0 4px; border: 0; background: transparent; display: flex; align-items: center; cursor: pointer; }\n.dots span { display: block; width: 100%; height: 3px; background: var(--line-strong); }\n.dots [aria-current=\"true\"] span { background: var(--red-500); }\n\n.l-tablet { grid-template-columns: minmax(0, 1fr); gap: 10px; }\n.l-tablet .thumbs { order: 2; flex-direction: row; gap: 10px; }\n.l-tablet .thumb { flex: 1; width: auto; height: 72px; }\n.l-tablet .main { aspect-ratio: 4 / 3.2; }\n\n.l-mobile { grid-template-columns: minmax(0, 1fr); gap: 8px; }\n.l-mobile .thumbs, .l-mobile .arrows { display: none; }\n.l-mobile .count, .l-mobile .dots { display: flex; }\n`,\n\n  mounted(d2) {\n    FONT();\n    const items = () => { const p = d2.params || {}; return list(p.items).length ? list(p.items) : DEMO; };\n    const go = (k) => {\n      const n = items().length;\n      if (!n) return;\n      const i = ((k % n) + n) % n;\n      if (d2.state.i !== i) { d2.state.i = i; emit(d2, 'onChange', i); }\n    };\n    const cur = () => d2.state.i || 0;\n    d2.on('[data-go]', 'click', (e, el) => go(Number(el.getAttribute('data-go'))));\n    d2.on('.prev', 'click', () => go(cur() - 1));\n    d2.on('.next', 'click', () => go(cur() + 1));\n    d2.on('.play-big', 'click', (e, el) => {\n      const href = el.getAttribute('data-href');\n      emit(d2, 'onVideo', href || '');\n      if (href && typeof window !== 'undefined') window.open(href, '_blank', 'noopener');\n    });\n    // Arrastar para trocar (toque e mouse)\n    let x0 = null;\n    d2.on('.main', 'pointerdown', (e) => { x0 = e.clientX; });\n    d2.on('.main', 'pointerup', (e) => {\n      if (x0 == null) return;\n      const dx = e.clientX - x0; x0 = null;\n      if (Math.abs(dx) > 40) go(cur() + (dx < 0 ? 1 : -1));\n    });\n    d2.on('.gal', 'keydown', (e) => {\n      if (e.key === 'ArrowRight') { e.preventDefault(); go(cur() + 1); }\n      if (e.key === 'ArrowLeft') { e.preventDefault(); go(cur() - 1); }\n    });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const items = list(p.items).length ? list(p.items) : DEMO;\n    const n = items.length;\n    const i = Math.min(d2.state.i || 0, Math.max(0, n - 1));\n    const iconRef = refOf(d2.param('iconComponent'));\n    const cur = items[i] || {};\n    const label = (it, k) => (it.video ? 'Vídeo' : 'Foto ' + (k + 1)) + ' de ' + n;\n\n    const thumbs = items.map((it, k) => {\n      const inner = it.video\n        ? `${it.image ? `<img src=\"${esc(it.image)}\" alt=\"\">` : ''}<span class=\"play\">${ic(d2, iconRef, 'play', 14, '#ffffff', 'tp' + k)}</span>`\n        : (it.image ? `<img src=\"${esc(it.image)}\" alt=\"\">` : `<span class=\"ph\">${esc(it.label || 'Foto ' + (k + 1))}</span>`);\n      return `<button type=\"button\" class=\"thumb\" data-go=\"${k}\" aria-current=\"${k === i ? 'true' : 'false'}\" aria-label=\"${esc(label(it, k))}\">${inner}</button>`;\n    }).join('');\n\n    const big = cur.image\n      ? `<img src=\"${esc(cur.image)}\" alt=\"${esc(cur.alt || '')}\" draggable=\"false\">`\n      : (cur.video ? '' : `<span class=\"ph\">Foto ${i + 1} de ${n}</span>`);\n    const videoHref = typeof cur.video === 'string' ? cur.video : (cur.href || '');\n    const play = cur.video\n      ? `<button type=\"button\" class=\"play-big\" data-href=\"${esc(videoHref)}\" aria-label=\"Assistir ao vídeo\">${ic(d2, iconRef, 'play', 26, '#ffffff', 'pb')}</button>`\n      : '';\n\n    const arrows = n > 1 ? `<div class=\"arrows\">\n        <button type=\"button\" class=\"prev\" aria-label=\"Foto anterior\">${ic(d2, iconRef, 'chevron-left', 18, '#0b0b0c', 'al')}</button>\n        <button type=\"button\" class=\"next\" aria-label=\"Próxima foto\">${ic(d2, iconRef, 'chevron-right', 18, '#0b0b0c', 'ar')}</button>\n      </div>` : '';\n    const count = n > 1 ? `<span class=\"count\" aria-live=\"polite\">${i + 1}/${n}</span>` : '';\n    const dots = n > 1 ? `<div class=\"dots\">${items.map((it, k) => `<button type=\"button\" data-go=\"${k}\" aria-label=\"Ir para a foto ${k + 1}\" aria-current=\"${k === i ? 'true' : 'false'}\"><span></span></button>`).join('')}</div>` : '';\n\n    return `<div class=\"gal l-${layout}\" role=\"group\" aria-roledescription=\"galeria\" aria-label=\"${esc(p.ariaLabel || 'Fotos do produto')}\" tabindex=\"-1\">\n      <div class=\"thumbs\">${thumbs}</div>\n      <div class=\"main\">${big}${play}${arrows}${count}</div>\n      ${dots}\n    </div>`;\n  }\n};"}},"ariaLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ariaLabel"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"items":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"items"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChange"}}}},"onVideo":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onVideo"}}}}}}}}}},{"_id":"6ababba9f8aee52476044a72","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"BuyBox","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// BuyBox — Loja Lucas Fontana\n// Tudo para decidir e comprar: etiqueta vermelha da categoria, nome do produto (44/32/30px), \"Cód. [SKU]\",\n// selo de parceiro, o Price grande, quantidade + \"Adicionar ao carrinho\" (preto), \"Comprar agora\" (o único vermelho)\n// e a BenefitList.\n// Esgotado (`available: false`): o selo \"Volta já já\" e o \"Me avise quando chegar\" (contorno) no lugar dos botões.\n// `partner` (ex.: \"BPower\"): põe o selo \"Parceiro BPower\" e troca a 1ª linha de benefícios para \"Enviado pela BPower\".\n// Não desenha selo, preço, quantidade, botão nem lista: usa Badge, Price, QuantityStepper, Button e BenefitList por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst BENEFITS = [\n  { icon: 'truck', title: 'Enviamos para todo o Brasil', text: 'O frete é calculado no fechamento do pedido.' },\n  { icon: 'card', title: 'Pix ou cartão em até [N]x', text: 'Pagamento seguro, com antifraude em todas as compras.' },\n  { icon: 'swap', title: 'Troca e devolução', link: { label: 'Ver política de trocas', href: '/politicas/trocas-e-devolucoes' } }\n];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.buy { --red-500: #c8102e; --ink: #0b0b0c; --grey-500: #6b6e73; --line: #e4e4e2;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: flex; flex-direction: column; width: 100%; color: var(--ink); }\np, h1 { margin: 0; }\n.cat { font-size: 12px; font-weight: 700; letter-spacing: .24em; line-height: 1.3; text-transform: uppercase; color: var(--red-500); margin-bottom: 12px; }\n.title { font-size: 44px; font-weight: 800; font-stretch: 115%; line-height: .9; letter-spacing: -.01em; text-transform: uppercase; color: var(--ink); overflow-wrap: break-word; }\n.sku { margin-top: 10px; font-size: 14px; color: var(--grey-500); }\n.badge { margin-top: 12px; height: 24px; }\n.sec { padding: 20px 0 24px; border-bottom: 1px solid var(--line); }\n.actions { display: flex; flex-direction: column; gap: 12px; padding: 24px 0; }\n.row { display: flex; gap: 12px; align-items: stretch; }\n.qty { flex: none; width: 120px; height: 52px; }\n.grow { flex: 1; min-width: 0; height: 52px; }\n.full { width: 100%; height: 52px; }\n.soldout { height: 28px; }\n\n.l-tablet .title { font-size: 32px; line-height: .95; }\n.l-tablet .cat { font-size: 11px; margin-bottom: 10px; }\n\n.l-mobile .cat { font-size: 11px; margin-bottom: 10px; }\n.l-mobile .title { font-size: 30px; font-stretch: 112%; line-height: .98; letter-spacing: 0; }\n.l-mobile .sku { font-size: 13px; }\n.l-mobile .sec { padding: 20px 0; }\n.l-mobile .actions { padding: 20px 0; gap: 10px; }\n.l-mobile .row { gap: 8px; }\n.l-mobile .qty { width: 96px; }\n.l-mobile .badge { height: 20px; }\n.l-mobile .soldout { height: 22px; }\n`,\n\n  mounted(d2) { FONT(); },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const badgeRef = refOf(d2.param('badge'));\n    const priceRef = refOf(d2.param('priceComponent'));\n    const qtyRef = refOf(d2.param('quantityStepper'));\n    const btnRef = refOf(d2.param('button'));\n    const listRef = refOf(d2.param('benefitList'));\n    const iconRef = refOf(d2.param('iconComponent'));\n    const available = p.available == null || p.available === '' ? true : truthy(p.available);\n    const partner = p.partner ? String(p.partner) : '';\n    const name = p.name || 'Shampoo automotivo neutro';\n    const category = p.category == null ? 'Lavagem' : p.category;\n    const sku = p.sku == null ? '[SKU]' : p.sku;\n    const getQty = () => (d2.root && d2.root.__lfQty) || 1;\n\n    const badgeLabel = p.badgeLabel || (partner ? 'Parceiro ' + partner : '');\n    const badge = badgeLabel && badgeRef\n      ? `<div class=\"badge\">${d2.render(badgeRef, { label: badgeLabel, shortLabel: partner || '', tone: 'red', layout }, { key: 'badge' })}</div>`\n      : '';\n\n    const price = priceRef\n      ? `<div class=\"sec\">${d2.render(priceRef, {\n          price: p.price == null ? 89.9 : p.price, pixPrice: p.pixPrice, pixDiscount: p.pixDiscount,\n          installments: p.installments == null ? 3 : p.installments, oldPrice: p.oldPrice, size: 'buybox', layout\n        }, { key: 'price', style: 'height:auto' })}</div>`\n      : '';\n\n    const btn = (key, cls, label, shortLabel, variant, evt) => btnRef ? `<div class=\"${cls}\">${d2.render(btnRef, {\n        label, shortLabel: shortLabel || '', variant, size: 'lg', fullWidth: 'always', layout\n      }, { key, height: 52, onClick: () => emit(d2, evt, getQty()) })}</div>` : '';\n\n    let actions;\n    if (available) {\n      const qty = qtyRef\n        ? `<div class=\"qty\">${d2.render(qtyRef, { layout, min: 1, max: p.maxQuantity || 99, value: 1, iconComponent: iconRef }, {\n            key: 'qty', height: 52,\n            onChange: (v) => { if (d2.root) d2.root.__lfQty = v; emit(d2, 'onQuantityChange', v); }\n          })}</div>`\n        : '';\n      actions = `<div class=\"row\">${qty}${btn('add', 'grow', p.addLabel || 'Adicionar à sacola', p.addShortLabel || 'Adicionar', 'primary', 'onAdd')}</div>\n        ${btn('buy', 'full', p.buyNowLabel || 'Comprar agora', '', 'brand', 'onBuyNow')}`;\n    } else {\n      const sold = badgeRef\n        ? `<div class=\"soldout\">${d2.render(badgeRef, { label: p.soldOutLabel || 'Volta já já', isStatus: true, tone: 'ink', layout }, { key: 'sold' })}</div>`\n        : '';\n      actions = `${sold}${btn('notify', 'full', p.notifyLabel || 'Me avise quando chegar', 'Avise-me', 'outline', 'onNotify')}`;\n    }\n\n    let items = list(p.benefits);\n    if (!items.length) {\n      items = BENEFITS.slice();\n      if (partner) items[0] = { icon: 'truck', title: 'Enviado pela ' + partner, text: 'O parceiro envia direto para você e informa o código de rastreio.' };\n    }\n    const showBenefits = p.showBenefits == null || p.showBenefits === '' ? true : truthy(p.showBenefits);\n    const benefits = showBenefits && listRef\n      ? d2.render(listRef, { items, layout, iconComponent: iconRef }, {\n          key: 'ben' + (partner ? '-' + partner : ''), style: 'height:auto',\n          onLink: (h) => emit(d2, 'onBenefitLink', h)\n        })\n      : '';\n\n    return `<div class=\"buy l-${layout}\">\n      ${category ? `<p class=\"cat\">${esc(category)}</p>` : ''}\n      <h1 class=\"title\">${esc(name)}</h1>\n      ${sku ? `<p class=\"sku\">Cód. ${esc(sku)}</p>` : ''}\n      ${badge}\n      ${price}\n      <div class=\"actions\">${actions}</div>\n      ${benefits}\n    </div>`;\n  }\n};"}},"addLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"addLabel"}}}},"addShortLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"addShortLabel"}}}},"available":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"available"}}}},"badge":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"badge"}}}},"badgeLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"badgeLabel"}}}},"benefitList":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"benefitList"}}}},"benefits":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"benefits"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"buyNowLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"buyNowLabel"}}}},"category":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"category"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"installments":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"installments"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"maxQuantity":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"maxQuantity"}}}},"name":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"name"}}}},"notifyLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notifyLabel"}}}},"oldPrice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"oldPrice"}}}},"onAdd":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onAdd"}}}},"onBenefitLink":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onBenefitLink"}}}},"onBuyNow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onBuyNow"}}}},"onNotify":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onNotify"}}}},"onQuantityChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onQuantityChange"}}}},"partner":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"partner"}}}},"pixDiscount":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"pixDiscount"}}}},"pixPrice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"pixPrice"}}}},"price":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"price"}}}},"priceComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"priceComponent"}}}},"quantityStepper":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"quantityStepper"}}}},"showBenefits":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"showBenefits"}}}},"sku":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"sku"}}}},"soldOutLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"soldOutLabel"}}}}}}}}}},{"_id":"6ababc85440fbc0d402d16b5","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"ProductDetails","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// ProductDetails — Loja Lucas Fontana\n// O conteúdo de uma aba do produto: texto em 16px cinza, CheckList de benefícios e/ou a tabela da ficha técnica,\n// com o QuoteCard ao lado no desktop (embaixo no tablet e no mobile).\n// Na aba \"Como usar\", `videoHref` põe o link para o vídeo curto de aplicação.\n// A compatibilidade de peças (\"para qual carro serve\") entra como linhas da ficha técnica (`specs`).\n// O texto chega por `body` (o nome `text` é reservado do Data2).\n// Não desenha lista nem card: usa CheckList e QuoteCard por parâmetro (e repassa o Icon).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst ic = (d2, ref, name, size, color, key) => ref\n  ? d2.render(ref, { name, size, iconColor: color || 'currentColor' }, { key, width: size, height: size, style: 'flex:none' })\n  : '';\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst paras = (t) => String(t == null ? '' : t).split(/\\n\\s*\\n/).map((x) => x.trim()).filter(Boolean)\n  .map((x) => `<p class=\"tx\">${esc(x).replace(/\\n/g, '<br>')}</p>`).join('');\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.det { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-700: #45474b; --line: #e4e4e2;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 48px; align-items: start; width: 100%; color: var(--ink); }\n.det.solo { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }\n.txt { display: flex; flex-direction: column; gap: 20px; min-width: 0; }\n.tx { margin: 0; font-size: 16px; line-height: 1.75; color: var(--grey-700); max-width: 720px; }\ntable { width: 100%; border-collapse: collapse; font-size: 15px; }\nth, td { text-align: left; padding: 12px 0; border-bottom: 1px solid var(--line); vertical-align: top; line-height: 1.45; }\nth { width: 40%; font-weight: 600; color: var(--grey-700); padding-right: 16px; }\ntd { color: var(--ink); }\n.vid { display: inline-flex; align-items: center; gap: 12px; align-self: flex-start; color: var(--ink); text-decoration: none; font-size: 15px; font-weight: 700; }\n.vid .sq { width: 36px; height: 36px; background: var(--red-500); color: var(--white); display: flex; align-items: center; justify-content: center; flex: none; }\n.vid span.lb { text-decoration: underline; text-underline-offset: 3px; }\n.vid:hover span.lb { color: var(--red-500); }\n.vid:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.det.l-tablet { grid-template-columns: minmax(0, 1fr); gap: 28px; }\n.det.l-mobile { grid-template-columns: minmax(0, 1fr); gap: 20px; }\n.l-mobile .tx { font-size: 15px; }\n`,\n\n  mounted(d2) {\n    FONT();\n    d2.on('.vid', 'click', (e, el) => emit(d2, 'onVideo', el.getAttribute('href')));\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const clRef = refOf(d2.param('checkList'));\n    const qcRef = refOf(d2.param('quoteCard'));\n    const iconRef = refOf(d2.param('iconComponent'));\n    const benefits = list(p.benefits);\n    const specs = list(p.specs).map((r) => Array.isArray(r) ? { label: r[0], value: r[1] } : (r || {})).filter((r) => r.label);\n\n    const check = benefits.length && clRef\n      ? d2.render(clRef, { items: benefits, layout, iconComponent: iconRef }, { key: 'cl', style: 'height:auto' })\n      : '';\n    const table = specs.length\n      ? `<table><tbody>${specs.map((r) => `<tr><th scope=\"row\">${esc(r.label)}</th><td>${esc(r.value)}</td></tr>`).join('')}</tbody></table>`\n      : '';\n    const vid = p.videoHref\n      ? `<a class=\"vid\" href=\"${esc(p.videoHref)}\" target=\"_blank\" rel=\"noopener\"><span class=\"sq\" aria-hidden=\"true\">${ic(d2, iconRef, 'play', 14, '#ffffff', 'vp')}</span><span class=\"lb\">${esc(p.videoLabel || 'Ver o vídeo de aplicação')}</span></a>`\n      : '';\n    const quote = p.quote && qcRef\n      ? `<div class=\"qc\">${d2.render(qcRef, { quote: p.quote, author: p.author, eyebrow: p.eyebrow, layout }, { key: 'qc', style: 'height:auto' })}</div>`\n      : '';\n\n    return `<div class=\"det l-${layout}${quote ? '' : ' solo'}\">\n      <div class=\"txt\">${paras(p.body)}${check}${table}${vid}</div>\n      ${quote}\n    </div>`;\n  }\n};"}},"author":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"author"}}}},"benefits":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"benefits"}}}},"body":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"body"}}}},"checkList":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkList"}}}},"eyebrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"eyebrow"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onVideo":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onVideo"}}}},"quote":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"quote"}}}},"quoteCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"quoteCard"}}}},"specs":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"specs"}}}},"videoHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"videoHref"}}}},"videoLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"videoLabel"}}}}}}}}}},{"_id":"6ababca769443659fcd00566","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Tabs","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Tabs — Loja Lucas Fontana\n// As informações do produto em abas no desktop e no tablet (\"Descrição\", \"Como usar\", \"Ficha técnica\"):\n// rótulos de 13px em caixa alta, cinza até serem escolhidos; a aba ativa fica preta com sublinhado vermelho de 3px.\n// No mobile as mesmas abas viram sanfona: linhas de 64px com o quadrado de 28px (\"+\" preto fechado, \"−\" vermelho aberto);\n// a primeira começa aberta. As setas do teclado trocam de aba.\n// Cada item é o conteúdo de um ProductDetails: `{label, body, benefits, specs, quote, author, videoHref, videoLabel}`.\n// Já traz o respiro da página (96/40/20px nas laterais e 120/88/64px embaixo); `padded: false` tira.\n// Não desenha o conteúdo: usa ProductDetails por parâmetro (e repassa CheckList, QuoteCard e Icon).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst nums = (v) => {\n  if (Array.isArray(v)) return v.map(Number).filter((n) => !isNaN(n));\n  if (typeof v === 'number') return [v];\n  if (typeof v === 'string' && v.trim()) return v.split(',').map((s) => Number(s.trim())).filter((n) => !isNaN(n));\n  return null;\n};\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst ic = (d2, ref, name, size, color, key) => ref\n  ? d2.render(ref, { name, size, iconColor: color || 'currentColor' }, { key, width: size, height: size, style: 'flex:none' })\n  : '';\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst PAD = { desktop: '0 96px 120px', tablet: '0 40px 88px', mobile: '0 20px 64px' };\nconst DEMO = [\n  { label: 'Descrição',\n    body: '[Descrição do produto: o que é, para que serve e por que o Lucas recomenda. Texto escrito para o cliente e para buscas em IA — direto, com as palavras que as pessoas usam para procurar.]',\n    benefits: ['[Benefício principal do produto]', '[Segundo benefício — ex.: rendimento, proteção, cheiro]', '[Terceiro benefício — ex.: seguro para a pintura]'],\n    quote: '[Comentário do Lucas sobre o produto — pode vir de uma fala do vídeo.]' },\n  { label: 'Como usar', body: '[Passo a passo de aplicação — com link para o vídeo curto do Lucas.]', videoHref: '#', videoLabel: 'Ver o vídeo de aplicação' },\n  { label: 'Ficha técnica', specs: [['Diluição', '[1:100]'], ['pH', '[Neutro]'], ['Aplicação', '[Para qual carro/uso serve]'], ['Marca', 'Lucas Fontana']] }\n];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.tabs { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-500: #6b6e73; --line: #e4e4e2;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased; width: 100%; background: var(--white); color: var(--ink); }\n.list { display: flex; gap: 32px; border-bottom: 1px solid var(--line); overflow-x: auto; scrollbar-width: none; }\n.list::-webkit-scrollbar { display: none; }\n.tab { position: relative; flex-shrink: 0; height: 52px; margin: 0; padding: 0; border: 0; background: transparent;\n  font: 800 13px/1 ${FF}; letter-spacing: .14em; text-transform: uppercase; color: var(--grey-500); cursor: pointer; }\n.tab:hover, .tab[aria-selected=\"true\"] { color: var(--ink); }\n.tab[aria-selected=\"true\"]::after { content: ''; position: absolute; left: 0; right: 0; bottom: -1px; height: 3px; background: var(--red-500); }\n.tab:focus-visible, .head:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.panel { padding-top: 32px; }\n.acc { border-bottom: 1px solid var(--line); }\n.acc:first-child { border-top: 1px solid var(--line); }\n.head { display: flex; width: 100%; align-items: center; justify-content: space-between; gap: 12px; min-height: 64px; margin: 0; padding: 0; border: 0; background: transparent;\n  font: 800 14px/1.2 ${FF}; letter-spacing: .14em; text-transform: uppercase; color: var(--ink); cursor: pointer; text-align: left; }\n.head i { flex: none; width: 28px; height: 28px; background: var(--ink); color: var(--white); display: flex; align-items: center; justify-content: center; font-style: normal; }\n.head[aria-expanded=\"true\"] i { background: var(--red-500); }\n.body { padding: 4px 0 24px; }\n`,\n\n  mounted(d2) {\n    FONT();\n    const items = () => { const p = d2.params || {}; return list(p.items).length ? list(p.items) : DEMO; };\n    const pick = (k) => {\n      const n = items().length;\n      const i = ((k % n) + n) % n;\n      d2.state.active = i;\n      emit(d2, 'onChange', i);\n      setTimeout(() => { const el = d2.$(`.tab[data-k=\"${i}\"]`); if (el) el.focus(); }, 0);\n    };\n    d2.on('.tab', 'click', (e, el) => { d2.state.active = Number(el.dataset.k); emit(d2, 'onChange', d2.state.active); });\n    d2.on('.list', 'keydown', (e) => {\n      if (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') return;\n      e.preventDefault();\n      pick((d2.state.active || 0) + (e.key === 'ArrowRight' ? 1 : -1));\n    });\n    d2.on('.head', 'click', (e, el) => {\n      const k = Number(el.dataset.k);\n      const p = d2.params || {};\n      const cur = (d2.state.open || nums(p.defaultOpen) || [0]).slice();\n      d2.state.open = cur.indexOf(k) >= 0 ? cur.filter((x) => x !== k) : cur.concat([k]);\n    });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const items = list(p.items).length ? list(p.items) : DEMO;\n    const pdRef = refOf(d2.param('productDetails'));\n    const clRef = refOf(d2.param('checkList'));\n    const qcRef = refOf(d2.param('quoteCard'));\n    const iconRef = refOf(d2.param('iconComponent'));\n    const padded = p.padded == null || p.padded === '' ? true : truthy(p.padded);\n    const active = Math.min(d2.state.active || 0, items.length - 1);\n    const open = d2.state.open || nums(p.defaultOpen) || [0];\n\n    const details = (it, k) => pdRef ? d2.render(pdRef, {\n      body: it.body || '', benefits: it.benefits || [], specs: it.specs || [], quote: it.quote || '', author: it.author || '',\n      eyebrow: it.eyebrow || '', videoHref: it.videoHref || '', videoLabel: it.videoLabel || '',\n      layout, checkList: clRef, quoteCard: qcRef, iconComponent: iconRef\n    }, { key: 'pd-' + k + '-' + layout, style: 'height:auto' }) : '';\n\n    let inner;\n    if (layout === 'mobile') {\n      inner = `<div class=\"accs\">${items.map((it, k) => {\n        const isOpen = open.indexOf(k) >= 0;\n        return `<div class=\"acc\">\n          <button type=\"button\" class=\"head\" data-k=\"${k}\" aria-expanded=\"${isOpen ? 'true' : 'false'}\" aria-controls=\"tp-${k}\">\n            <span>${esc(it.label)}</span><i aria-hidden=\"true\">${ic(d2, iconRef, isOpen ? 'minus' : 'plus', 14, '#ffffff', 'h' + k + (isOpen ? 'm' : 'p'))}</i>\n          </button>\n          ${isOpen ? `<div class=\"body\" id=\"tp-${k}\" role=\"region\">${details(it, k)}</div>` : ''}\n        </div>`;\n      }).join('')}</div>`;\n    } else {\n      inner = `<div class=\"list\" role=\"tablist\" aria-label=\"${esc(p.ariaLabel || 'Informações do produto')}\">${items.map((it, k) =>\n        `<button type=\"button\" class=\"tab\" role=\"tab\" id=\"tt-${k}\" data-k=\"${k}\" aria-selected=\"${k === active ? 'true' : 'false'}\" aria-controls=\"tp-${k}\" tabindex=\"${k === active ? 0 : -1}\">${esc(it.label)}</button>`\n      ).join('')}</div>\n      <div class=\"panel\" role=\"tabpanel\" id=\"tp-${active}\" aria-labelledby=\"tt-${active}\">${details(items[active] || {}, active)}</div>`;\n    }\n    return `<section class=\"tabs l-${layout}\" style=\"padding:${padded ? PAD[layout] : '0'}\" aria-label=\"Detalhes do produto\">${inner}</section>`;\n  }\n};"}},"ariaLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ariaLabel"}}}},"checkList":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkList"}}}},"defaultOpen":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"defaultOpen"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"items":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"items"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChange"}}}},"padded":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"padded"}}}},"productDetails":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"productDetails"}}}},"quoteCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"quoteCard"}}}}}}}}}},{"_id":"6ababcbfbeb54327cc83c216","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"ProductLayout","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// ProductLayout — Loja Lucas Fontana\n// O topo da página de produto: breadcrumb e, embaixo, a galeria e a BuyBox lado a lado.\n// Desktop: galeria à esquerda e BuyBox de 471px à direita, que fica presa na tela enquanto a galeria rola,\n// 56px entre as duas; uma hairline fecha o bloco.\n// Tablet: galeria em cima e BuyBox embaixo, na largura toda.\n// Mobile: a galeria vai de ponta a ponta; o breadcrumb rola para o lado em vez de quebrar.\n// As fotos chegam por `images` (itens do ProductGallery) e o produto por `product` (parâmetros da BuyBox).\n// Não desenha nada disso: usa Breadcrumb, ProductGallery e BuyBox por parâmetro (e repassa Badge, Price,\n// QuantityStepper, Button, BenefitList e Icon para eles).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst PAD = { desktop: '32px 96px 64px', tablet: '28px 40px 56px', mobile: '20px 20px 48px' };\nconst CRUMB_H = { desktop: 24, tablet: 24, mobile: 30 };\n// Sacola no navegador (mesma chave da página Sacola): [{sku, qty}]\nconst addToBag = (sku, qty) => {\n  if (!sku) return;\n  try {\n    const bag = JSON.parse(localStorage.getItem('lf-sacola') || '[]');\n    const l = Array.isArray(bag) ? bag : [];\n    const f = l.find((y) => y && y.sku === sku);\n    if (f) f.qty = (Number(f.qty) || 0) + (Number(qty) || 1); else l.push({ sku, qty: Number(qty) || 1 });\n    localStorage.setItem('lf-sacola', JSON.stringify(l));\n    window.dispatchEvent(new CustomEvent('lf-sacola', { detail: { count: l.reduce((s, y) => s + (Number(y.qty) || 0), 0) } }));\n  } catch (e) { /* sem storage */ }\n};\nconst CRUMBS = [{ label: 'Início', href: '/' }, { label: 'Cuidado automotivo', href: '/categoria/cuidado-automotivo' }, { label: 'Lavagem', href: '/categoria/cuidado-automotivo/lavagem' }, { label: 'Shampoo automotivo neutro' }];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.pdp { --line: #e4e4e2; width: 100%; background: #ffffff; }\n.in { display: flex; flex-direction: column; gap: 24px; }\n.crumb { width: 100%; }\n.grid { display: grid; grid-template-columns: minmax(0, 1fr) 471px; gap: 56px; align-items: start; padding-bottom: 56px; border-bottom: 1px solid var(--line); }\n.gal { min-width: 0; }\n.buy { position: sticky; top: 24px; min-width: 0; }\n.l-tablet .grid { grid-template-columns: minmax(0, 1fr); gap: 32px; padding-bottom: 0; border-bottom: 0; }\n.l-tablet .buy { position: static; }\n.l-mobile .in { gap: 16px; }\n.l-mobile .grid { grid-template-columns: minmax(0, 1fr); gap: 24px; padding-bottom: 0; border-bottom: 0; }\n.l-mobile .buy { position: static; }\n.l-mobile .gal { margin: 0 -20px; }\n`,\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const bcRef = refOf(d2.param('breadcrumb'));\n    const galRef = refOf(d2.param('productGallery'));\n    const buyRef = refOf(d2.param('buyBox'));\n    const iconRef = refOf(d2.param('iconComponent'));\n    const crumbs = list(p.crumbs).length ? list(p.crumbs) : CRUMBS;\n    const product = obj(p.product);\n\n    const crumb = bcRef\n      ? `<div class=\"crumb\" style=\"height:${CRUMB_H[layout]}px\">${d2.render(bcRef, { items: crumbs, layout, scroll: layout === 'mobile' }, {\n          key: 'bc', onNavigate: (h) => emit(d2, 'onNavigate', h) })}</div>`\n      : '';\n    const gallery = galRef\n      ? d2.render(galRef, { items: list(p.images), layout, iconComponent: iconRef }, { key: 'gal', style: 'height:auto' })\n      : '';\n    const buy = buyRef\n      ? d2.render(buyRef, Object.assign({}, product, {\n          layout,\n          badge: refOf(d2.param('badge')), priceComponent: refOf(d2.param('priceComponent')),\n          quantityStepper: refOf(d2.param('quantityStepper')), button: refOf(d2.param('button')),\n          benefitList: refOf(d2.param('benefitList')), iconComponent: iconRef\n        }), {\n          key: 'buy' + (product.available === false || product.available === 'false' ? '-off' : '') + (product.partner ? '-' + product.partner : ''),\n          style: 'height:auto',\n          onAdd: (q) => { addToBag(product.sku, q); emit(d2, 'onAdd', q); }, onBuyNow: (q) => { addToBag(product.sku, q); emit(d2, 'onBuyNow', q); },\n          onNotify: (q) => emit(d2, 'onNotify', q), onQuantityChange: (q) => emit(d2, 'onQuantityChange', q)\n        })\n      : '';\n\n    return `<div class=\"pdp l-${layout}\"><div class=\"in\" style=\"padding:${PAD[layout]}\">\n      ${crumb}\n      <div class=\"grid\"><div class=\"gal\">${gallery}</div><div class=\"buy\">${buy}</div></div>\n    </div></div>`;\n  }\n};"}},"badge":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"badge"}}}},"benefitList":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"benefitList"}}}},"breadcrumb":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"breadcrumb"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"buyBox":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"buyBox"}}}},"crumbs":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"crumbs"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"images":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"images"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onAdd":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onAdd"}}}},"onBuyNow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onBuyNow"}}}},"onNavigate":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onNavigate"}}}},"onNotify":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onNotify"}}}},"onQuantityChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onQuantityChange"}}}},"priceComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"priceComponent"}}}},"product":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"product"}}}},"productGallery":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"productGallery"}}}},"quantityStepper":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"quantityStepper"}}}}}}}}}},{"_id":"6abbd2a25b997bc7f1419f8c","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"FormField","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// FormField — Loja Lucas Fontana\n// O campo de formulário em tamanho cheio: rótulo de 14px em negrito, campo branco de 48px com borda line-strong\n// (fica preta, com anel de 1px, no foco) e, embaixo, dica, erro, contador ou link.\n// `optional` põe \"(opcional)\" sob o rótulo; `hint` é a dica cinza; `error` deixa a borda vermelha e mostra a mensagem;\n// `linkLabel`/`linkHref` põem um link auxiliar sublinhado (\"Não sei meu CEP\").\n// Com `type: \"password\"`, aparece o botão de olho para mostrar/esconder a senha.\n// `multiline: true` vira uma área de texto de 176px (redimensionável); com `maxLength` + `counter: true`\n// mostra \"0 de 1.000 caracteres\" embaixo.\n// `options: [{value, label}]` vira um select com seta (o `placeholder` vira a primeira opção vazia).\n// `mask` formata enquanto a pessoa digita: `cep` (00000-000), `phone` ((00) 00000-0000), `uf` (2 letras maiúsculas),\n// `cpf` (000.000.000-00), `cnpj` (00.000.000/0000-00, aceita letras nas 12 primeiras posições — CNPJ alfanumérico),\n// `digits` (só números). CEP, telefone, CPF e dígitos abrem o teclado numérico; CNPJ abre o teclado comum, em maiúsculas.\n// Placeholder é exemplo (\"seuemail@exemplo.com\"), nunca o rótulo.\n// Não desenha ícone: usa o Icon pelo parâmetro `iconComponent`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst arr = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst ic = (d2, ref, name, size, color, key) => ref\n  ? d2.render(ref, { name, size, iconColor: color || 'currentColor' }, { key, width: size, height: size, style: 'flex:none' })\n  : '';\nconst TYPES = ['text', 'email', 'password', 'tel', 'number', 'search', 'url'];\nconst CHEV = '<svg class=\"chev\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"m6 9 6 6 6-6\"/></svg>';\nconst num = (v) => { const n = parseInt(v, 10); return isFinite(n) && n > 0 ? n : 0; };\nconst fmtN = (n) => String(n).replace(/\\B(?=(\\d{3})+(?!\\d))/g, '.');\n\n// Máscaras: recebem o texto digitado e devolvem o formatado\nconst pattern = (d, pat) => { let out = '', i = 0; for (const c of pat) { if (i >= d.length) break; if (c === '0') out += d[i++]; else out += c; } return out; };\nconst MASKS = {\n  digits: (v) => v.replace(/\\D/g, ''),\n  cep: (v) => pattern(v.replace(/\\D/g, '').slice(0, 8), '00000-000'),\n  cpf: (v) => pattern(v.replace(/\\D/g, '').slice(0, 11), '000.000.000-00'),\n  cnpj: (v) => {\n    // CNPJ alfanumérico (a partir de jul/2026): 12 primeiras posições aceitam A–Z e 0–9; as 2 últimas (DV) só números\n    const s = String(v).toUpperCase().replace(/[^A-Z0-9]/g, '');\n    let out = '';\n    for (const c of s) { if (out.length >= 14) break; if (out.length < 12 || /\\d/.test(c)) out += c; }\n    return pattern(out, '00.000.000/0000-00');\n  },\n  uf: (v) => v.replace(/[^a-zA-Z]/g, '').slice(0, 2).toUpperCase(),\n  phone: (v) => { const d = v.replace(/\\D/g, '').slice(0, 11); return d.length > 10 ? pattern(d, '(00) 00000-0000') : pattern(d, '(00) 0000-0000'); }\n};\nconst NUMERIC = ['digits', 'cep', 'cpf', 'phone'];\nconst CAPS = ['cnpj', 'uf'];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.ff { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-500: #6b6e73; --grey-700: #45474b; --line-strong: #d9d9d6;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: flex; flex-direction: column; gap: 8px; min-width: 0; width: 100%; }\nlabel { display: flex; flex-direction: column; gap: 2px; font-size: 14px; font-weight: 700; color: var(--ink); }\nlabel small { font-size: 13px; font-weight: 400; color: var(--grey-500); }\n.box { position: relative; display: flex; align-items: center; }\ninput, select, textarea { width: 100%; margin: 0; border: 1px solid var(--line-strong); border-radius: 2px; background: var(--white);\n  font: 400 16px/1.2 ${FF}; color: var(--ink); outline: none; -webkit-appearance: none; appearance: none; }\ninput, select { height: 48px; padding: 0 14px; }\nselect { padding-right: 40px; cursor: pointer; }\nselect.empty { color: var(--grey-500); }\n.chev { position: absolute; right: 12px; width: 16px; height: 16px; color: var(--ink); pointer-events: none; }\n.chev-ic { position: absolute; right: 12px; display: flex; pointer-events: none; }\ntextarea { display: block; height: 176px; min-height: 120px; padding: 12px 14px; line-height: 1.5; resize: vertical; }\ninput::placeholder, textarea::placeholder { color: var(--grey-500); }\ninput:focus, select:focus, textarea:focus { border-color: var(--ink); box-shadow: 0 0 0 1px var(--ink); }\n.has-reveal input { padding-right: 48px; }\n.reveal { position: absolute; right: 4px; width: 40px; height: 40px; margin: 0; padding: 0; border: 0; background: transparent; color: var(--grey-700);\n  display: flex; align-items: center; justify-content: center; cursor: pointer; }\n.reveal:focus-visible { outline: 2px solid var(--red-500); outline-offset: -2px; }\n.error input, .error select, .error textarea { border-color: var(--red-500); box-shadow: 0 0 0 1px var(--red-500); }\np { margin: 0; font-size: 13px; line-height: 1.4; }\n.hint, .count { color: var(--grey-500); }\n.count.full { color: var(--ink); font-weight: 600; }\n.err { font-weight: 600; color: var(--red-500); }\na { align-self: flex-start; font-size: 13px; font-weight: 600; color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }\na:hover { color: var(--red-500); }\na:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n`,\n\n  mounted(d2) {\n    FONT();\n    const keep = (el) => { if (d2.root) d2.root.__lfVal = el ? el.value : ''; };\n    const count = (el) => {\n      const c = d2.$('.count');\n      if (!c || !el) return;\n      const max = num(el.getAttribute('maxlength'));\n      const n = el.value.length;\n      const nEl = c.querySelector('.n');\n      if (nEl) nEl.textContent = fmtN(n);\n      if (max) c.classList.toggle('full', n >= max);\n    };\n    d2.on('.reveal', 'click', () => { keep(d2.$('input')); d2.state.show = !d2.state.show; });\n    d2.on('input', 'input', (e, el) => {\n      const m = MASKS[(d2.params || {}).mask];\n      if (m) { const v = m(el.value); if (v !== el.value) el.value = v; }\n      keep(el); emit(d2, 'onInput', el.value);\n    });\n    d2.on('input', 'change', (e, el) => emit(d2, 'onChange', el.value));\n    d2.on('input, textarea, select', 'focusout', (e, el) => emit(d2, 'onBlur', el.value));\n    d2.on('textarea', 'input', (e, el) => { keep(el); count(el); emit(d2, 'onInput', el.value); });\n    d2.on('textarea', 'change', (e, el) => emit(d2, 'onChange', el.value));\n    d2.on('select', 'change', (e, el) => {\n      keep(el); el.classList.toggle('empty', !el.value);\n      emit(d2, 'onInput', el.value); emit(d2, 'onChange', el.value);\n    });\n    d2.on('a', 'click', (e, el) => emit(d2, 'onLink', el.getAttribute('href')));\n  },\n\n  updated(d2) {\n    // Mantém o que foi digitado quando o campo redesenha (mostrar/esconder senha, erro que aparece ou some)\n    const el = d2.$('input, textarea, select');\n    if (el && d2.root && d2.root.__lfVal != null && el.value !== d2.root.__lfVal) el.value = d2.root.__lfVal;\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const iconRef = refOf(d2.param('iconComponent'));\n    const options = arr(p.options).map((o) => (o && typeof o === 'object' ? o : { value: String(o), label: String(o) }));\n    const kind = options.length ? 'select' : (truthy(p.multiline) ? 'textarea' : 'input');\n    const baseType = TYPES.indexOf(p.type) >= 0 ? p.type : 'text';\n    const isPw = kind === 'input' && baseType === 'password';\n    const reveal = isPw && (p.reveal == null || p.reveal === '' ? true : truthy(p.reveal));\n    const show = !!d2.state.show;\n    const type = isPw && show ? 'text' : baseType;\n    const mask = MASKS[p.mask] ? p.mask : '';\n    const inputMode = p.inputMode || (NUMERIC.indexOf(mask) >= 0 ? 'numeric' : '');\n    const max = num(p.maxLength);\n    const withCount = kind === 'textarea' && max > 0 && truthy(p.counter);\n    const id = 'f';\n    const err = p.error ? String(p.error) : '';\n    const hint = p.hint ? String(p.hint) : '';\n    const raw = p.value == null ? '' : String(p.value);\n    const val = mask && kind === 'input' ? MASKS[mask](raw) : raw;\n    const describe = [hint ? id + '-h' : '', err ? id + '-e' : '', withCount ? id + '-c' : ''].filter(Boolean).join(' ');\n    const common = [\n      `id=\"${id}\"`,\n      p.name ? `name=\"${esc(p.name)}\"` : '',\n      p.autoComplete ? `autocomplete=\"${esc(p.autoComplete)}\"` : '',\n      describe ? `aria-describedby=\"${describe}\"` : '',\n      p.ariaLabel && !p.label ? `aria-label=\"${esc(p.ariaLabel)}\"` : '',\n      err ? 'aria-invalid=\"true\"' : '',\n      truthy(p.required) ? 'required' : ''\n    ];\n\n    let control;\n    if (kind === 'select') {\n      const ph = p.placeholder ? `<option value=\"\"${val ? '' : ' selected'}>${esc(p.placeholder)}</option>` : '';\n      const opts = options.map((o) => `<option value=\"${esc(o.value)}\"${String(o.value) === val ? ' selected' : ''}>${esc(o.label != null ? o.label : o.value)}</option>`).join('');\n      const chev = iconRef ? `<span class=\"chev-ic\" aria-hidden=\"true\">${ic(d2, iconRef, 'chevron-down', 16, '#0b0b0c', 'chev')}</span>` : CHEV;\n      control = `<select class=\"${!val && p.placeholder ? 'empty' : ''}\" ${common.filter(Boolean).join(' ')}>${ph}${opts}</select>${chev}`;\n    } else if (kind === 'textarea') {\n      const a = common.concat([\n        p.placeholder ? `placeholder=\"${esc(p.placeholder)}\"` : '',\n        max ? `maxlength=\"${max}\"` : '',\n        p.rows ? `rows=\"${num(p.rows)}\"` : ''\n      ]).filter(Boolean).join(' ');\n      control = `<textarea ${a}>${esc(val)}</textarea>`;\n    } else {\n      const a = common.concat([\n        `type=\"${type}\"`,\n        p.placeholder ? `placeholder=\"${esc(p.placeholder)}\"` : '',\n        inputMode ? `inputmode=\"${esc(inputMode)}\"` : '',\n        CAPS.indexOf(mask) >= 0 ? 'autocapitalize=\"characters\" spellcheck=\"false\"' : '',\n        max ? `maxlength=\"${max}\"` : '',\n        val !== '' ? `value=\"${esc(val)}\"` : ''\n      ]).filter(Boolean).join(' ');\n      const eye = reveal\n        ? `<button type=\"button\" class=\"reveal\" aria-label=\"${show ? 'Esconder senha' : 'Mostrar senha'}\" aria-pressed=\"${show ? 'true' : 'false'}\">${ic(d2, iconRef, show ? 'eye-off' : 'eye', 20, '#45474b', 'eye-' + (show ? 'off' : 'on'))}</button>`\n        : '';\n      control = `<input ${a}>${eye}`;\n    }\n\n    const n = (d2.root && d2.root.__lfVal != null ? d2.root.__lfVal : val).length;\n    const counter = withCount\n      ? `<p class=\"count${n >= max ? ' full' : ''}\" id=\"${id}-c\" aria-live=\"polite\"><span class=\"n\">${fmtN(n)}</span> de ${fmtN(max)} caracteres</p>`\n      : '';\n\n    return `<div class=\"ff l-${layout}${err ? ' error' : ''}${reveal ? ' has-reveal' : ''}\">\n      ${p.label ? `<label for=\"${id}\">${esc(p.label)}${truthy(p.optional) ? '<small>(opcional)</small>' : ''}</label>` : ''}\n      <div class=\"box\">${control}</div>\n      ${err ? `<p class=\"err\" id=\"${id}-e\">${esc(err)}</p>` : ''}\n      ${hint ? `<p class=\"hint\" id=\"${id}-h\">${esc(hint)}</p>` : ''}\n      ${counter}\n      ${p.linkLabel ? `<a href=\"${esc(p.linkHref || '#')}\"${/^https?:\\/\\//.test(String(p.linkHref || '')) ? ' target=\"_blank\" rel=\"noopener\"' : ''}>${esc(p.linkLabel)}</a>` : ''}\n    </div>`;\n  }\n};"}},"ariaLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ariaLabel"}}}},"autoComplete":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"autoComplete"}}}},"counter":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"counter"}}}},"error":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"error"}}}},"hint":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"hint"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"inputMode":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"inputMode"}}}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"linkHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"linkHref"}}}},"linkLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"linkLabel"}}}},"mask":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"mask"}}}},"maxLength":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"maxLength"}}}},"multiline":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"multiline"}}}},"name":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"name"}}}},"onBlur":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onBlur"}}}},"onChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChange"}}}},"onInput":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onInput"}}}},"onLink":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onLink"}}}},"optional":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"optional"}}}},"options":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"options"}}}},"placeholder":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"placeholder"}}}},"required":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"required"}}}},"reveal":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"reveal"}}}},"rows":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"rows"}}}},"type":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"type"}}}},"value":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"value"}}}}}}}}}},{"_id":"6abbd2c37da9f132eb834397","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"LoginForm","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// LoginForm — Loja Lucas Fontana\n// O formulário de entrar, em duas etapas.\n// Etapa 1 (`step: \"login\"`): kicker \"Minha conta\", \"ENTRAR\" (44/36/28px), boas-vindas, e-mail e senha (com olho),\n// \"Esqueci minha senha\", o botão preto \"Entrar\" e a nota \"Você continua conectado por 5 dias neste aparelho.\"\n// Etapa 2 (`step: \"code\"`, verificação em duas etapas): e-mail e senha continuam preenchidos; entram o aviso com barra preta\n// (\"Se suas credenciais estiverem corretas, você recebeu um código de autenticação em seu e-mail.\" — não confirma se a conta\n// existe), o CodeField, o ResendCode e \"Entrar\"; a nota passa a ser \"Por segurança, todo login é confirmado com um código\n// enviado ao seu e-mail.\"\n// Fluxo: \"Entrar\" na etapa 1 confere o básico, emite `onSubmit` {email, password} e avança para o código\n// (`autoAdvance: false` desliga). Na etapa 2, \"Entrar\" confere os 6 números e emite `onVerify` {email, code}.\n// \"Usar outro e-mail\" volta para a etapa 1 (limpa senha e código) e emite `onChangeEmail`; \"Reenviar código\" emite `onResend`.\n// Erros do servidor: `emailError`, `passwordError`, `codeError` (\"Código incorreto. Confere o e-mail e tenta de novo.\").\n// `formError`: aviso único acima dos campos, sem marcar nenhum campo (na loja: \"E-mail ou senha incorretos.\"). Some quando\n// a pessoa volta a digitar.\n// `lockedMinutes`: login travado depois de 3 tentativas erradas — mostra \"Muitas tentativas seguidas.\" com o tempo de espera.\n// `email` já vem preenchido no campo (ex.: quando a pessoa chega pelo aviso de conta existente do cadastro).\n// Na loja, `autoAdvance: false` desliga a etapa do código (o 2FA fica só para o backoffice).\n// Não desenha campo, aviso, botão nem ícone: usa FormField, CodeField, ResendCode, Notice, Button e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst ic = (d2, ref, name, size, color, key) => ref\n  ? d2.render(ref, { name, size, iconColor: color || 'currentColor' }, { key, width: size, height: size, style: 'flex:none' })\n  : '';\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst EMAIL = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nconst store = (d2) => (d2.root ? (d2.root.__lf || (d2.root.__lf = { email: '', password: '', code: '' })) : { email: '', password: '', code: '' });\nconst codeLen = (p) => { const n = Number(p.codeLength); return n > 0 && n < 13 ? n : 6; };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.lf { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-500: #6b6e73; --grey-700: #45474b; --line: #e4e4e2;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: flex; flex-direction: column; gap: 18px; width: 100%; height: 100%; padding: 56px; margin: 0;\n  border: 1px solid var(--line); border-right: 0; background: var(--white); color: var(--ink); }\np, h1 { margin: 0; }\n.kicker { display: flex; align-items: center; gap: 12px; font-size: 12px; font-weight: 700; letter-spacing: .3em; line-height: 1.3; text-transform: uppercase; color: var(--red-500); }\n.kicker::before { content: ''; width: 22px; height: 3px; background: var(--red-500); flex: none; }\n.title { font-size: 44px; font-weight: 800; font-stretch: 115%; line-height: 1; letter-spacing: -.01em; text-transform: uppercase; color: var(--ink); }\n.text { margin: -4px 0 6px; font-size: 16px; line-height: 1.55; color: var(--grey-700); }\n.forgot { align-self: flex-end; font-size: 14px; font-weight: 600; color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }\n.forgot:hover { color: var(--red-500); }\n.forgot:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.submit { height: 52px; margin-top: 4px; }\n.note { display: flex; align-items: center; gap: 8px; font-size: 13px; line-height: 1.45; color: var(--grey-500); }\n\n.l-tablet { padding: 40px; border-right: 1px solid var(--line); border-bottom: 0; }\n.l-tablet .title { font-size: 36px; }\n\n.l-mobile { padding: 0; border: 0; gap: 16px; }\n.l-mobile .kicker { font-size: 11px; letter-spacing: .26em; }\n.l-mobile .title { font-size: 28px; font-stretch: 112%; letter-spacing: 0; }\n.l-mobile .text { font-size: 15px; }\n`,\n\n  mounted(d2) {\n    FONT();\n    d2.on('.forgot', 'click', (e, el) => emit(d2, 'onForgot', el.getAttribute('href')));\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const ffRef = refOf(d2.param('formField'));\n    const cfRef = refOf(d2.param('codeField'));\n    const rsRef = refOf(d2.param('resendCode'));\n    const ntRef = refOf(d2.param('notice'));\n    const btnRef = refOf(d2.param('button'));\n    const iconRef = refOf(d2.param('iconComponent'));\n    const s = store(d2);\n    const step = d2.state.step || (p.step === 'code' ? 'code' : 'login');\n    const code = step === 'code';\n    const n = codeLen(p);\n    if (!s.email && p.email) s.email = String(p.email);\n    const errE = code ? '' : (d2.state.errE || p.emailError || '');\n    const errP = code ? '' : (d2.state.errP || p.passwordError || '');\n    const errC = d2.state.errC || p.codeError || '';\n\n    const submit = () => {\n      const st = store(d2);\n      if ((d2.state.step || (p.step === 'code' ? 'code' : 'login')) === 'code') {\n        const c = String(st.code || '');\n        const eC = c.length < n ? `Digite os ${n} números do código.` : '';\n        d2.state.errC = eC;\n        if (!eC) emit(d2, 'onVerify', { email: String(st.email || '').trim(), code: c });\n        return;\n      }\n      const email = String(st.email || '').trim();\n      const password = String(st.password || '');\n      const eE = !email ? 'Informe seu e-mail.' : (!EMAIL.test(email) ? 'Confira o e-mail: falta o @ ou o domínio.' : '');\n      const eP = !password ? 'Informe sua senha.' : '';\n      d2.state.errE = eE; d2.state.errP = eP;\n      if (!eE && !eP) {\n        emit(d2, 'onSubmit', { email, password });\n        if (p.autoAdvance == null || p.autoAdvance === '' || truthy(p.autoAdvance)) { st.code = ''; d2.state.errC = ''; d2.state.step = 'code'; }\n      }\n    };\n    const backToLogin = () => {\n      const st = store(d2);\n      st.password = ''; st.code = '';\n      d2.state.errC = ''; d2.state.errE = ''; d2.state.errP = '';\n      d2.state.step = 'login';\n      emit(d2, 'onChangeEmail', st.email);\n    };\n\n    const field = (key, params, err, onInput) => ffRef ? d2.render(ffRef, Object.assign({ layout, iconComponent: iconRef, error: err }, params), {\n      key: key + '-' + step + (err ? '-err-' + err.length : ''), style: 'height:auto', onInput\n    }) : '';\n\n    const email = field('email', {\n      label: 'E-mail', type: 'email', name: 'email', autoComplete: 'email', inputMode: 'email',\n      placeholder: 'seuemail@exemplo.com', value: s.email\n    }, errE, (v) => { store(d2).email = v; if (!d2.state.feHidden && (p.formError || p.lockedMinutes)) d2.state.feHidden = true; });\n    const pass = field('senha', {\n      label: 'Senha', type: 'password', name: 'senha', autoComplete: 'current-password', placeholder: 'Sua senha',\n      value: s.password || (code ? (p.password || '••••••••••••') : '')\n    }, errP, (v) => { store(d2).password = v; if (!d2.state.feHidden && (p.formError || p.lockedMinutes)) d2.state.feHidden = true; });\n\n    // Aviso único do servidor (erro genérico ou bloqueio), acima dos campos\n    const lockMin = Number(p.lockedMinutes) > 0 ? Number(p.lockedMinutes) : 0;\n    const feText = lockMin\n      ? '**Muitas tentativas seguidas.** Por segurança, espera ' + lockMin + ' minutos para tentar de novo ou use **Esqueci minha senha**, logo abaixo.'\n      : (p.formError ? '**' + String(p.formError) + '**' : '');\n    const formAlert = !code && feText && !d2.state.feHidden && ntRef ? d2.render(ntRef, {\n      tone: 'accent', iconName: lockMin ? 'lock' : 'close', live: true, layout, iconComponent: iconRef, body: feText\n    }, { key: 'fe-' + (lockMin ? 'l' + lockMin : 'e') + '-' + feText.length, style: 'height:auto' }) : '';\n\n    const notice = code && ntRef ? d2.render(ntRef, {\n      tone: 'accent', iconName: 'mail', live: true, layout, iconComponent: iconRef,\n      body: p.noticeText || 'Se suas credenciais estiverem corretas, você recebeu um **código de autenticação** em seu e-mail.'\n    }, { key: 'notice', style: 'height:auto' }) : '';\n    const codeField = code && cfRef ? d2.render(cfRef, {\n      layout, length: n, validity: p.codeValidity || '', error: errC, autoFocus: true, value: s.code\n    }, {\n      key: 'code' + (errC ? '-err-' + errC.length : ''), style: 'height:auto',\n      onInput: (v) => { store(d2).code = v; }\n    }) : '';\n    const resend = code && rsRef ? d2.render(rsRef, {\n      layout, seconds: p.resendSeconds == null || p.resendSeconds === '' ? 59 : p.resendSeconds, showChange: true\n    }, {\n      key: 'resend', style: 'height:auto',\n      onResend: () => emit(d2, 'onResend', store(d2).email), onChangeEmail: backToLogin\n    }) : '';\n\n    const btn = btnRef ? `<div class=\"submit\">${d2.render(btnRef, {\n      label: p.submitLabel || 'Entrar', variant: 'primary', size: 'lg', fullWidth: 'always', layout\n    }, { key: 'submit', height: 52, onClick: submit })}</div>` : '';\n\n    const defNote = code ? 'Por segurança, todo login é confirmado com um código enviado ao seu e-mail.' : 'Você continua conectado por 5 dias neste aparelho.';\n    const note = p.note === '' ? '' : (p.note || defNote);\n\n    return `<div class=\"lf l-${layout} step-${step}\" role=\"form\" aria-label=\"${code ? 'Confirmar o login com o código' : 'Entrar na sua conta'}\">\n      <p class=\"kicker\">${esc(p.eyebrow || 'Minha conta')}</p>\n      <h1 class=\"title\">${esc(p.title || 'Entrar')}</h1>\n      <p class=\"text\">${esc(p.description || 'Que bom te ver de novo. Seu carrinho continua salvo quando você entrar.')}</p>\n      ${formAlert}\n      ${email}\n      ${pass}\n      <a class=\"forgot\" href=\"${esc(p.forgotHref || '/esqueci-minha-senha')}\">${esc(p.forgotLabel || 'Esqueci minha senha')}</a>\n      ${notice}\n      ${codeField}\n      ${resend}\n      ${btn}\n      ${note ? `<div class=\"note\">${ic(d2, iconRef, 'lock', 14, '#6b6e73', 'lock')}<span>${esc(note)}</span></div>` : ''}\n    </div>`;\n  }\n};"}},"autoAdvance":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"autoAdvance"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"codeError":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"codeError"}}}},"codeField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"codeField"}}}},"codeLength":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"codeLength"}}}},"codeValidity":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"codeValidity"}}}},"description":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"description"}}}},"email":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"email"}}}},"emailError":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"emailError"}}}},"eyebrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"eyebrow"}}}},"forgotHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"forgotHref"}}}},"forgotLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"forgotLabel"}}}},"formError":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formError"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"lockedMinutes":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"lockedMinutes"}}}},"note":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"note"}}}},"notice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notice"}}}},"noticeText":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"noticeText"}}}},"onChangeEmail":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChangeEmail"}}}},"onForgot":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onForgot"}}}},"onResend":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onResend"}}}},"onSubmit":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSubmit"}}}},"onVerify":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onVerify"}}}},"password":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"password"}}}},"passwordError":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"passwordError"}}}},"resendCode":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"resendCode"}}}},"resendSeconds":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"resendSeconds"}}}},"step":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"step"}}}},"submitLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"submitLabel"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}}}}}}}},{"_id":"6abbd2dc7da9f132eb8343de","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"PromoCard","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// PromoCard — Loja Lucas Fontana\n// Card preto que vende uma ação: xadrez no canto, kicker vermelho claro, título largo em caixa alta,\n// CheckList branca, botão vermelho opcional e régua vermelha de 6px embaixo (5px no mobile).\n// Login: \"Primeira vez aqui? / Crie sua conta em 1 minuto\" + \"Criar conta\".\n// `compact` é a versão estreita para a lateral do cadastro: sem régua, xadrez menor e uma nota com cadeado (`foot`).\n// Não desenha lista, botão nem ícone: usa CheckList, Button e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst ic = (d2, ref, name, size, color, key) => ref\n  ? d2.render(ref, { name, size, iconColor: color || 'currentColor' }, { key, width: size, height: size, style: 'flex:none' })\n  : '';\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst ITEMS = ['Acompanhe seus pedidos e o código de rastreio', 'Compre mais rápido com seus dados já preenchidos', 'Seja avisado quando o produto do vídeo voltar ao estoque'];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.pc { --red-500: #c8102e; --red-300: #ff4d62; --ink: #0b0b0c; --white: #ffffff; --grey-200: #c9cacd; --graphite-700: #34363a;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  position: relative; display: flex; flex-direction: column; justify-content: center; gap: 20px; width: 100%; height: 100%;\n  padding: 56px; background: var(--ink); color: var(--white); overflow: hidden; border-bottom: 6px solid var(--red-500); }\np, h2 { margin: 0; position: relative; }\n.checker { position: absolute; top: 0; right: 0; width: 150px; height: 90px; pointer-events: none;\n  background: repeating-conic-gradient(rgba(255,255,255,.08) 0 25%, transparent 0 50%) 0 0 / 30px 30px; }\n.kicker { display: flex; align-items: center; gap: 12px; font-size: 12px; font-weight: 700; letter-spacing: .3em; line-height: 1.3; text-transform: uppercase; color: var(--red-300); }\n.kicker::before { content: ''; width: 22px; height: 3px; background: var(--red-300); flex: none; }\n.title { font-size: 34px; font-weight: 800; font-stretch: 115%; line-height: 1; text-transform: uppercase; }\n.list, .cta { position: relative; }\n.cta { height: 52px; margin-top: 4px; align-self: flex-start; min-width: 200px; }\n.foot { position: relative; display: flex; gap: 12px; align-items: flex-start; padding-top: 20px; border-top: 1px solid var(--graphite-700);\n  font-size: 14px; line-height: 1.5; color: var(--grey-200); }\n.foot .fi { flex: none; margin-top: 2px; }\n.foot b { color: var(--white); }\n\n.compact { padding: 32px 28px; gap: 16px; border-bottom: 0; justify-content: flex-start; }\n.compact .checker { width: 72px; height: 48px; background-size: 24px 24px; }\n.compact .title { font-size: 24px; }\n\n.l-tablet { padding: 40px; }\n.l-tablet .title { font-size: 30px; }\n.l-mobile { padding: 32px 24px; border-bottom-width: 5px; }\n.l-mobile .kicker { font-size: 11px; letter-spacing: .26em; }\n.l-mobile .title { font-size: 24px; font-stretch: 112%; }\n.l-mobile .cta { align-self: stretch; }\n.l-mobile.compact { padding: 28px 22px; }\n`,\n\n  mounted(d2) { FONT(); },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const compact = truthy(p.compact);\n    const clRef = refOf(d2.param('checkList'));\n    const btnRef = refOf(d2.param('button'));\n    const iconRef = refOf(d2.param('iconComponent'));\n    const items = list(p.items).length ? list(p.items) : (compact ? [] : ITEMS);\n    const eyebrow = p.eyebrow == null ? (compact ? 'Por que criar conta' : 'Primeira vez aqui?') : p.eyebrow;\n    const title = p.title == null ? (compact ? '' : 'Crie sua conta em 1 minuto') : p.title;\n    const ctaLabel = p.ctaLabel == null ? (compact ? '' : 'Criar conta') : p.ctaLabel;\n    const ctaHref = p.ctaHref || '/cadastro';\n\n    const listHtml = items.length && clRef\n      ? `<div class=\"list\">${d2.render(clRef, { items, tone: 'dark', layout, iconComponent: iconRef }, { key: 'cl', style: 'height:auto' })}</div>`\n      : '';\n    const cta = ctaLabel && btnRef\n      ? `<div class=\"cta\">${d2.render(btnRef, { label: ctaLabel, variant: 'brand', size: 'lg', fullWidth: 'always', href: ctaHref, layout }, {\n          key: 'cta', height: 52, onClick: () => emit(d2, 'onCta', ctaHref) })}</div>`\n      : '';\n    const foot = p.foot\n      ? `<div class=\"foot\"><span class=\"fi\">${ic(d2, iconRef, 'lock', 18, '#ffffff', 'lock')}</span><div>${esc(p.foot).replace(/\\*\\*(.+?)\\*\\*/g, '<b>$1</b>')}</div></div>`\n      : '';\n\n    return `<aside class=\"pc l-${layout}${compact ? ' compact' : ''}\">\n      <span class=\"checker\" aria-hidden=\"true\"></span>\n      ${eyebrow ? `<p class=\"kicker\">${esc(eyebrow)}</p>` : ''}\n      ${title ? `<h2 class=\"title\">${esc(title)}</h2>` : ''}\n      ${listHtml}\n      ${cta}\n      ${foot}\n    </aside>`;\n  }\n};"}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"checkList":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkList"}}}},"compact":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"compact"}}}},"ctaHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ctaHref"}}}},"ctaLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ctaLabel"}}}},"eyebrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"eyebrow"}}}},"foot":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"foot"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"items":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"items"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onCta":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCta"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}}}}}}}},{"_id":"6abbd2ee0c5e4f969dbbc838","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"AuthLayout","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// AuthLayout — Loja Lucas Fontana\n// O corpo das páginas de conta: um cartão de até 1040px centralizado.\n// `mode: \"login\"` (padrão): a metade branca do formulário (LoginForm) e a metade escura do PromoCard lado a lado, na mesma altura.\n// Tablet: as metades empilham numa coluna de 560px. Mobile: o formulário perde a borda e o PromoCard vem 32px abaixo.\n// `mode: \"forgot\"`: cartão único de 560px centralizado com o ForgotPasswordForm (recuperar senha); sem borda no mobile.\n// Traz o respiro da página: 72/48/32px em cima e 120/88/64px embaixo.\n// Os textos chegam por `form` (parâmetros do LoginForm), `promo` (do PromoCard) e `forgot` (do ForgotPasswordForm).\n// Não desenha nada: usa LoginForm, PromoCard e ForgotPasswordForm por parâmetro (e repassa FormField, CodeField, ResendCode,\n// Notice, StepIndicator, Button, CheckList e Icon).\n// Para abrir o login direto na etapa do código: `form: { step: \"code\", email: \"…\" }`; a recuperação na etapa 2: `forgot: { step: \"sent\" }`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst PAD = { desktop: '72px 96px 120px', tablet: '48px 40px 88px', mobile: '32px 20px 64px' };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.auth { width: 100%; background: #ffffff; }\n.in { display: flex; justify-content: center; }\n.split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); width: 100%; max-width: 1040px; align-items: stretch; }\n.half { min-width: 0; }\n.single .split { grid-template-columns: minmax(0, 1fr); max-width: 560px; }\n.l-tablet .split { grid-template-columns: minmax(0, 1fr); max-width: 560px; }\n.l-mobile .split { grid-template-columns: minmax(0, 1fr); gap: 32px; }\n`,\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const r = (n) => refOf(d2.param(n));\n    const icon = r('iconComponent'); const btn = r('button');\n    const forgot = p.mode === 'forgot';\n    const style = layout === 'desktop' && !forgot ? 'height:100%' : 'height:auto';\n\n    let inner;\n    if (forgot) {\n      const f = r('forgotForm') ? d2.render(r('forgotForm'), Object.assign({}, obj(p.forgot), {\n        layout, stepIndicator: r('stepIndicator'), formField: r('formField'), notice: r('notice'), resendCode: r('resendCode'), button: btn, iconComponent: icon\n      }), {\n        key: 'forgot', style,\n        onSubmit: (v) => emit(d2, 'onSubmit', v), onResend: (v) => emit(d2, 'onResend', v),\n        onChangeEmail: (v) => emit(d2, 'onChangeEmail', v), onBack: (h) => emit(d2, 'onBack', h)\n      }) : '';\n      inner = `<div class=\"half\">${f}</div>`;\n    } else {\n      const form = r('loginForm') ? d2.render(r('loginForm'), Object.assign({}, obj(p.form), {\n        layout, formField: r('formField'), button: btn, iconComponent: icon, codeField: r('codeField'), resendCode: r('resendCode'), notice: r('notice')\n      }), {\n        key: 'form', style,\n        onSubmit: (v) => emit(d2, 'onSubmit', v), onForgot: (h) => emit(d2, 'onForgot', h),\n        onVerify: (v) => emit(d2, 'onVerify', v), onResend: (v) => emit(d2, 'onResend', v), onChangeEmail: (v) => emit(d2, 'onChangeEmail', v)\n      }) : '';\n      const promo = r('promoCard') ? d2.render(r('promoCard'), Object.assign({}, obj(p.promo), {\n        layout, checkList: r('checkList'), button: btn, iconComponent: icon\n      }), { key: 'promo', style, onCta: (h) => emit(d2, 'onCta', h) }) : '';\n      inner = `<div class=\"half\">${form}</div><div class=\"half\">${promo}</div>`;\n    }\n\n    return `<div class=\"auth l-${layout}${forgot ? ' single' : ''}\"><div class=\"in\" style=\"padding:${PAD[layout]}\">\n      <div class=\"split\">${inner}</div>\n    </div></div>`;\n  }\n};"}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"checkList":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkList"}}}},"codeField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"codeField"}}}},"forgot":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"forgot"}}}},"forgotForm":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"forgotForm"}}}},"form":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"form"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"loginForm":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"loginForm"}}}},"mode":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"mode"}}}},"notice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notice"}}}},"onBack":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onBack"}}}},"onChangeEmail":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChangeEmail"}}}},"onCta":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCta"}}}},"onForgot":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onForgot"}}}},"onResend":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onResend"}}}},"onSubmit":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSubmit"}}}},"onVerify":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onVerify"}}}},"promo":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"promo"}}}},"promoCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"promoCard"}}}},"resendCode":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"resendCode"}}}},"stepIndicator":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"stepIndicator"}}}}}}}}}},{"_id":"6abbec1eeebb96eb174b6b5d","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Notice","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Notice — Loja Lucas Fontana\n// Caixa de aviso discreta, fundo cinza-claro, com ícone: por que pedimos um dado ou o que não guardamos\n// (\"**Não guardamos dados de cartão** — o pagamento é feito com segurança pelo Mercado Pago.\").\n// `tone: \"accent\"` põe uma barra preta de 4px à esquerda, para a mensagem que responde ao que a pessoa acabou de fazer\n// (o aviso do código de autenticação no login, com o ícone `mail`).\n// O ícone chega por `iconName` (padrão `lock`) — `icon` é nome reservado do bloco base do Data2.\n// O texto chega por `body`; trechos entre **asteriscos duplos** saem em negrito. (O nome `text` também é reservado.)\n// `live: true` anuncia a mensagem para leitor de tela quando ela aparece.\n// Não desenha ícone: usa o Icon pelo parâmetro `iconComponent`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst rich = (t) => esc(t).replace(/\\*\\*(.+?)\\*\\*/g, '<b>$1</b>');\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.nt { --ink: #0b0b0c; --grey-50: #f5f5f3; --grey-700: #45474b;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: flex; gap: 14px; align-items: flex-start; width: 100%; padding: 16px 18px; background: var(--grey-50);\n  font-size: 14px; line-height: 1.5; color: var(--grey-700); }\n.nt b { color: var(--ink); }\n.ic { flex: none; margin-top: 2px; display: flex; }\n.accent { border-left: 4px solid var(--ink); padding: 16px 18px 16px 20px; align-items: center; }\n.accent .ic { margin-top: 0; }\n.success { background: #e3f4e8; border-left: 4px solid #1e8e4a; padding: 16px 18px 16px 20px; align-items: center; color: #14532d; font-weight: 600; }\n.success b { color: #0f3d22; }\n.error { background: #fbe9ec; border-left: 4px solid #c8102e; padding: 16px 18px 16px 20px; align-items: center; color: #7a0b1c; font-weight: 600; }\n.error b { color: #5c0815; }\n.success .ic, .error .ic { margin-top: 0; }\n`,\n  mounted() { FONT(); },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const accent = p.tone === 'accent';\n    const success = p.tone === 'success';\n    const err = p.tone === 'error';\n    const iconRef = refOf(d2.param('iconComponent'));\n    const name = (typeof p.iconName === 'string' && p.iconName) || (typeof p.icon === 'string' && p.icon) || (success ? 'check' : err ? 'close' : 'lock');\n    const size = accent || success || err ? 20 : 18;\n    const icon = iconRef ? d2.render(iconRef, { name, size, iconColor: success ? '#1e8e4a' : err ? '#c8102e' : '#0b0b0c' }, { key: 'ic-' + name, width: size, height: size }) : '';\n    const body = p.body == null ? '**Não guardamos dados de cartão** — o pagamento é feito com segurança pelo Mercado Pago.' : p.body;\n    return `<div class=\"nt l-${layout}${accent ? ' accent' : ''}${success ? ' success' : ''}${err ? ' error' : ''}\" role=\"${truthy(p.live) ? 'status' : 'note'}\">\n      <span class=\"ic\" aria-hidden=\"true\">${icon}</span><div>${rich(body)}</div>\n    </div>`;\n  }\n};"}},"body":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"body"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"iconName":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconName"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"live":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"live"}}}},"tone":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"tone"}}}}}}}}}},{"_id":"6abbec3396e03407355ee24f","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"CodeField","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// CodeField — Loja Lucas Fontana\n// O campo do código de autenticação (login em duas etapas): 56px de altura (52px no mobile), números centralizados,\n// grandes (24px, 800) e espaçados, \"000000\" de exemplo e a dica\n// \"Digite os 6 números enviados para o seu e-mail. O código vale por [X] minutos.\"\n// É UM campo só, não seis caixinhas: aceita colar, abre o teclado numérico (`inputmode=\"numeric\"`),\n// o celular sugere o código que chegou (`autocomplete=\"one-time-code\"`) e tudo que não é número é descartado.\n// `error` mostra o código errado ou vencido (\"Código incorreto. Confere o e-mail e tenta de novo.\").\n// Emite `onInput` a cada tecla e `onComplete` quando os 6 números estão preenchidos.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst len = (p) => { const n = Number(p.length); return n > 0 && n < 13 ? n : 6; };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.ff { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-400: #8e9095; --grey-500: #6b6e73; --line-strong: #d9d9d6;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: flex; flex-direction: column; gap: 8px; width: 100%; min-width: 0; }\nlabel { font-size: 14px; font-weight: 700; color: var(--ink); }\ninput { width: 100%; height: 56px; margin: 0; padding: 0 0 0 .5em; border: 1px solid var(--line-strong); border-radius: 2px; background: var(--white);\n  font: 800 24px/1 ${FF}; letter-spacing: .5em; text-align: center; font-variant-numeric: tabular-nums; color: var(--ink);\n  outline: none; -webkit-appearance: none; appearance: none; }\ninput::placeholder { color: var(--grey-400); letter-spacing: .5em; }\ninput:focus { border-color: var(--ink); box-shadow: 0 0 0 1px var(--ink); }\n.error input { border-color: var(--red-500); box-shadow: 0 0 0 1px var(--red-500); }\np { margin: 0; font-size: 13px; line-height: 1.4; }\n.hint { color: var(--grey-500); }\n.err { font-weight: 600; color: var(--red-500); }\n.l-mobile input { height: 52px; font-size: 22px; letter-spacing: .4em; }\n.l-mobile input::placeholder { letter-spacing: .4em; }\n`,\n\n  mounted(d2) {\n    FONT();\n    d2.on('input', 'input', (e, el) => {\n      const n = len(d2.params || {});\n      const clean = String(el.value || '').replace(/\\D/g, '').slice(0, n);\n      if (el.value !== clean) el.value = clean;\n      if (d2.root) d2.root.__lfVal = clean;\n      emit(d2, 'onInput', clean);\n      if (clean.length === n) emit(d2, 'onComplete', clean);\n    });\n    if (truthy((d2.params || {}).autoFocus)) setTimeout(() => { const el = d2.$('input'); if (el) el.focus({ preventScroll: true }); }, 60);\n  },\n\n  updated(d2) {\n    const el = d2.$('input');\n    if (el && d2.root && d2.root.__lfVal != null && el.value !== d2.root.__lfVal) el.value = d2.root.__lfVal;\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const n = len(p);\n    const err = p.error ? String(p.error) : '';\n    const hint = p.hint == null ? `Digite os ${n} números enviados para o seu e-mail. O código vale por ${p.validity || '[X]'} minutos.` : String(p.hint);\n    const describe = [err ? 'c-e' : '', hint ? 'c-h' : ''].filter(Boolean).join(' ');\n    const value = p.value ? String(p.value).replace(/\\D/g, '').slice(0, n) : '';\n    return `<div class=\"ff l-${layout}${err ? ' error' : ''}\">\n      <label for=\"c\">${esc(p.label || 'Código de autenticação')}</label>\n      <input id=\"c\" name=\"${esc(p.name || 'codigo')}\" type=\"text\" inputmode=\"numeric\" autocomplete=\"one-time-code\" pattern=\"[0-9]*\"\n        maxlength=\"${n}\" placeholder=\"${'0'.repeat(n)}\"${value ? ` value=\"${value}\"` : ''}${describe ? ` aria-describedby=\"${describe}\"` : ''}${err ? ' aria-invalid=\"true\"' : ''}>\n      ${err ? `<p class=\"err\" id=\"c-e\">${esc(err)}</p>` : ''}\n      ${hint ? `<p class=\"hint\" id=\"c-h\">${esc(hint)}</p>` : ''}\n    </div>`;\n  }\n};"}},"autoFocus":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"autoFocus"}}}},"error":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"error"}}}},"hint":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"hint"}}}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"length":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"length"}}}},"name":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"name"}}}},"onComplete":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onComplete"}}}},"onInput":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onInput"}}}},"validity":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"validity"}}}},"value":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"value"}}}}}}}}}},{"_id":"6abbec4338f2579fe8c01c50","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"ResendCode","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// ResendCode — Loja Lucas Fontana\n// A linha embaixo do campo do código: \"Não chegou? Reenviar em **0:59**\" contando de verdade.\n// Quando chega a zero, vira o link \"Reenviar código\"; ao reenviar, o contador recomeça.\n// \"Usar outro e-mail\" fica à direita (`showChange: false` esconde).\n// `align: \"center\"` empilha e centraliza as duas partes (tela \"Confira seu e-mail\" da recuperação de senha).\n// Mantenha o contador em 60 segundos ou mais (`seconds`, padrão 59 = 0:59).\n// Emite `onResend` e `onChangeEmail`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst start = (p) => (p.seconds == null || p.seconds === '' ? 59 : Math.max(0, Number(p.seconds) || 0));\nconst mmss = (s) => Math.floor(s / 60) + ':' + ('0' + (s % 60)).slice(-2);\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.rs { --red-500: #c8102e; --ink: #0b0b0c; --grey-700: #45474b;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 16px; min-height: 44px; width: 100%;\n  font-size: 15px; color: var(--grey-700); }\n.rs.center { flex-direction: column; justify-content: center; gap: 10px; min-height: 0; text-align: center; }\nb { color: var(--ink); font-weight: 800; font-variant-numeric: tabular-nums; }\nbutton { margin: 0; padding: 0; border: 0; background: none; font: 700 15px/1.2 ${FF}; color: var(--ink); text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }\nbutton:hover { color: var(--red-500); }\nbutton:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.l-mobile { font-size: 14px; }\n.l-mobile button { font-size: 14px; }\n`,\n\n  mounted(d2) {\n    FONT();\n    const tick = () => {\n      const p = d2.params || {};\n      if (truthy(p.paused)) return;\n      const left = d2.state.left == null ? start(p) : d2.state.left;\n      if (left > 0) d2.state.left = left - 1;\n    };\n    const t = setInterval(tick, 1000);\n    d2.onUnmount(() => clearInterval(t));\n    d2.on('.resend', 'click', () => { d2.state.left = start(d2.params || {}); emit(d2, 'onResend', true); });\n    d2.on('.change', 'click', () => emit(d2, 'onChangeEmail', true));\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const left = d2.state.left == null ? start(p) : d2.state.left;\n    const showChange = p.showChange == null || p.showChange === '' ? true : truthy(p.showChange);\n    const lead = esc(p.leadLabel || 'Não chegou?');\n    const status = left > 0\n      ? `<span aria-live=\"off\">${lead} Reenviar em <b>${mmss(left)}</b></span>`\n      : `<span>${lead} <button type=\"button\" class=\"resend\">${esc(p.resendLabel || 'Reenviar código')}</button></span>`;\n    return `<div class=\"rs l-${layout}${p.align === 'center' ? ' center' : ''}\">\n      ${status}\n      ${showChange ? `<button type=\"button\" class=\"change\">${esc(p.changeLabel || 'Usar outro e-mail')}</button>` : ''}\n    </div>`;\n  }\n};"}},"align":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"align"}}}},"changeLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"changeLabel"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"leadLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"leadLabel"}}}},"onChangeEmail":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChangeEmail"}}}},"onResend":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onResend"}}}},"paused":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"paused"}}}},"resendLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"resendLabel"}}}},"seconds":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"seconds"}}}},"showChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"showChange"}}}}}}}}}},{"_id":"6abc284feebb96eb174c178e","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"FormRow","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// FormRow — Loja Lucas Fontana\n// Dois campos lado a lado (16px entre eles) no desktop e no tablet; empilhados no mobile.\n// `keep: true` mantém as duas colunas no mobile para pares curtos (Número + Complemento), com 12px entre eles.\n// Os campos chegam por `fields`: uma lista de parâmetros do FormField. Um item vazio (null ou {}) deixa a vaga em branco,\n// para um campo curto ficar com meia largura (CEP, Estado, WhatsApp).\n// Repassa o que é digitado como { name, value } em `onInput` e `onChange`.\n// Não desenha campo: usa o FormField pelo parâmetro `formField` (e repassa o Icon).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst arr = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; align-items: start; width: 100%; }\n.l-mobile .row { grid-template-columns: minmax(0, 1fr); }\n.l-mobile .row.keep { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; }\n.l-mobile .row:not(.keep) .gap { display: none; }\n.cell { min-width: 0; }\n`,\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const ffRef = refOf(d2.param('formField'));\n    const iconRef = refOf(d2.param('iconComponent'));\n    const fields = arr(p.fields).slice(0, 2);\n    while (fields.length < 2) fields.push(null);\n\n    const cells = fields.map((f, i) => {\n      const fp = obj(f);\n      if (!Object.keys(fp).length || !ffRef) return '<div class=\"cell gap\" aria-hidden=\"true\"></div>';\n      const name = fp.name || 'campo' + (i + 1);\n      const field = d2.render(ffRef, Object.assign({}, fp, { layout, iconComponent: iconRef }), {\n        key: 'f-' + name,\n        onInput: (v) => emit(d2, 'onInput', { name, value: v }),\n        onChange: (v) => emit(d2, 'onChange', { name, value: v }),\n        onLink: (h) => emit(d2, 'onLink', { name, href: h })\n      });\n      return `<div class=\"cell\">${field}</div>`;\n    }).join('');\n\n    return `<div class=\"l-${layout}\"><div class=\"row${truthy(p.keep) ? ' keep' : ''}\">${cells}</div></div>`;\n  }\n};"}},"fields":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"fields"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"keep":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"keep"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChange"}}}},"onInput":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onInput"}}}},"onLink":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onLink"}}}}}}}}}},{"_id":"6abc284f869c478810fbd9eb","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"ChipGroup","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// ChipGroup — Loja Lucas Fontana\n// Uma escolha única em chips de 44px: borda line-strong, texto 14px em negrito; o escolhido fica preenchido de preto.\n// Feito sobre radio: as setas do teclado trocam a escolha e o grupo tem legenda para leitor de tela.\n// Usado em \"Sobre o que você quer falar?\" (Elogio · Sugestão de vídeo · Ideia de produto · Quero contratar o Lucas · Outro assunto).\n// `options: [{value, label}]`, `value` para a escolha inicial, `error` para a mensagem de validação.\n// Avisa a escolha em `onChange` (o valor da opção).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst arr = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\nfieldset { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --line-strong: #d9d9d6;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  border: 0; margin: 0; padding: 0; min-width: 0; display: flex; flex-direction: column; gap: 10px; }\nlegend { padding: 0; margin-bottom: 10px; font-size: 14px; font-weight: 700; color: var(--ink); }\n.list { display: flex; flex-wrap: wrap; gap: 8px; }\n.item { position: relative; display: inline-flex; }\n.item input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }\n.item span { display: inline-flex; align-items: center; height: 44px; padding: 0 14px; border: 1px solid var(--line-strong); border-radius: 0;\n  background: var(--white); font-size: 14px; font-weight: 700; color: var(--ink); cursor: pointer; white-space: nowrap;\n  transition: background-color .15s ease, border-color .15s ease, color .15s ease; }\n.item span:hover { border-color: var(--ink); }\n.item input:checked + span { background: var(--ink); border-color: var(--ink); color: var(--white); }\n.item input:focus-visible + span { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.l-mobile .item span { white-space: normal; min-height: 44px; height: auto; padding: 10px 14px; line-height: 1.25; }\n.error .item span { border-color: var(--red-500); }\n.error .item input:checked + span { border-color: var(--ink); }\n.err { margin: 0; font-size: 13px; line-height: 1.4; font-weight: 600; color: var(--red-500); }\n`,\n\n  mounted(d2) {\n    FONT();\n    d2.on('input[type=\"radio\"]', 'change', (e, el) => {\n      if (!el.checked) return;\n      d2.state.v = el.value;\n      emit(d2, 'onChange', el.value);\n    });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const opts = arr(p.options).map((o) => (o && typeof o === 'object' ? o : { value: String(o), label: String(o) }));\n    const name = p.name ? String(p.name) : 'assunto';\n    const cur = d2.state.v !== undefined ? d2.state.v : (p.value == null ? '' : String(p.value));\n    const err = p.error ? String(p.error) : '';\n    const items = opts.map((o) => `<label class=\"item\" data-key=\"${esc(o.value)}\">\n        <input type=\"radio\" name=\"${esc(name)}\" value=\"${esc(o.value)}\"${String(o.value) === cur ? ' checked' : ''}>\n        <span>${esc(o.label != null ? o.label : o.value)}</span></label>`).join('');\n    return `<fieldset class=\"l-${layout}${err ? ' error' : ''}\"${err ? ' aria-invalid=\"true\" aria-describedby=\"cg-e\"' : ''}>\n      ${p.label ? `<legend>${esc(p.label)}</legend>` : ''}\n      <div class=\"list\">${items}</div>\n      ${err ? `<p class=\"err\" id=\"cg-e\">${esc(err)}</p>` : ''}\n    </fieldset>`;\n  }\n};"}},"error":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"error"}}}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"name":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"name"}}}},"onChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChange"}}}},"options":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"options"}}}},"value":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"value"}}}}}}}}}},{"_id":"6abc284f3857467fb2c20c97","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Callout","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Callout — Loja Lucas Fontana\n// Bloco cinza-claro (grey-50) com régua vermelha de 4px à esquerda, para campos ou notas que aparecem por causa de uma\n// escolha anterior: \"**Parcerias, mídia e imprensa.** Conta um pouco da proposta…\" com empresa e tipo de proposta.\n// O texto chega por `body` (trechos entre **asteriscos duplos** saem em negrito).\n// Os campos chegam por `rows`: uma lista de linhas, cada linha com os parâmetros de um FormRow ({ fields: [...], keep }).\n// Repassa o que é digitado como { name, value } em `onInput` e `onChange`.\n// Não desenha campo: usa FormRow e FormField por parâmetro (e repassa o Icon).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst arr = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\nconst rich = (t) => esc(t).replace(/\\*\\*(.+?)\\*\\*/g, '<b>$1</b>');\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.co { --red-500: #c8102e; --ink: #0b0b0c; --grey-50: #f5f5f3; --grey-700: #45474b;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: flex; flex-direction: column; gap: 16px; width: 100%; padding: 20px 20px 22px; background: var(--grey-50); border-left: 4px solid var(--red-500); }\n.co > p { margin: 0; font-size: 14px; line-height: 1.5; color: var(--grey-700); }\n.co > p b { color: var(--ink); }\n.l-mobile.co { padding: 18px 16px 20px; }\n`,\n  mounted() { FONT(); },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const frRef = refOf(d2.param('formRow'));\n    const ffRef = refOf(d2.param('formField'));\n    const iconRef = refOf(d2.param('iconComponent'));\n    const rows = frRef ? arr(p.rows).map((r, i) => {\n      const rp = Array.isArray(r) ? { fields: r } : obj(r);\n      return d2.render(frRef, Object.assign({}, rp, { layout, formField: ffRef, iconComponent: iconRef }), {\n        key: 'row-' + i,\n        onInput: (v) => emit(d2, 'onInput', v),\n        onChange: (v) => emit(d2, 'onChange', v)\n      });\n    }).join('') : '';\n    return `<div class=\"co l-${layout}\">${p.body ? `<p>${rich(p.body)}</p>` : ''}${rows}</div>`;\n  }\n};"}},"body":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"body"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"formRow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formRow"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChange"}}}},"onInput":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onInput"}}}},"rows":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"rows"}}}}}}}}}},{"_id":"6abc2890351c900cbaf4da2e","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"HelpCard","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// HelpCard — Loja Lucas Fontana\n// \"Precisa de ajuda com este pedido?\": título, uma linha apontando para o SAC e um botão de largura cheia \"Falar com o SAC\".\n// Padrão: fundo branco com borda `line` e botão com contorno.\n// `tone: \"grey\"` é a versão grey-50 sem borda, título largo em caixa alta e botão preto — usada como\n// \"Dúvida sobre pedido?\" na página Fale com o Lucas.\n// `linkLabel`/`linkHref` põem um link sublinhado embaixo (\"Ver perguntas frequentes\").\n// O destino do SAC chega por `ctaHref` (WhatsApp ou e-mail do SAC — a definir). Sem link, o botão avisa em `onCta`.\n// Não desenha botão: usa o Button pelo parâmetro `button`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst rich = (t) => esc(t).replace(/\\*\\*(.+?)\\*\\*/g, '<b>$1</b>');\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.hc { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-50: #f5f5f3; --grey-700: #45474b; --line: #e4e4e2;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: flex; flex-direction: column; gap: 12px; width: 100%; padding: 24px; border: 1px solid var(--line); background: var(--white); }\nh2 { margin: 0; font-size: 17px; font-weight: 700; line-height: 1.3; color: var(--ink); }\np { margin: 0 0 4px; font-size: 15px; line-height: 1.5; color: var(--grey-700); }\n.grey { background: var(--grey-50); border-color: var(--grey-50); }\n.grey h2 { font-size: 18px; font-weight: 800; font-stretch: 112%; letter-spacing: .01em; text-transform: uppercase; }\n.link { align-self: center; margin-top: 6px; font-size: 14px; font-weight: 700; color: var(--ink); text-decoration: underline; text-underline-offset: 3px;\n  min-height: 44px; display: inline-flex; align-items: center; }\n.link:hover { color: var(--red-500); }\n.link:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.l-mobile.hc { padding: 20px; }\n`,\n\n  mounted(d2) {\n    FONT();\n    d2.on('.link', 'click', (e, el) => emit(d2, 'onLink', el.getAttribute('href')));\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const grey = p.tone === 'grey';\n    const btnRef = refOf(d2.param('button'));\n    const title = p.title || 'Precisa de ajuda com este pedido?';\n    const body = p.body || 'Fala com a gente pelo SAC informando o número do pedido.';\n    const cta = p.ctaLabel || 'Falar com o SAC';\n    const btn = btnRef ? d2.render(btnRef, {\n      label: cta, variant: grey ? 'primary' : 'outline', fullWidth: 'always', layout,\n      href: p.ctaHref || '', newTab: !!p.ctaHref\n    }, { key: 'cta', onClick: () => emit(d2, 'onCta', p.ctaHref || '') }) : '';\n    return `<section class=\"hc l-${layout}${grey ? ' grey' : ''}\">\n      <h2>${esc(title)}</h2>\n      <p>${rich(body)}</p>\n      ${btn}\n      ${p.linkLabel ? `<a class=\"link\" href=\"${esc(p.linkHref || '#')}\">${esc(p.linkLabel)}</a>` : ''}\n    </section>`;\n  }\n};\n"}},"body":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"body"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"ctaHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ctaHref"}}}},"ctaLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ctaLabel"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"linkHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"linkHref"}}}},"linkLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"linkLabel"}}}},"onCta":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCta"}}}},"onLink":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onLink"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}},"tone":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"tone"}}}}}}}}}},{"_id":"6abc289138ce7ce429d5b7c7","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"ChannelCard","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// ChannelCard — Loja Lucas Fontana\n// \"Siga o canal\": uma foto do Lucas sobre a régua vermelha de 6px (5px abaixo de 1200px), depois um painel preto com o\n// kicker em red-300, uma linha de texto e os botões quadrados de 44px do YouTube e do Instagram.\n// Sem `image`, mostra o espaço reservado da foto com o texto de `placeholder` (\"Foto do Lucas\").\n// `youtubeHref` / `instagramHref`: sem link, o botão aparece marcado como \"link a definir\" e não navega.\n// `showYoutube: false` / `showInstagram: false` escondem um deles.\n// Não desenha ícone: usa o Icon pelo parâmetro `iconComponent`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst ic = (d2, ref, name, size, color, key) => ref\n  ? d2.render(ref, { name, size, iconColor: color || 'currentColor' }, { key, width: size, height: size, style: 'flex:none' })\n  : '';\nconst IMG = '<svg viewBox=\"0 0 24 24\" width=\"28\" height=\"28\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"1\"/><circle cx=\"9\" cy=\"10\" r=\"2\"/><path d=\"m21 17-5-5-9 8\"/></svg>';\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.ch { --red-500: #c8102e; --red-300: #ff4d62; --ink: #0b0b0c; --white: #ffffff; --graphite-700: #34363a; --graphite-900: #1c1d1f;\n  --grey-200: #c9cacd; --grey-300: #a7a9ad;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: flex; flex-direction: column; width: 100%; background: var(--ink); color: var(--white); }\n.media { position: relative; height: 256px; background: var(--graphite-900); border-bottom: 6px solid var(--red-500);\n  display: flex; align-items: center; justify-content: center; overflow: hidden; }\n.l-tablet .media, .l-mobile .media { border-bottom-width: 5px; }\n.l-tablet .media { height: 220px; }\n.l-mobile .media { height: 240px; }\n.media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }\n.ph { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 0 16px; text-align: center;\n  font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--grey-300); }\n.ph small { font-size: 10px; font-weight: 600; letter-spacing: .1em; opacity: .8; }\n.body { display: flex; flex-direction: column; gap: 12px; padding: 22px 24px 26px; }\n.kicker { display: flex; align-items: center; gap: 12px; font-size: 12px; font-weight: 700; letter-spacing: .3em; line-height: 1.3;\n  text-transform: uppercase; color: var(--red-300); }\n.kicker::before { content: ''; width: 22px; height: 3px; background: var(--red-500); flex: none; }\n.body p { margin: 0; font-size: 15px; line-height: 1.55; color: var(--grey-200); }\n.social { display: flex; gap: 10px; margin-top: 4px; }\n.social a { width: 44px; height: 44px; border: 1px solid var(--graphite-700); color: var(--grey-200); display: flex; align-items: center; justify-content: center;\n  transition: border-color .15s ease, color .15s ease; }\n.social a:hover { border-color: var(--white); color: var(--white); }\n.social a:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.social a.pending { border-style: dashed; cursor: default; }\n.l-mobile .body { padding: 20px 20px 24px; }\n`,\n\n  mounted(d2) {\n    FONT();\n    d2.on('.social a', 'click', (e, el) => {\n      if (el.classList.contains('pending')) e.preventDefault();\n      emit(d2, 'onSocial', { network: el.getAttribute('data-net'), href: el.classList.contains('pending') ? '' : el.getAttribute('href') });\n    });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const iconRef = refOf(d2.param('iconComponent'));\n    const eyebrow = p.eyebrow || 'Siga o canal';\n    const body = p.body || 'Vídeo novo toda semana. Muita coisa que chega por aqui vira pauta.';\n    const media = p.image\n      ? `<img src=\"${esc(p.image)}\" alt=\"${esc(p.imageAlt || 'Lucas Fontana')}\">`\n      : `<span class=\"ph\">${IMG}${esc(p.placeholder || 'Foto do Lucas')}<small>Imagem a definir</small></span>`;\n    const link = (net, label, href, show) => {\n      if (show === false || show === 'false') return '';\n      const pending = !href;\n      return `<a data-net=\"${net}\" href=\"${esc(href || '#')}\"${pending ? ' class=\"pending\" aria-disabled=\"true\" title=\"Link a definir\"' : ' target=\"_blank\" rel=\"noopener\"'}\n        aria-label=\"${esc(label)}${pending ? ' (link a definir)' : ''}\">${ic(d2, iconRef, net, 20, 'currentColor', 'ic-' + net)}</a>`;\n    };\n    return `<section class=\"ch l-${layout}\">\n      <div class=\"media\">${media}</div>\n      <div class=\"body\">\n        <span class=\"kicker\">${esc(eyebrow)}</span>\n        <p>${esc(body)}</p>\n        <div class=\"social\">${link('youtube', 'YouTube do Lucas', p.youtubeHref, p.showYoutube)}${link('instagram', 'Instagram do Lucas', p.instagramHref, p.showInstagram)}</div>\n      </div>\n    </section>`;\n  }\n};\n"}},"body":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"body"}}}},"eyebrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"eyebrow"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"image":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"image"}}}},"imageAlt":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"imageAlt"}}}},"instagramHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"instagramHref"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onSocial":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSocial"}}}},"placeholder":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"placeholder"}}}},"showInstagram":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"showInstagram"}}}},"showYoutube":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"showYoutube"}}}},"youtubeHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"youtubeHref"}}}}}}}}}},{"_id":"6abc28c33857467fb2c20ea0","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"ContactLayout","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// ContactLayout — Loja Lucas Fontana\n// O corpo da página \"Fale com o Lucas\": o formulário (até 800px) ao lado de um aside fixo (sticky) de 380px com o\n// ChannelCard e o HelpCard cinza \"Dúvida sobre pedido?\". Tablet: aside de 300px. Mobile: uma coluna, o card do SAC sobe\n// para cima do formulário e o card do canal fecha a página.\n// Ordem do formulário: ChipGroup de assuntos → nome + e-mail → WhatsApp (opcional) → Callout quando o assunto pede\n// (padrão: \"Quero contratar o Lucas\", com empresa e tipo de proposta) → mensagem com contador de 1.000 caracteres\n// → linha de privacidade → botão preto \"Enviar mensagem →\".\n// Valida no envio: assunto, nome, e-mail válido e mensagem (e empresa, quando o Callout aparece); o erro some quando a\n// pessoa corrige o campo. Com tudo certo, avisa `onSubmit` com\n// { subject, subjectLabel, name, email, whatsapp, company, proposalType, message } e mostra o estado de sucesso:\n// um Notice de destaque (ícone check) + \"Mandar outro recado\", que limpa o formulário.\n// `status`: \"sent\" força o sucesso; \"error\" mostra o aviso de falha acima do botão; \"sending\" trava o botão.\n// `values` preenche o formulário ao abrir (útil para pré-visualizar, ex.: { subject: \"contratar\" }).\n// `channel` e `help` levam os parâmetros do ChannelCard e do HelpCard (foto, links e destino do SAC a definir).\n// Não desenha nada: usa ChipGroup, FormRow, FormField, Callout, Button, Notice, ChannelCard e HelpCard por parâmetro\n// (e repassa o Icon).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst arr = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\n\nconst SUBJECTS = [\n  { value: 'elogio', label: 'Elogio' },\n  { value: 'video', label: 'Sugestão de vídeo' },\n  { value: 'produto', label: 'Ideia de produto' },\n  { value: 'contratar', label: 'Quero contratar o Lucas' },\n  { value: 'outro', label: 'Outro assunto' }\n];\nconst PROPOSALS = [\n  { value: 'publi', label: 'Publi / conteúdo patrocinado' },\n  { value: 'evento', label: 'Evento' },\n  { value: 'entrevista', label: 'Entrevista / imprensa' },\n  { value: 'outro', label: 'Outro' }\n];\nconst MSG = {\n  subject: 'Escolhe um assunto pra gente saber pra quem mandar.',\n  name: 'Conta pra gente como te chamar.',\n  email: 'Confere o e-mail: falta o @ ou o domínio.',\n  emailEmpty: 'Deixa um e-mail pra gente conseguir responder.',\n  message: 'Escreve sua mensagem antes de enviar.',\n  company: 'Conta o nome da marca, agência ou veículo.'\n};\nconst EMAIL = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]{2,}$/;\nconst PAD = { desktop: '40px 96px 120px', tablet: '32px 40px 88px', mobile: '24px 20px 64px' };\nconst box = (d2) => { const r = d2.root || d2; if (!r.__lfv) r.__lfv = {}; return r; };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.ct { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-700: #45474b;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased; width: 100%; background: var(--white); }\n.in { display: grid; grid-template-columns: minmax(0, 1fr) 380px; gap: 56px; align-items: start; }\n.l-tablet .in { grid-template-columns: minmax(0, 1fr) 300px; gap: 32px; }\n.l-mobile .in { grid-template-columns: minmax(0, 1fr); gap: 32px; }\n.top { display: none; }\n.l-mobile .top { display: block; }\n.form { display: flex; flex-direction: column; gap: 20px; max-width: 800px; min-width: 0; }\n.legal { margin: 0; font-size: 14px; line-height: 1.5; color: var(--grey-700); }\n.legal a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }\n.legal a:hover { color: var(--red-500); }\n.legal a:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.submit { align-self: flex-start; margin-top: 4px; }\n.l-mobile .submit { align-self: stretch; }\n.aside { display: flex; flex-direction: column; gap: 16px; position: sticky; top: 24px; min-width: 0; }\n.l-mobile .aside { position: static; }\n.l-mobile .aside .help { display: none; }\n.done { display: flex; flex-direction: column; gap: 20px; align-items: flex-start; }\n.l-mobile .done { align-items: stretch; }\n`,\n\n  mounted(d2) { FONT(); },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const R = {\n      chip: refOf(d2.param('chipGroup')), row: refOf(d2.param('formRow')), ff: refOf(d2.param('formField')),\n      callout: refOf(d2.param('callout')), btn: refOf(d2.param('button')), notice: refOf(d2.param('notice')),\n      chan: refOf(d2.param('channelCard')), help: refOf(d2.param('helpCard')), icon: refOf(d2.param('iconComponent'))\n    };\n    const b = box(d2);\n    if (!b.__lfSeeded) { b.__lfSeeded = true; Object.assign(b.__lfv, obj(p.values)); }\n    const v = b.__lfv;\n    const gen = d2.state.gen || 0;\n    const errors = d2.state.errors || {};\n    const subjects = arr(p.subjects).length ? arr(p.subjects) : SUBJECTS;\n    const hireValue = p.hireValue || 'contratar';\n    const subject = d2.state.subject !== undefined ? d2.state.subject : (v.subject || '');\n    const hire = subject === hireValue;\n    const status = String(p.status || '');\n    const sent = status === 'sent' || !!d2.state.sent;\n    const sending = status === 'sending';\n    // No tablet a coluna do formulário tem ~356px: as linhas de dois campos empilham para não cortar os placeholders.\n    const rowLayout = layout === 'tablet' ? 'mobile' : layout;\n\n    const clearErr = (name) => {\n      if (!errors[name]) return;\n      const next = Object.assign({}, errors); delete next[name]; d2.state.errors = next;\n    };\n    const onField = (e) => { if (!e || !e.name) return; v[e.name] = e.value; clearErr(e.name); };\n\n    const validate = () => {\n      const e = {};\n      if (!v.subject) e.subject = MSG.subject;\n      if (!String(v.name || '').trim()) e.name = MSG.name;\n      const mail = String(v.email || '').trim();\n      if (!mail) e.email = MSG.emailEmpty; else if (!EMAIL.test(mail)) e.email = MSG.email;\n      if (!String(v.message || '').trim()) e.message = MSG.message;\n      if (v.subject === hireValue && !String(v.company || '').trim()) e.company = MSG.company;\n      return e;\n    };\n    const submit = () => {\n      if (sending) return;\n      const e = validate();\n      d2.state.errors = e;\n      if (Object.keys(e).length) return;\n      const s = subjects.find((o) => String(o.value) === String(v.subject)) || {};\n      const isHire = v.subject === hireValue;\n      emit(d2, 'onSubmit', {\n        subject: v.subject, subjectLabel: s.label || v.subject,\n        name: String(v.name || '').trim(), email: String(v.email || '').trim(), whatsapp: String(v.whatsapp || '').trim(),\n        company: isHire ? String(v.company || '').trim() : '', proposalType: isHire ? (v.proposalType || '') : '',\n        message: String(v.message || '').trim()\n      });\n      if (p.confirmOnSubmit !== false && p.confirmOnSubmit !== 'false') d2.state.sent = true;\n    };\n    const reset = () => {\n      b.__lfv = {}; d2.state.errors = {}; d2.state.subject = ''; d2.state.sent = false; d2.state.gen = gen + 1;\n      emit(d2, 'onReset');\n    };\n\n    const help = (key) => R.help ? d2.render(R.help, Object.assign({\n      tone: 'grey', title: 'Dúvida sobre pedido?',\n      body: 'Troca, entrega ou pagamento é com o SAC — lá a resposta é mais rápida.',\n      linkLabel: 'Ver perguntas frequentes', linkHref: '/faq'\n    }, obj(p.help), { layout, button: R.btn }), {\n      key, onCta: (h) => emit(d2, 'onSac', h), onLink: (h) => emit(d2, 'onFaq', h)\n    }) : '';\n    const channel = R.chan ? d2.render(R.chan, Object.assign({}, obj(p.channel), { layout, iconComponent: R.icon }), {\n      key: 'chan', onSocial: (s) => emit(d2, 'onSocial', s)\n    }) : '';\n\n    let form;\n    if (sent) {\n      const notice = R.notice ? d2.render(R.notice, {\n        tone: 'accent', iconName: 'check', live: true, layout, iconComponent: R.icon,\n        body: p.successBody || '**Recado entregue.** Sua mensagem já chegou no time do Lucas. Se precisar, a gente responde no e-mail que você deixou.'\n      }, { key: 'ok' }) : '';\n      const again = R.btn ? d2.render(R.btn, {\n        label: p.againLabel || 'Mandar outro recado', variant: 'outline', fullWidth: 'mobile', layout\n      }, { key: 'again', onClick: reset }) : '';\n      form = `<div class=\"done\">${notice}${again}</div>`;\n    } else {\n      // Filhos aninhados não recebem parâmetros novos depois de montados: a chave muda quando o erro ou o assunto mudam,\n      // e o campo remonta com o valor guardado (nada do que foi digitado se perde).\n      const sig = (names) => names.map((n) => (errors[n] ? '1' : '0')).join('');\n      const k = (n, names) => n + '-' + gen + (names ? '-' + sig(names) : '') + (hire ? '-h' : '');\n      const chips = R.chip ? d2.render(R.chip, {\n        label: p.subjectLabel || 'Sobre o que você quer falar?', options: subjects, value: subject, name: 'assunto',\n        error: errors.subject || '', layout\n      }, { key: k('subject', ['subject']), onChange: (val) => { v.subject = val; d2.state.subject = val; clearErr('subject'); } }) : '';\n      const row = (key, fields) => R.row ? d2.render(R.row, { fields, layout: rowLayout, formField: R.ff, iconComponent: R.icon }, { key: k(key, fields.filter(Boolean).map((f) => f.name)), onInput: onField }) : '';\n      const r1 = row('r1', [\n        { label: 'Seu nome', name: 'name', placeholder: 'Como você quer ser chamado', autoComplete: 'name', value: v.name || '', error: errors.name || '' },\n        { label: 'E-mail', name: 'email', type: 'email', placeholder: 'seuemail@exemplo.com', autoComplete: 'email', hint: 'Só para responder você, se precisar.', value: v.email || '', error: errors.email || '' }\n      ]);\n      const r2 = row('r2', [\n        { label: 'WhatsApp', name: 'whatsapp', type: 'tel', optional: true, placeholder: '(00) 00000-0000', autoComplete: 'tel', inputMode: 'tel', value: v.whatsapp || '' },\n        null\n      ]);\n      const callout = hire && R.callout ? d2.render(R.callout, {\n        layout: rowLayout, formRow: R.row, formField: R.ff, iconComponent: R.icon,\n        body: p.calloutBody || '**Parcerias, mídia e imprensa.** Conta um pouco da proposta que o time do Lucas retorna pelo e-mail informado.',\n        rows: [{ fields: [\n          { label: 'Empresa ou veículo', name: 'company', placeholder: 'Nome da marca, agência ou veículo', autoComplete: 'organization', value: v.company || '', error: errors.company || '' },\n          { label: 'Tipo de proposta', name: 'proposalType', placeholder: 'Escolha uma opção', options: arr(p.proposalTypes).length ? arr(p.proposalTypes) : PROPOSALS, value: v.proposalType || '' }\n        ] }]\n      }, { key: k('callout', ['company']), onInput: onField, onChange: onField }) : '';\n      const msg = R.ff ? d2.render(R.ff, {\n        label: 'Mensagem', name: 'message', multiline: true, maxLength: 1000, counter: true, layout, iconComponent: R.icon,\n        placeholder: hire ? 'Conta sobre a marca, a ideia, o formato (publi, evento, entrevista) e as datas.' : 'Conta pra gente o que você curtiu, o que quer ver no canal ou o que dá pra melhorar.',\n        value: v.message || '', error: errors.message || ''\n      }, { key: k('message', ['message']), onInput: (val) => onField({ name: 'message', value: val }) }) : '';\n      const fail = status === 'error' && R.notice ? d2.render(R.notice, {\n        tone: 'accent', iconName: 'message', live: true, layout, iconComponent: R.icon,\n        body: p.errorBody || '**Não deu pra enviar agora.** Confere sua conexão e tenta de novo em instantes — o que você escreveu continua aqui.'\n      }, { key: 'fail' }) : '';\n      const btn = R.btn ? d2.render(R.btn, {\n        label: sending ? 'Enviando…' : (p.submitLabel || 'Enviar mensagem'), variant: 'primary', size: 'lg', arrow: !sending,\n        isDisabled: sending, fullWidth: 'mobile', layout\n      }, { key: 'submit-' + (sending ? 's' : 'i'), onClick: submit }) : '';\n      form = `${chips}${r1}${r2}${callout}${msg}\n        <p class=\"legal\">Ao enviar, você concorda com a nossa <a href=\"${esc(p.privacyHref || '/politica-de-privacidade')}\">Política de Privacidade</a>.</p>\n        ${fail}<div class=\"submit\">${btn}</div>`;\n    }\n\n    return `<div class=\"ct l-${layout}\"><div class=\"in\" style=\"padding:${PAD[layout]}\">\n      <div class=\"top\">${layout === 'mobile' ? help('help-top') : ''}</div>\n      <div class=\"form\">${form}</div>\n      <aside class=\"aside\">${channel}<div class=\"help\">${layout === 'mobile' ? '' : help('help')}</div></aside>\n    </div></div>`;\n  }\n};"}},"againLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"againLabel"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"callout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"callout"}}}},"calloutBody":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"calloutBody"}}}},"channel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"channel"}}}},"channelCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"channelCard"}}}},"chipGroup":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"chipGroup"}}}},"confirmOnSubmit":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"confirmOnSubmit"}}}},"errorBody":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"errorBody"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"formRow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formRow"}}}},"help":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"help"}}}},"helpCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"helpCard"}}}},"hireValue":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"hireValue"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"notice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notice"}}}},"onFaq":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onFaq"}}}},"onReset":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onReset"}}}},"onSac":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSac"}}}},"onSocial":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSocial"}}}},"onSubmit":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSubmit"}}}},"privacyHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"privacyHref"}}}},"proposalTypes":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"proposalTypes"}}}},"status":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"status"}}}},"subjectLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"subjectLabel"}}}},"subjects":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"subjects"}}}},"submitLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"submitLabel"}}}},"successBody":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"successBody"}}}},"values":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"values"}}}}}}}}}},{"_id":"6abc3713eebb96eb174c3d34","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Checkbox","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Checkbox — Loja Lucas Fontana\n// Quadrado de 18px com borda de 1,5px grey-500; marcado fica vermelho com check branco.\n// A linha inteira (42px) é a área de toque. Rótulo de 15px.\n// No rótulo: `[texto](link)` vira link sublinhado; `((texto))` sai em cinza (ex.: \"(opcional — dá pra mudar quando quiser)\").\n// `top: true` alinha o quadrado com a primeira linha, para rótulos de várias linhas (consentimentos).\n// `count` mostra um número cinza à direita (filtros: \"Lavagem 12\"). `error` mostra a mensagem em vermelho embaixo.\n// Emite `onChange` com true/false. Não desenha o check: usa o Icon pelo parâmetro `iconComponent`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst rich = (t) => esc(t)\n  .replace(/\\[([^\\]]+)\\]\\(([^)\\s]+)\\)/g, '<a href=\"$2\">$1</a>')\n  .replace(/\\(\\((.+?)\\)\\)/g, '<span class=\"muted\">$1</span>')\n  .replace(/\\*\\*(.+?)\\*\\*/g, '<b>$1</b>');\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.cb { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-500: #6b6e73;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased; width: 100%; }\nlabel { display: flex; align-items: center; gap: 12px; min-height: 42px; padding: 4px 0; cursor: pointer; font-size: 15px; line-height: 1.45; color: var(--ink); }\n.top label { align-items: flex-start; }\ninput { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; pointer-events: none; }\n.box { flex: none; width: 18px; height: 18px; border: 1.5px solid var(--grey-500); border-radius: 2px; background: var(--white);\n  display: flex; align-items: center; justify-content: center; color: var(--white); }\n.top .box { margin-top: 2px; }\n.box > * { opacity: 0; }\ninput:checked + .box { background: var(--red-500); border-color: var(--red-500); }\ninput:checked + .box > * { opacity: 1; }\ninput:focus-visible + .box { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.dis label { cursor: not-allowed; opacity: .5; }\n.txt { flex: 1; min-width: 0; }\n.txt a { color: var(--ink); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }\n.txt a:hover { color: var(--red-500); }\n.muted { color: var(--grey-500); }\n.count { flex: none; font-size: 13px; color: var(--grey-500); }\n.err { margin: 0 0 0 30px; font-size: 13px; font-weight: 600; color: var(--red-500); }\n.error .box { border-color: var(--red-500); }\n`,\n\n  mounted(d2) {\n    FONT();\n    d2.on('input', 'change', (e, el) => { d2.state.checked = el.checked; emit(d2, 'onChange', el.checked); });\n    d2.on('.txt a', 'click', (e, el) => { e.stopPropagation(); emit(d2, 'onLink', el.getAttribute('href')); });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const iconRef = refOf(d2.param('iconComponent'));\n    const checked = d2.state.checked != null ? d2.state.checked : truthy(p.checked);\n    const dis = truthy(p.disabled);\n    const err = p.error ? String(p.error) : '';\n    const check = iconRef ? d2.render(iconRef, { name: 'check', size: 13, iconColor: '#ffffff' }, { key: 'ck', width: 13, height: 13 }) : '✓';\n    return `<div class=\"cb l-${layout}${truthy(p.top) ? ' top' : ''}${dis ? ' dis' : ''}${err ? ' error' : ''}\">\n      <label>\n        <input type=\"checkbox\"${p.name ? ` name=\"${esc(p.name)}\"` : ''}${p.value ? ` value=\"${esc(p.value)}\"` : ''}${checked ? ' checked' : ''}${dis ? ' disabled' : ''}${err ? ' aria-invalid=\"true\" aria-describedby=\"cb-e\"' : ''}>\n        <span class=\"box\" aria-hidden=\"true\">${check}</span>\n        <span class=\"txt\">${rich(p.label || '')}</span>\n        ${p.count != null && p.count !== '' ? `<span class=\"count\">${esc(p.count)}</span>` : ''}\n      </label>\n      ${err ? `<p class=\"err\" id=\"cb-e\">${esc(err)}</p>` : ''}\n    </div>`;\n  }\n};"}},"checked":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checked"}}}},"count":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"count"}}}},"disabled":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"disabled"}}}},"error":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"error"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"name":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"name"}}}},"onChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChange"}}}},"onLink":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onLink"}}}},"top":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"top"}}}},"value":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"value"}}}}}}}}}},{"_id":"6abc37270c5e4f969dbce7d2","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"Radio","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Radio — Loja Lucas Fontana\n// Grupo de opções redondas (escolha uma): círculo de 18px com borda de 1,5px grey-500; o escolhido fica com\n// borda vermelha e o miolo vermelho. Cada opção é uma linha de 42px clicável, rótulo de 15px.\n// No rótulo: `**texto**` sai em negrito e `((texto))` em cinza — \"**CPF** ((pessoa física))\".\n// As opções ficam lado a lado; no mobile empilham (`inline: false` empilha sempre).\n// Usado no TaxIdField (CPF/CNPJ) e, depois, na forma de pagamento. Emite `onChange` com o `value` escolhido.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst rich = (t) => esc(t).replace(/\\*\\*(.+?)\\*\\*/g, '<b>$1</b>').replace(/\\(\\((.+?)\\)\\)/g, '<span class=\"muted\">$1</span>');\nconst DEMO = [{ value: 'cpf', label: '**CPF** ((pessoa física))' }, { value: 'cnpj', label: '**CNPJ** ((pessoa jurídica))' }];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.rg { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-500: #6b6e73;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased; display: flex; flex-wrap: wrap; gap: 0 28px; width: 100%; margin: 0; padding: 0; border: 0; }\n.stack { flex-direction: column; }\nlabel { display: flex; align-items: center; gap: 10px; min-height: 42px; cursor: pointer; font-size: 15px; color: var(--ink); }\ninput { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; pointer-events: none; }\n.dot { flex: none; width: 18px; height: 18px; border: 1.5px solid var(--grey-500); border-radius: 50%; background: var(--white);\n  display: flex; align-items: center; justify-content: center; }\n.dot::after { content: ''; width: 8px; height: 8px; border-radius: 50%; background: var(--red-500); opacity: 0; }\ninput:checked + .dot { border-color: var(--red-500); }\ninput:checked + .dot::after { opacity: 1; }\ninput:focus-visible + .dot { outline: 2px solid var(--red-500); outline-offset: 2px; }\nb { font-weight: 700; }\n.muted { color: var(--grey-500); }\n`,\n\n  mounted(d2) {\n    FONT();\n    d2.on('input', 'change', (e, el) => { d2.state.value = el.value; emit(d2, 'onChange', el.value); });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const opts = list(p.options).length ? list(p.options) : DEMO;\n    const value = d2.state.value != null ? d2.state.value : (p.value != null && p.value !== '' ? String(p.value) : String((opts[0] || {}).value || ''));\n    const inline = p.inline == null || p.inline === '' ? true : truthy(p.inline);\n    const stack = !inline || layout === 'mobile';\n    const name = esc(p.name || 'opcao');\n    return `<div class=\"rg l-${layout}${stack ? ' stack' : ''}\" role=\"radiogroup\"${p.ariaLabel ? ` aria-label=\"${esc(p.ariaLabel)}\"` : ''}>\n      ${opts.map((o) => `<label><input type=\"radio\" name=\"${name}\" value=\"${esc(o.value)}\"${String(o.value) === value ? ' checked' : ''}><span class=\"dot\" aria-hidden=\"true\"></span><span>${rich(o.label || o.value)}</span></label>`).join('')}\n    </div>`;\n  }\n};"}},"ariaLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ariaLabel"}}}},"inline":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"inline"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"name":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"name"}}}},"onChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChange"}}}},"options":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"options"}}}},"value":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"value"}}}}}}}}}},{"_id":"6abc3741b953c62a975bfee6","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"TaxIdField","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// TaxIdField — Loja Lucas Fontana\n// Um campo só para CPF ou CNPJ: título \"CPF ou CNPJ\", duas opções (\"**CPF** (pessoa física)\" / \"**CNPJ** (pessoa jurídica)\")\n// que escolhem o documento, o campo com a máscara e o exemplo certos (000.000.000-00 / 00.000.000/0000-00)\n// e a dica \"Um campo só: a gente confere se o número é válido e usa na nota fiscal.\"\n// Confere os dígitos verificadores (não só a quantidade de números) assim que o último número é digitado e de novo\n// quando a pessoa sai do campo; mostra \"CPF inválido. Confere os números.\" (ou CNPJ) e apaga o erro quando fica certo.\n// Recusa também sequências repetidas (111.111.111-11, 00.000.000/0000-00).\n// `error` mostra um erro vindo de fora (tem prioridade). As opções ficam lado a lado; no mobile empilham.\n// Emite `onInput` com {kind, value, digits, valid} e `onKindChange` com \"cpf\" ou \"cnpj\".\n// Não desenha opção nem campo: usa Radio e FormField por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\n// Dígitos verificadores\nconst validCPF = (d) => {\n  if (!/^\\d{11}$/.test(d) || /^(\\d)\\1+$/.test(d)) return false;\n  const calc = (n) => { let s = 0; for (let i = 0; i < n; i++) s += Number(d[i]) * (n + 1 - i); const r = (s * 10) % 11; return r === 10 ? 0 : r; };\n  return calc(9) === Number(d[9]) && calc(10) === Number(d[10]);\n};\n// CNPJ alfanumérico (Receita/Serpro, a partir de jul/2026): 12 primeiras posições A–Z/0–9, 2 últimas numéricas;\n// cada caractere vale o código ASCII − 48 (0–9 continuam 0–9; A=17 … Z=42), mesmo módulo 11 e mesmos pesos.\n// Os CNPJs só numéricos de hoje continuam válidos pela mesma conta. Exemplo oficial: 12.ABC.345/01DE-35.\nconst validCNPJ = (raw) => {\n  const d = String(raw || '').toUpperCase();\n  if (!/^[A-Z0-9]{12}\\d{2}$/.test(d) || /^(.)\\1+$/.test(d)) return false;\n  const val = (c) => c.charCodeAt(0) - 48;\n  const calc = (n) => { const w = n === 12 ? [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2] : [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]; let s = 0; for (let i = 0; i < n; i++) s += val(d[i]) * w[i]; const r = s % 11; return r < 2 ? 0 : 11 - r; };\n  return calc(12) === Number(d[12]) && calc(13) === Number(d[13]);\n};\nconst norm = (kind, v) => (kind === 'cnpj' ? String(v || '').toUpperCase().replace(/[^A-Z0-9]/g, '') : String(v || '').replace(/\\D/g, ''));\nconst check = (kind, v) => { const d = norm(kind, v); return kind === 'cnpj' ? validCNPJ(d) : validCPF(d); };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\nfieldset { --ink: #0b0b0c; font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: flex; flex-direction: column; gap: 4px; width: 100%; margin: 0; padding: 0; border: 0; min-width: 0; }\nlegend { padding: 0; margin-bottom: 2px; font-size: 14px; font-weight: 700; color: var(--ink); }\n.field { margin-top: 4px; }\n.live { margin: 4px 0 0; font-size: 13px; font-weight: 600; line-height: 1.4; color: #c8102e; }\n`,\n\n  mounted(d2) { FONT(); },\n\n  updated(d2) {\n    // Devolve o cursor ao campo quando o erro aparece ou some enquanto a pessoa digita\n    if (!d2.root || !d2.root.__refocus) return;\n    d2.root.__refocus = false;\n    setTimeout(() => {\n      const host = d2.$('.field > *');\n      const inp = host && host.shadowRoot ? host.shadowRoot.querySelector('input') : null;\n      if (inp) { inp.focus({ preventScroll: true }); const n = inp.value.length; try { inp.setSelectionRange(n, n); } catch (e) { /* tipo sem seleção */ } }\n    }, 30);\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const radioRef = refOf(d2.param('radio'));\n    const ffRef = refOf(d2.param('formField'));\n    const iconRef = refOf(d2.param('iconComponent'));\n    const kind = d2.state.kind || (p.kind === 'cnpj' ? 'cnpj' : 'cpf');\n    const st = d2.root ? (d2.root.__lf || (d2.root.__lf = { value: p.value || '' })) : { value: p.value || '' };\n    const own = d2.state.err || '';\n    const err = p.error || own;\n    const live = !err && d2.state.live ? d2.state.live : '';\n    const label = kind === 'cnpj' ? 'CNPJ' : 'CPF';\n\n    const radio = radioRef ? d2.render(radioRef, {\n      name: p.name ? p.name + '-tipo' : 'documento-tipo', value: kind, layout, ariaLabel: 'Tipo de documento',\n      options: [{ value: 'cpf', label: '**CPF** ((pessoa física))' }, { value: 'cnpj', label: '**CNPJ** ((pessoa jurídica))' }]\n    }, {\n      key: 'radio', style: 'height:auto',\n      onChange: (v) => {\n        const k = v === 'cnpj' ? 'cnpj' : 'cpf';\n        const s = d2.root ? d2.root.__lf : null; if (s) s.value = '';\n        d2.state.err = ''; d2.state.kind = k;\n        emit(d2, 'onKindChange', k);\n        emit(d2, 'onInput', { kind: k, value: '', digits: '', valid: false });\n      }\n    }) : '';\n\n    const hint = p.hint == null\n      ? (kind === 'cnpj' ? 'Aceita o CNPJ novo, com letras. A gente confere se é válido e usa na nota fiscal.' : 'Um campo só: a gente confere se o número é válido e usa na nota fiscal.')\n      : String(p.hint);\n    const field = ffRef ? d2.render(ffRef, {\n      ariaLabel: label, name: p.name || 'documento', mask: kind, inputMode: kind === 'cnpj' ? 'text' : 'numeric',\n      placeholder: kind === 'cnpj' ? '00.000.000/0000-00' : '000.000.000-00',\n      hint, error: err, value: st.value, layout, iconComponent: iconRef\n    }, {\n      key: 'doc-' + kind + (err ? '-err-' + err.length : ''), style: 'height:auto',\n      onInput: (v) => {\n        const s = d2.root ? d2.root.__lf : null; if (s) s.value = v;\n        const d = norm(kind, v);\n        const full = d.length === (kind === 'cnpj' ? 14 : 11);\n        const ok = check(kind, v);\n        // Valida na hora: com todos os números digitados mostra o erro (ou apaga, se estiver certo);\n        // enquanto a pessoa ainda digita, apaga um erro antigo para não ficar vermelho à toa.\n        const e = full && !ok ? `${label} inválido. Confere os números.` : '';\n        // Durante a digitação o aviso aparece embaixo do campo sem redesenhá-lo (o cursor continua no lugar).\n        if (e !== (d2.state.live || '')) d2.state.live = e;\n        // Número completo e certo: apaga o erro de borda vermelha que tinha vindo ao sair do campo.\n        if (full && ok && d2.state.err) d2.state.err = '';\n        emit(d2, 'onInput', { kind, value: v, digits: d, valid: ok });\n      },\n      onBlur: (v) => {\n        const d = norm(kind, v);\n        const e = d && !check(kind, v) ? `${label} inválido. Confere os números.` : '';\n        if (e !== (d2.state.err || '')) { d2.state.err = e; d2.state.live = ''; }\n      }\n    }) : '';\n\n    return `<fieldset class=\"l-${layout}\"><legend>${esc(p.label || 'CPF ou CNPJ')}</legend>${radio}<div class=\"field\">${field}</div>${live ? `<p class=\"live\" role=\"alert\">${esc(live)}</p>` : ''}</fieldset>`;\n  }\n};"}},"error":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"error"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"hint":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"hint"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"kind":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"kind"}}}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"name":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"name"}}}},"onInput":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onInput"}}}},"onKindChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onKindChange"}}}},"radio":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"radio"}}}},"value":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"value"}}}}}}}}}},{"_id":"6abc375f3857467fb2c232e5","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"FormSection","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// FormSection — Loja Lucas Fontana\n// Um grupo de campos com título numerado: o número (`number`, ex.: \"01\") em vermelho itálico largo e o nome em caixa alta espaçada\n// (\"**01** SEUS DADOS\"). (`index` também funciona por dentro de outro componente, mas é nome reservado do bloco.) `plain: true` dá um título sem número, no estilo display (\"COMUNICAÇÕES\").\n// Os campos chegam por `rows`: cada linha tem 1 ou 2 campos. Duas na mesma linha ficam lado a lado (16px) no desktop\n// e no tablet e empilham no mobile — menos a linha com `keep: true` (Número + Complemento), que mantém as duas colunas.\n// Um campo `{kind: \"spacer\"}` guarda meia largura para um campo curto sozinho (CEP, Estado).\n// Cada campo: `{key, kind, ...}` — `kind` \"field\" (padrão, parâmetros do FormField), \"taxid\" (TaxIdField)\n// ou \"checkbox\" (parâmetros do Checkbox: `label`, `checked`). Checkboxes seguidos na mesma linha ficam empilhados, sem espaço\n// entre eles (cada um já tem 42px de área de toque), como em \"Comunicações\".\n// `note` põe uma linha cinza no fim (\"Avisos sobre os seus pedidos… continuam chegando normalmente.\").\n// `divider: true` põe uma linha fina acima da seção, com 24px de respiro.\n// Valores e erros chegam por `values` e `errors` (objetos por `key`); emite `onInput` e `onBlur` com {key, value}\n// (no checkbox, `value` é true/false).\n// 20px entre os campos. Não desenha campo: usa FormField, TaxIdField, Radio, Checkbox e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst DEMO = [\n  { fields: [{ key: 'documento', kind: 'taxid' }] },\n  { fields: [{ key: 'nome', label: 'Nome completo', placeholder: 'Como está no seu documento', autoComplete: 'name' }] },\n  { fields: [{ key: 'email', label: 'E-mail', type: 'email', placeholder: 'seuemail@exemplo.com', autoComplete: 'email' },\n    { key: 'whatsapp', label: 'WhatsApp', type: 'tel', mask: 'phone', placeholder: '(00) 00000-0000', hint: 'Para avisos do pedido.', autoComplete: 'tel' }] }\n];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.fs { --red-500: #c8102e; --ink: #0b0b0c; --grey-500: #6b6e73; --line: #e4e4e2;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased; display: flex; flex-direction: column; gap: 20px; width: 100%; margin: 0; }\n.fs.div { padding-top: 24px; border-top: 1px solid var(--line); }\nh2 { display: flex; align-items: baseline; gap: 12px; margin: 0; font-size: 13px; font-weight: 800; letter-spacing: .2em; line-height: 1.2; text-transform: uppercase; color: var(--ink); }\nh2 b { font-size: 22px; font-weight: 800; font-style: italic; font-stretch: 125%; letter-spacing: 0; color: var(--red-500); }\nh2.plain { display: block; font-size: 20px; font-weight: 800; font-stretch: 115%; letter-spacing: 0; line-height: 1.05; }\n.row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; align-items: start; }\n.row.one { grid-template-columns: minmax(0, 1fr); }\n.row.checks { display: flex; flex-direction: column; gap: 0; }\n.l-mobile .row { grid-template-columns: minmax(0, 1fr); gap: 20px; }\n.l-mobile .row.checks { gap: 0; }\n.l-mobile .row.keep { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; }\n.l-mobile .row .spacer { display: none; }\n.note { margin: -12px 0 0; font-size: 13px; line-height: 1.4; color: var(--grey-500); }\n`,\n\n  mounted() { FONT(); },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const ffRef = refOf(d2.param('formField'));\n    const txRef = refOf(d2.param('taxIdField'));\n    const rdRef = refOf(d2.param('radio'));\n    const cbRef = refOf(d2.param('checkbox'));\n    const iconRef = refOf(d2.param('iconComponent'));\n    const values = obj(p.values);\n    const errors = obj(p.errors);\n    const ver = p.version == null ? '' : String(p.version);\n    const rows = (list(p.rows).length ? list(p.rows) : DEMO).map((r) => (Array.isArray(r) ? { fields: r } : (r || { fields: [] })));\n\n    const renderField = (f) => {\n      if (!f || f.kind === 'spacer') return '<span class=\"spacer\" aria-hidden=\"true\"></span>';\n      const key = String(f.key || f.name || '');\n      const err = errors[key] ? String(errors[key]) : '';\n      const k = key + '-' + ver + (err ? '-e' + err.length : '');\n      if (f.kind === 'checkbox') {\n        const on = values[key] == null ? truthy(f.checked) : truthy(values[key]);\n        return cbRef ? d2.render(cbRef, {\n          label: f.label || '', name: f.name || key, checked: on, top: f.top !== false, error: err, layout, iconComponent: iconRef\n        }, { key: 'cb-' + k, style: 'height:auto', onChange: (val) => emit(d2, 'onInput', { key, value: !!val }), onLink: (h) => emit(d2, 'onLink', { key, href: h }) }) : '';\n      }\n      if (f.kind === 'taxid') {\n        const v = values[key] && typeof values[key] === 'object' ? values[key] : { kind: values[key + 'Kind'] || 'cpf', value: values[key] || '' };\n        return txRef ? d2.render(txRef, {\n          name: f.name || key, kind: v.kind || 'cpf', value: v.value || '', error: err, hint: f.hint, label: f.label,\n          layout, radio: rdRef, formField: ffRef, iconComponent: iconRef\n        }, { key: 'tx-' + k, style: 'height:auto', onInput: (val) => emit(d2, 'onInput', { key, value: val }) }) : '';\n      }\n      const params = Object.assign({}, f, { name: f.name || key, value: values[key] == null ? (f.value || '') : values[key], error: err, layout, iconComponent: iconRef });\n      delete params.key; delete params.kind;\n      return ffRef ? d2.render(ffRef, params, {\n        key: 'ff-' + k, style: 'height:auto',\n        onInput: (val) => emit(d2, 'onInput', { key, value: val }),\n        onBlur: (val) => emit(d2, 'onBlur', { key, value: val }),\n        onLink: (h) => emit(d2, 'onLink', { key, href: h })\n      }) : '';\n    };\n\n    const title = p.title\n      ? `<h2 class=\"${truthy(p.plain) ? 'plain' : ''}\">${!truthy(p.plain) && (p.number || p.index) ? `<b>${esc(p.number || p.index)}</b>` : ''}${esc(p.title)}</h2>`\n      : '';\n    const body = rows.map((r) => {\n      const fs = list(r.fields);\n      const checks = fs.length > 0 && fs.every((f) => f && f.kind === 'checkbox');\n      if (checks) return `<div class=\"row checks\">${fs.map(renderField).join('')}</div>`;\n      return `<div class=\"row${fs.length < 2 ? ' one' : ''}${truthy(r.keep) ? ' keep' : ''}\">${fs.map(renderField).join('')}</div>`;\n    }).join('');\n    const note = p.note ? `<p class=\"note\">${esc(p.note)}</p>` : '';\n    return `<section class=\"fs l-${layout}${truthy(p.divider) ? ' div' : ''}\">${title}${body}${note}</section>`;\n  }\n};\n"}},"checkbox":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkbox"}}}},"divider":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"divider"}}}},"errors":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"errors"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"index":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"index"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"note":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"note"}}}},"number":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"number"}}}},"onBlur":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onBlur"}}}},"onInput":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onInput"}}}},"onLink":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onLink"}}}},"plain":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"plain"}}}},"radio":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"radio"}}}},"rows":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"rows"}}}},"taxIdField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"taxIdField"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}},"values":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"values"}}}},"version":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"version"}}}}}}}}}},{"_id":"6abc37b3eebb96eb174c3eef","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"SignupForm","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// SignupForm — Loja Lucas Fontana\n// O formulário de criar conta, em duas etapas.\n// Etapa 1 (`step: \"form\"`): 01 SEUS DADOS (CPF/CNPJ, nome, e-mail, WhatsApp), 02 ENDEREÇO DE ENTREGA (CEP com\n// \"Não sei meu CEP\", rua, número + complemento, bairro + cidade, estado), 03 SENHA (senha + confirmação + regras),\n// os dois consentimentos (aceite obrigatório da Política de Privacidade e dos Termos; novidades por e-mail/WhatsApp\n// opcional, nenhum marcado ao abrir), o botão preto \"Criar minha conta\" e \"Já tem conta? Entrar\".\n// CEP: com os 8 números, consulta o ViaCEP e preenche rua, bairro, cidade e estado (a pessoa pode corrigir).\n// Antes de enviar confere: obrigatórios, nome e sobrenome, CPF/CNPJ válido, e-mail, WhatsApp (DDD + 9 números), CEP, UF,\n// a política de senha, a confirmação igual e o aceite. Mostra o erro em cada campo. Tudo certo: emite `onSubmit` com os\n// dados e passa para a etapa 2 (`verifyEmail: false` desliga — na V1 da loja fica desligado).\n// Etapa 2 (`step: \"code\"`, confirmação de e-mail): aviso com barra preta (\"Enviamos um código de confirmação para …\"),\n// CodeField, ResendCode (\"Corrigir o e-mail\" volta para a etapa 1 com tudo preenchido) e \"Confirmar e criar conta\".\n// Emite `onVerify` {email, code}, `onResend` e `onChangeEmail`. Erro do servidor: `codeError`, `emailError`, `documentError`.\n// `accountExists: true` (resposta do servidor quando o e-mail ou o documento já têm conta): aviso único no topo, sem dizer\n// qual dos dois — \"Os dados informados já possuem um cadastro vinculado.\" — com \"Entrar\" e \"Esqueci minha senha\", que\n// levam o e-mail já preenchido (`loginHref`, `forgotHref`). A página rola até o aviso; o formulário continua preenchido.\n// Senha segura: 8+ caracteres, letra maiúscula e minúscula, número, símbolo, diferente do e-mail e fora da lista de\n// senhas comuns. As regras aparecem embaixo da senha e ganham check enquanto a pessoa digita.\n// Não desenha campo, aviso, caixa nem botão: usa FormSection, FormField, TaxIdField, Radio, Checkbox, Notice,\n// CodeField, ResendCode, Button e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst EMAIL = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nconst UFS = 'AC AL AP AM BA CE DF ES GO MA MT MS MG PA PB PR PE PI RJ RN RS RO RR SC SP SE TO'.split(' ');\nconst onlyD = (v) => String(v || '').replace(/\\D/g, '');\nconst validCPF = (d) => {\n  if (!/^\\d{11}$/.test(d) || /^(\\d)\\1+$/.test(d)) return false;\n  const calc = (n) => { let s = 0; for (let i = 0; i < n; i++) s += Number(d[i]) * (n + 1 - i); const r = (s * 10) % 11; return r === 10 ? 0 : r; };\n  return calc(9) === Number(d[9]) && calc(10) === Number(d[10]);\n};\n// CNPJ alfanumérico (jul/2026): 12 primeiras posições A–Z/0–9, DV numérico; cada caractere vale ASCII − 48.\nconst validCNPJ = (raw) => {\n  const d = String(raw || '').toUpperCase();\n  if (!/^[A-Z0-9]{12}\\d{2}$/.test(d) || /^(.)\\1+$/.test(d)) return false;\n  const val = (c) => c.charCodeAt(0) - 48;\n  const calc = (n) => { const w = n === 12 ? [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2] : [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]; let s = 0; for (let i = 0; i < n; i++) s += val(d[i]) * w[i]; const r = s % 11; return r < 2 ? 0 : 11 - r; };\n  return calc(12) === Number(d[12]) && calc(13) === Number(d[13]);\n};\nconst docNorm = (kind, v) => (kind === 'cnpj' ? String(v || '').toUpperCase().replace(/[^A-Z0-9]/g, '') : onlyD(v));\n// Política de senha segura (a mesma conferência é refeita no servidor)\nconst COMMON = ['12345678', '123456789', '1234567890', 'senha123', 'senha@123', 'senha@1234', 'abcd@1234', 'abc@1234', 'qwerty123', 'qwerty@123',\n  'password1', 'password@1', 'admin@123', 'mudar@123', 'brasil@123', 'brasil2026', 'lucas@123', 'fontana@123', 'carro@123', 'teste@123'];\nconst pwRules = (pw, email) => {\n  const s = String(pw || ''); const low = s.toLowerCase();\n  const mail = String(email || '').trim().toLowerCase(); const user = mail.split('@')[0] || '';\n  return [\n    { id: 'len', label: '8 caracteres ou mais', ok: s.length >= 8 },\n    { id: 'case', label: 'Letra maiúscula e minúscula', ok: /[a-z]/.test(s) && /[A-Z]/.test(s) },\n    { id: 'num', label: 'Um número', ok: /\\d/.test(s) },\n    { id: 'sym', label: 'Um símbolo (ex.: ! @ # $ % & *)', ok: /[^A-Za-z0-9\\s]/.test(s) },\n    { id: 'mail', label: 'Diferente do seu e-mail', ok: !!s && (!mail || (low !== mail && !(user.length >= 3 && low.indexOf(user) >= 0))) },\n    { id: 'common', label: 'Não pode ser uma senha comum', ok: !!s && COMMON.indexOf(low) < 0 && !/^(.)\\1+$/.test(s) }\n  ];\n};\nconst store = (d2) => {\n  const blank = { v: { documento: { kind: 'cpf', value: '' } }, privacy: false, news: false, code: '', lastCep: '' };\n  return d2.root ? (d2.root.__lf || (d2.root.__lf = blank)) : blank;\n};\nconst SECTIONS = (cepHint) => [\n  { id: 's1', index: '01', title: 'Seus dados', rows: [\n    { fields: [{ key: 'documento', kind: 'taxid' }] },\n    { fields: [{ key: 'nome', label: 'Nome completo', placeholder: 'Como está no seu documento', autoComplete: 'name' }] },\n    { fields: [{ key: 'email', label: 'E-mail', type: 'email', placeholder: 'seuemail@exemplo.com', autoComplete: 'email' },\n      { key: 'whatsapp', label: 'WhatsApp', type: 'tel', mask: 'phone', placeholder: '(00) 00000-0000', hint: 'Para avisos do pedido.', autoComplete: 'tel' }] }] },\n  { id: 's2', index: '02', title: 'Endereço de entrega', rows: [\n    { fields: [{ key: 'cep', label: 'CEP', mask: 'cep', placeholder: '00000-000', autoComplete: 'postal-code', hint: cepHint,\n      linkLabel: 'Não sei meu CEP', linkHref: 'https://buscacepinter.correios.com.br/app/endereco/index.php' }, { kind: 'spacer' }] },\n    { fields: [{ key: 'rua', label: 'Rua / avenida', autoComplete: 'address-line1' }] },\n    { keep: true, fields: [{ key: 'numero', label: 'Número', placeholder: 'Ou S/N' }, { key: 'complemento', label: 'Complemento', optional: true, placeholder: 'Apto, bloco, referência', autoComplete: 'address-line2' }] },\n    { fields: [{ key: 'bairro', label: 'Bairro' }, { key: 'cidade', label: 'Cidade', autoComplete: 'address-level2' }] },\n    { fields: [{ key: 'uf', label: 'Estado', mask: 'uf', placeholder: 'UF', maxLength: 2, autoComplete: 'address-level1' }, { kind: 'spacer' }] }] },\n  { id: 's3', index: '03', title: 'Senha', rows: [\n    { fields: [{ key: 'senha', label: 'Senha', type: 'password', placeholder: 'Crie uma senha', autoComplete: 'new-password' },\n      { key: 'confirma', label: 'Confirmar senha', type: 'password', placeholder: 'Repita a senha', autoComplete: 'new-password' }] }] }\n];\nconst SEC_OF = { documento: 's1', nome: 's1', email: 's1', whatsapp: 's1', cep: 's2', rua: 's2', numero: 's2', complemento: 's2', bairro: 's2', cidade: 's2', uf: 's2', senha: 's3', confirma: 's3' };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.sf { --red-500: #c8102e; --ink: #0b0b0c; --grey-500: #6b6e73; --grey-700: #45474b; --line: #e4e4e2;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased; display: flex; flex-direction: column; gap: 32px; width: 100%; color: var(--ink); }\n.consents { display: flex; flex-direction: column; gap: 4px; padding-top: 24px; border-top: 1px solid var(--line); }\n.foot { display: flex; align-items: center; gap: 24px; flex-wrap: wrap; }\n.submit { width: 280px; height: 52px; }\n.have { margin: 0; font-size: 15px; color: var(--grey-700); }\n.have a { color: var(--ink); font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }\n.have a:hover { color: var(--red-500); }\n.have a:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.summary { margin: 0; font-size: 14px; font-weight: 600; color: var(--red-500); }\n.code { display: flex; flex-direction: column; gap: 18px; max-width: 520px; }\n.full { width: 100%; height: 52px; }\n.exists { display: flex; flex-direction: column; gap: 16px; }\n.exists .acts { display: flex; flex-wrap: wrap; gap: 12px; }\n.exists .acts > * { flex: 0 0 auto; width: auto !important; }\n.rules { list-style: none; margin: -12px 0 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 16px; }\n.rules li { display: flex; align-items: center; gap: 8px; font-size: 13px; line-height: 1.35; color: var(--grey-500); }\n.rules .dot { width: 16px; height: 16px; flex: none; border: 1.5px solid #d9d9d6; display: flex; align-items: center; justify-content: center; }\n.rules .ok { color: var(--ink); font-weight: 600; }\n.rules .ok .dot { background: var(--ink); border-color: var(--ink); }\n.rules.err li:not(.ok) { color: var(--red-500); }\n.rules.err li:not(.ok) .dot { border-color: var(--red-500); }\n.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }\n.l-mobile .rules { grid-template-columns: minmax(0, 1fr); }\n.l-mobile .exists .acts { flex-direction: column; }\n.l-mobile .exists .acts > * { width: 100% !important; }\n.l-mobile { gap: 28px; }\n.l-mobile .foot { flex-direction: column; align-items: stretch; gap: 16px; }\n.l-mobile .submit { width: 100%; }\n.l-mobile .have { text-align: center; }\n`,\n\n  mounted(d2) {\n    FONT();\n    d2.on('.have a', 'click', (e, el) => emit(d2, 'onLogin', el.getAttribute('href')));\n  },\n\n  updated(d2) {\n    // Conta existente: rola até o aviso uma vez\n    const p = d2.params || {};\n    if (!truthy(p.accountExists) && !d2.state.exists) { if (d2.root) d2.root.__lfExists = false; return; }\n    if (d2.root && d2.root.__lfExists) return;\n    if (d2.root) d2.root.__lfExists = true;\n    setTimeout(() => { const el = d2.$('.exists'); if (el && el.scrollIntoView) el.scrollIntoView({ behavior: 'smooth', block: 'center' }); }, 80);\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const R = {\n      fs: refOf(d2.param('formSection')), ff: refOf(d2.param('formField')), tx: refOf(d2.param('taxIdField')),\n      rd: refOf(d2.param('radio')), cb: refOf(d2.param('checkbox')), nt: refOf(d2.param('notice')),\n      cf: refOf(d2.param('codeField')), rs: refOf(d2.param('resendCode')), btn: refOf(d2.param('button')), icon: refOf(d2.param('iconComponent'))\n    };\n    const s = store(d2);\n    const step = d2.state.step || (p.step === 'code' ? 'code' : 'form');\n    const errs = Object.assign({}, d2.state.errs || {});\n    if (p.emailError && !errs.email) errs.email = p.emailError;\n    if (p.documentError && !errs.documento) errs.documento = p.documentError;\n    const ver = d2.state.ver || { s1: 0, s2: 0, s3: 0, c: 0 };\n    const bump = (ids) => { const v = Object.assign({ s1: 0, s2: 0, s3: 0, c: 0 }, d2.state.ver || {}); ids.forEach((i) => { v[i] = (v[i] || 0) + 1; }); d2.state.ver = v; };\n\n    // ——— CEP → ViaCEP\n    const lookupCep = (digits) => {\n      const st = store(d2);\n      if (digits.length !== 8 || digits === st.lastCep) return;\n      st.lastCep = digits;\n      d2.state.cepStatus = 'loading';\n      fetch('https://viacep.com.br/ws/' + digits + '/json/').then((r) => r.json()).then((j) => {\n        const e = Object.assign({}, d2.state.errs || {});\n        if (!j || j.erro) {\n          e.cep = 'CEP não encontrado. Confere os números ou preencha o endereço.';\n        } else {\n          delete e.cep;\n          const v = store(d2).v;\n          v.rua = j.logradouro || v.rua || ''; v.bairro = j.bairro || v.bairro || '';\n          v.cidade = j.localidade || v.cidade || ''; v.uf = j.uf || v.uf || '';\n          ['rua', 'bairro', 'cidade', 'uf'].forEach((k) => { if (v[k]) delete e[k]; });\n        }\n        d2.state.errs = e; d2.state.cepStatus = j && !j.erro ? 'ok' : 'fail'; bump(['s2']);\n        emit(d2, 'onCep', j && !j.erro ? j : null);\n      }).catch(() => { d2.state.cepStatus = 'fail'; });\n    };\n\n    // ——— Conferência\n    const validate = () => {\n      const v = store(d2).v; const e = {};\n      const doc = v.documento || {}; const dd = docNorm(doc.kind, doc.value);\n      if (!dd) e.documento = 'Informe seu ' + (doc.kind === 'cnpj' ? 'CNPJ' : 'CPF') + '.';\n      else if (!(doc.kind === 'cnpj' ? validCNPJ(dd) : validCPF(dd))) e.documento = (doc.kind === 'cnpj' ? 'CNPJ' : 'CPF') + ' inválido. Confere os números.';\n      const nome = String(v.nome || '').trim();\n      if (!nome) e.nome = 'Informe seu nome completo.'; else if (nome.split(/\\s+/).length < 2) e.nome = 'Coloque nome e sobrenome.';\n      const email = String(v.email || '').trim();\n      if (!email) e.email = 'Informe seu e-mail.'; else if (!EMAIL.test(email)) e.email = 'Confira o e-mail: falta o @ ou o domínio.';\n      const w = onlyD(v.whatsapp); if (!w) e.whatsapp = 'Informe seu WhatsApp.'; else if (w.length !== 11 || w[2] !== '9') e.whatsapp = 'Confira o WhatsApp: DDD + 9 números (celular).';\n      const c = onlyD(v.cep); if (!c) e.cep = 'Informe o CEP.'; else if (c.length !== 8) e.cep = 'O CEP tem 8 números.';\n      else if ((d2.state.errs || {}).cep) e.cep = d2.state.errs.cep;\n      if (!String(v.rua || '').trim()) e.rua = 'Informe a rua ou avenida.';\n      if (!String(v.numero || '').trim()) e.numero = 'Informe o número (ou \"s/n\").';\n      if (!String(v.bairro || '').trim()) e.bairro = 'Informe o bairro.';\n      if (!String(v.cidade || '').trim()) e.cidade = 'Informe a cidade.';\n      const uf = String(v.uf || '').toUpperCase(); if (!uf) e.uf = 'Informe o estado.'; else if (UFS.indexOf(uf) < 0) e.uf = 'Use a sigla do estado (ex.: SP).';\n      const pw = String(v.senha || '');\n      if (!pw) e.senha = 'Crie uma senha.'; else if (pwRules(pw, v.email).some((r) => !r.ok)) e.senha = 'A senha ainda não cumpre todas as regras abaixo.';\n      if (!v.confirma) e.confirma = 'Repita a senha.'; else if (v.confirma !== pw) e.confirma = 'As senhas não são iguais.';\n      if (!store(d2).privacy) e.privacy = 'Para criar a conta, aceite a Política de Privacidade e os Termos de Uso.';\n      return e;\n    };\n    const submit = () => {\n      const e = validate();\n      const prev = d2.state.errs || {};\n      const changed = new Set();\n      Object.keys(Object.assign({}, prev, e)).forEach((k) => { if (prev[k] !== e[k] && SEC_OF[k]) changed.add(SEC_OF[k]); });\n      if (prev.privacy !== e.privacy) changed.add('c');\n      d2.state.errs = e; bump(Array.from(changed));\n      if (Object.keys(e).length) {\n        setTimeout(() => { const el = d2.$('.sf'); if (el && el.scrollIntoView) el.scrollIntoView({ behavior: 'smooth', block: 'start' }); }, 50);\n        return;\n      }\n      const st = store(d2); const v = st.v;\n      const data = {\n        documentKind: (v.documento || {}).kind || 'cpf', document: docNorm((v.documento || {}).kind, (v.documento || {}).value), name: String(v.nome || '').trim(),\n        email: String(v.email || '').trim(), whatsapp: onlyD(v.whatsapp),\n        address: { cep: onlyD(v.cep), street: v.rua || '', number: v.numero || '', complement: v.complemento || '', district: v.bairro || '', city: v.cidade || '', state: String(v.uf || '').toUpperCase() },\n        password: v.senha, acceptedPrivacy: true, marketingOptIn: !!st.news\n      };\n      emit(d2, 'onSubmit', data);\n      // Loja (sem código): cria a conta no serviço `cadastrarCliente`, entra pelo `lojaAuth` e volta para a origem\n      if (p.verifyEmail === false || p.verifyEmail === 'false') { sendSignup(data); return; }\n      if (p.verifyEmail == null || p.verifyEmail === '' || truthy(p.verifyEmail)) { st.code = ''; d2.state.errC = ''; d2.state.step = 'code'; }\n    };\n\n    // ——— Envio para o servidor (loja)\n    const dest = () => {\n      let v = '';\n      try { v = new URLSearchParams(window.location.search).get('voltar') || ''; } catch (e) { v = ''; }\n      return /^\\/(?!\\/)/.test(v) ? v : (p.redirectTo || '/');\n    };\n    const sendSignup = async (data) => {\n      if (d2.state.sending) return;\n      d2.state.sending = true; d2.state.srvErr = ''; d2.state.exists = false;\n      let r = null;\n      try {\n        const res = await d2.rush('cadastrarCliente').invoke(data);\n        r = res && res.data !== undefined ? res.data : res;\n      } catch (e) { r = null; }\n      if (r && r.ok) {\n        try {\n          await d2.auth('lojaAuth').login({ credentials: { email: r.email || data.email, senha: data.password } });\n          window.location.assign(dest());\n        } catch (e) {\n          window.location.assign((p.loginHref || '/entrar') + '?email=' + encodeURIComponent(r.email || data.email));\n        }\n        return;\n      }\n      d2.state.sending = false;\n      if (r && r.motivo === 'conta_existente') { d2.state.exists = true; return; }\n      if (r && r.erros && typeof r.erros === 'object') {\n        const e = Object.assign({}, r.erros);\n        d2.state.errs = e; bump(['s1', 's2', 's3', 'c']);\n        setTimeout(() => { const el = d2.$('.sf'); if (el && el.scrollIntoView) el.scrollIntoView({ behavior: 'smooth', block: 'start' }); }, 50);\n        return;\n      }\n      d2.state.srvErr = 'Não deu pra criar a conta agora. Confere sua conexão e tenta de novo — o que você preencheu continua aqui.';\n    };\n\n    const onField = (ev) => {\n      if (!ev || !ev.key) return;\n      const st = store(d2);\n      st.v[ev.key] = ev.value;\n      if (ev.key === 'cep') lookupCep(onlyD(ev.value));\n      if (ev.key === 'senha' || ev.key === 'email') d2.state['pw_' + ev.key] = String(ev.value || '');\n    };\n\n    // ——— Etapa 2: código\n    if (step === 'code') {\n      const email = String(store(d2).v.email || p.email || '[seuemail@exemplo.com]');\n      const errC = d2.state.errC || p.codeError || '';\n      const verify = () => {\n        const c = String(store(d2).code || '');\n        const eC = c.length < 6 ? 'Digite os 6 números do código.' : '';\n        d2.state.errC = eC;\n        if (!eC) emit(d2, 'onVerify', { email, code: c });\n      };\n      const back = () => { store(d2).code = ''; d2.state.errC = ''; d2.state.step = 'form'; bump(['s1', 's2', 's3', 'c']); emit(d2, 'onChangeEmail', email); };\n      const notice = R.nt ? d2.render(R.nt, {\n        tone: 'accent', iconName: 'mail', live: true, layout, iconComponent: R.icon,\n        body: 'Enviamos um **código de confirmação** para **' + email + '**. Digite abaixo para ativar sua conta.'\n      }, { key: 'notice', style: 'height:auto' }) : '';\n      const code = R.cf ? d2.render(R.cf, {\n        layout, length: 6, validity: p.codeValidity || '', error: errC, autoFocus: true, value: store(d2).code, label: 'Código de confirmação'\n      }, { key: 'code' + (errC ? '-e' + errC.length : ''), style: 'height:auto', onInput: (v) => { store(d2).code = v; } }) : '';\n      const resend = R.rs ? d2.render(R.rs, { layout, seconds: p.resendSeconds == null || p.resendSeconds === '' ? 59 : p.resendSeconds, changeLabel: 'Corrigir o e-mail' }, {\n        key: 'resend', style: 'height:auto', onResend: () => emit(d2, 'onResend', email), onChangeEmail: back\n      }) : '';\n      const btn = R.btn ? `<div class=\"full\">${d2.render(R.btn, { label: p.verifyLabel || 'Confirmar e criar conta', variant: 'primary', size: 'lg', fullWidth: 'always', layout }, { key: 'verify', height: 52, onClick: verify })}</div>` : '';\n      return `<div class=\"sf l-${layout} step-code\" role=\"form\" aria-label=\"Confirmar o e-mail\"><div class=\"code\">${notice}${code}${resend}${btn}</div></div>`;\n    }\n\n    // ——— Etapa 1: formulário\n    const cepHint = d2.state.cepStatus === 'loading' ? 'Buscando o endereço…' : (d2.state.cepStatus === 'ok' ? 'Endereço preenchido pelo CEP. Confere e completa o que faltar.' : '');\n    const sections = SECTIONS(cepHint).map((sec) => R.fs ? d2.render(R.fs, {\n      index: sec.index, title: sec.title, rows: sec.rows, values: store(d2).v, errors: errs, version: String(ver[sec.id] || 0) + (sec.id === 's2' ? '-' + (d2.state.cepStatus || '') : ''),\n      layout, formField: R.ff, taxIdField: R.tx, radio: R.rd, iconComponent: R.icon\n    }, { key: sec.id + '-' + (ver[sec.id] || 0) + (sec.id === 's2' ? '-' + (d2.state.cepStatus || '') : ''), style: 'height:auto', onInput: onField }) : '');\n\n    // Regras da senha, logo abaixo da seção 03 — atualizam enquanto a pessoa digita\n    const rules = pwRules(store(d2).v.senha, store(d2).v.email);\n    const rulesHtml = `<ul class=\"rules${errs.senha && store(d2).v.senha ? ' err' : ''}\" aria-label=\"Regras da senha\">${rules.map((r) => `<li class=\"${r.ok ? 'ok' : ''}\">\n        <span class=\"dot\" aria-hidden=\"true\">${r.ok && R.icon ? d2.render(R.icon, { name: 'check', size: 12, iconColor: '#ffffff' }, { key: 'rk-' + r.id, width: 12, height: 12, style: 'flex:none' }) : ''}</span>\n        <span>${esc(r.label)}<span class=\"sr\">${r.ok ? ' — ok' : ' — falta'}</span></span></li>`).join('')}</ul>`;\n    sections.splice(3, 0, rulesHtml);\n\n    // Conta existente (resposta do servidor)\n    const mail = String(store(d2).v.email || '').trim();\n    const q = mail ? '?email=' + encodeURIComponent(mail) : '';\n    const exists = (truthy(p.accountExists) || d2.state.exists) ? `<div class=\"exists\">${R.nt ? d2.render(R.nt, {\n      tone: 'accent', iconName: 'user', live: true, layout, iconComponent: R.icon,\n      body: p.accountExistsText || '**Os dados informados já possuem um cadastro vinculado.** Entre com a sua senha ou recupere o acesso.'\n    }, { key: 'exists', style: 'height:auto' }) : ''}<div class=\"acts\">${R.btn ? d2.render(R.btn, { label: 'Entrar', variant: 'primary', href: (p.loginHref || '/entrar') + q, layout }, { key: 'ex-login' }) : ''}${R.btn ? d2.render(R.btn, { label: 'Esqueci minha senha', variant: 'outline', href: (p.forgotHref || '/esqueci-minha-senha') + q, layout }, { key: 'ex-forgot' }) : ''}</div></div>` : '';\n\n    const cons = (key, label, top, err) => R.cb ? d2.render(R.cb, { name: key, label, top, checked: !!store(d2)[key], error: err || '', layout, iconComponent: R.icon }, {\n      key: 'cb-' + key + '-' + (ver.c || 0), style: 'height:auto', onChange: (v) => { store(d2)[key] = !!v; }\n    }) : '';\n    const consents = `<div class=\"consents\">\n      ${cons('privacy', 'Li e aceito a [Política de Privacidade](' + (p.privacyHref || '/politicas/privacidade') + ') e os [Termos de Uso](' + (p.termsHref || '/politicas/termos-de-venda') + ').', true, errs.privacy)}\n      ${cons('news', 'Quero receber novidades, lançamentos e ofertas por e-mail e WhatsApp. ((opcional — dá pra mudar quando quiser))', true, '')}\n    </div>`;\n    const n = Object.keys(errs).length;\n    const summary = n ? `<p class=\"summary\" role=\"alert\">Faltou ${n === 1 ? '1 coisa' : n + ' coisas'} — confere os campos marcados em vermelho.</p>` : (d2.state.srvErr ? `<p class=\"summary\" role=\"alert\">${esc(d2.state.srvErr)}</p>` : '');\n    const sending = !!d2.state.sending;\n    const btn = R.btn ? `<div class=\"submit\">${d2.render(R.btn, { label: sending ? 'Criando sua conta…' : (p.submitLabel || 'Criar minha conta'), variant: 'primary', size: 'lg', fullWidth: 'always', isDisabled: sending, layout }, { key: 'submit-' + (sending ? 's' : 'i'), height: 52, onClick: submit })}</div>` : '';\n    return `<div class=\"sf l-${layout}\" role=\"form\" aria-label=\"Criar conta\">\n      ${exists}\n      ${sections.join('')}\n      ${consents}\n      ${summary}\n      <div class=\"foot\">${btn}<p class=\"have\">Já tem conta? <a href=\"${esc(p.loginHref || '/entrar')}\">Entrar</a></p></div>\n    </div>`;\n  }\n};"}},"accountExists":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"accountExists"}}}},"accountExistsText":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"accountExistsText"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"checkbox":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkbox"}}}},"codeError":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"codeError"}}}},"codeField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"codeField"}}}},"codeValidity":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"codeValidity"}}}},"documentError":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"documentError"}}}},"email":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"email"}}}},"emailError":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"emailError"}}}},"forgotHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"forgotHref"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"formSection":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formSection"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"loginHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"loginHref"}}}},"notice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notice"}}}},"onCep":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCep"}}}},"onChangeEmail":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChangeEmail"}}}},"onLogin":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onLogin"}}}},"onResend":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onResend"}}}},"onSubmit":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSubmit"}}}},"onVerify":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onVerify"}}}},"privacyHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"privacyHref"}}}},"radio":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"radio"}}}},"resendCode":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"resendCode"}}}},"resendSeconds":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"resendSeconds"}}}},"step":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"step"}}}},"submitLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"submitLabel"}}}},"taxIdField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"taxIdField"}}}},"termsHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"termsHref"}}}},"verifyEmail":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"verifyEmail"}}}},"verifyLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"verifyLabel"}}}}}}}}}},{"_id":"6abc37d14516435d442e6467","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"SignupLayout","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// SignupLayout — Loja Lucas Fontana\n// O corpo da página de cadastro: kicker \"Criar conta\", título \"BORA CRIAR SUA CONTA\" (44/36/28px) e a frase\n// \"Leva um minutinho…\", depois o formulário (SignupForm, até 824px) e, no desktop, a lateral fixa de 360px com o\n// PromoCard compact (\"Por que criar conta\"), que acompanha a rolagem. No tablet e no mobile a lateral some.\n// Traz o respiro da página: 72/48/32px em cima e 120/88/64px embaixo.\n// Os textos do formulário chegam por `form` (parâmetros do SignupForm) e os da lateral por `aside` (do PromoCard).\n// Não desenha nada disso: usa SignupForm e PromoCard por parâmetro (e repassa FormSection, FormField, TaxIdField,\n// Radio, Checkbox, Notice, CodeField, ResendCode, CheckList, Button e Icon).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst PAD = { desktop: '72px 96px 120px', tablet: '48px 40px 88px', mobile: '32px 20px 64px' };\nconst WHY = ['Acompanhe seus pedidos e o código de rastreio', 'Compre mais rápido com seus dados já preenchidos', 'Seja avisado quando o produto do vídeo voltar ao estoque'];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.su { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-700: #45474b;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased; width: 100%; background: var(--white); color: var(--ink); }\n.in { display: grid; grid-template-columns: minmax(0, 824px) 360px; justify-content: space-between; gap: 64px; align-items: start; max-width: 1248px; margin: 0 auto; }\n.main { min-width: 0; display: flex; flex-direction: column; gap: 40px; }\n.head { display: flex; flex-direction: column; gap: 14px; max-width: 640px; }\np, h1 { margin: 0; }\n.kicker { display: flex; align-items: center; gap: 12px; font-size: 12px; font-weight: 700; letter-spacing: .3em; line-height: 1.3; text-transform: uppercase; color: var(--red-500); }\n.kicker::before { content: ''; width: 22px; height: 3px; background: var(--red-500); flex: none; }\n.title { font-size: 44px; font-weight: 800; font-stretch: 115%; line-height: 1; letter-spacing: -.01em; text-transform: uppercase; }\n.text { font-size: 16px; line-height: 1.55; color: var(--grey-700); }\n.aside { position: sticky; top: 24px; min-width: 0; }\n.l-tablet .in, .l-mobile .in { grid-template-columns: minmax(0, 1fr); }\n.l-tablet .aside, .l-mobile .aside { display: none; }\n.l-tablet .title { font-size: 36px; }\n.l-mobile .main { gap: 32px; }\n.l-mobile .kicker { font-size: 11px; letter-spacing: .26em; }\n.l-mobile .title { font-size: 28px; font-stretch: 112%; letter-spacing: 0; }\n.l-mobile .text { font-size: 15px; }\n`,\n\n  mounted() { FONT(); },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const r = (n) => refOf(d2.param(n));\n    const icon = r('iconComponent'); const btn = r('button');\n    const form = r('signupForm') ? d2.render(r('signupForm'), Object.assign({}, obj(p.form), {\n      layout, formSection: r('formSection'), formField: r('formField'), taxIdField: r('taxIdField'), radio: r('radio'),\n      checkbox: r('checkbox'), notice: r('notice'), codeField: r('codeField'), resendCode: r('resendCode'), button: btn, iconComponent: icon\n    }), {\n      key: 'form', style: 'height:auto',\n      onSubmit: (v) => emit(d2, 'onSubmit', v), onVerify: (v) => emit(d2, 'onVerify', v), onResend: (v) => emit(d2, 'onResend', v),\n      onChangeEmail: (v) => emit(d2, 'onChangeEmail', v), onLogin: (h) => emit(d2, 'onLogin', h), onCep: (v) => emit(d2, 'onCep', v)\n    }) : '';\n    const showAside = layout === 'desktop' && (p.showAside == null || p.showAside === '' || truthy(p.showAside));\n    const aside = showAside && r('promoCard') ? d2.render(r('promoCard'), Object.assign({\n      compact: true, eyebrow: 'Por que criar conta', items: WHY,\n      foot: '**Não guardamos dados de cartão.** O pagamento é feito com segurança pelo Mercado Pago.'\n    }, obj(p.aside), { layout, checkList: r('checkList'), button: btn, iconComponent: icon }), { key: 'aside', style: 'height:auto' }) : '';\n    return `<div class=\"su l-${layout}\" style=\"padding:${PAD[layout]}\"><div class=\"in\">\n      <div class=\"main\">\n        <div class=\"head\">\n          <p class=\"kicker\">${esc(p.eyebrow || 'Criar conta')}</p>\n          <h1 class=\"title\">${esc(p.title || 'Bora criar sua conta')}</h1>\n          <p class=\"text\">${esc(p.description || 'Leva um minutinho. Com esses dados a gente emite sua nota fiscal e entrega seu pedido sem enrolação.')}</p>\n        </div>\n        ${form}\n      </div>\n      ${showAside ? `<aside class=\"aside\">${aside}</aside>` : ''}\n    </div></div>`;\n  }\n};"}},"aside":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"aside"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"checkList":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkList"}}}},"checkbox":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkbox"}}}},"codeField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"codeField"}}}},"description":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"description"}}}},"eyebrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"eyebrow"}}}},"form":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"form"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"formSection":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formSection"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"notice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notice"}}}},"onCep":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCep"}}}},"onChangeEmail":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChangeEmail"}}}},"onLogin":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onLogin"}}}},"onResend":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onResend"}}}},"onSubmit":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSubmit"}}}},"onVerify":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onVerify"}}}},"promoCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"promoCard"}}}},"radio":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"radio"}}}},"resendCode":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"resendCode"}}}},"showAside":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"showAside"}}}},"signupForm":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"signupForm"}}}},"taxIdField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"taxIdField"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}}}}}}}},{"_id":"6abcf7cf2e8b2579d186175e","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"StepIndicator","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// StepIndicator — Loja Lucas Fontana\n// Barra de etapas para fluxos curtos: uma barra de 4px por etapa, com o rótulo numerado em caixa alta embaixo\n// (\"1. Pedir link · 2. Confira o e-mail · 3. Nova senha · 4. Pronto\"). Etapas feitas e a atual ficam com a barra\n// vermelha e o rótulo preto; as próximas ficam cinza. A etapa atual leva `aria-current=\"step\"`.\n// De 3 a 5 etapas com rótulos de duas ou três palavras; no mobile os rótulos quebram embaixo da barra.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst list = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst RECOVERY = ['Pedir link', 'Confira o e-mail', 'Nova senha', 'Pronto'];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\nol { --red-500: #c8102e; --ink: #0b0b0c; --grey-500: #6b6e73; --line: #e4e4e2;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  list-style: none; margin: 0; padding: 0; display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 8px; width: 100%; }\nli { display: flex; flex-direction: column; gap: 8px; font-size: 12px; font-weight: 800; letter-spacing: .1em; line-height: 1.25; text-transform: uppercase; color: var(--grey-500); }\nli::before { content: ''; height: 4px; background: var(--line); }\n.is-done, .is-current { color: var(--ink); }\n.is-done::before, .is-current::before { background: var(--red-500); }\n.l-mobile { gap: 6px; }\n.l-mobile li { font-size: 10px; letter-spacing: .08em; }\n`,\n  mounted() { FONT(); },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const steps = list(p.steps).length ? list(p.steps) : RECOVERY;\n    const cur = Math.max(1, Number(p.current) || 1);\n    return `<ol class=\"l-${layout}\" aria-label=\"${esc(p.ariaLabel || 'Etapas')}\">${steps.map((t, i) => {\n      const n = i + 1; const st = n < cur ? 'is-done' : (n === cur ? 'is-current' : 'is-pending');\n      return `<li class=\"${st}\"${n === cur ? ' aria-current=\"step\"' : ''}>${n}. ${esc(t)}</li>`;\n    }).join('')}</ol>`;\n  }\n};"}},"ariaLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ariaLabel"}}}},"current":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"current"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"steps":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"steps"}}}}}}}}}},{"_id":"6abcf7f22e8b2579d18617af","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"ForgotPasswordForm","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// ForgotPasswordForm — Loja Lucas Fontana\n// O cartão de recuperar senha, aberto pelo \"Esqueci minha senha\" do login. Fica no AuthLayout `mode: \"forgot\"`\n// (cartão único de 560px centralizado; sem borda no mobile). Duas etapas no MESMO componente:\n// Etapa 1 (`step: \"request\"`): StepIndicator em 1, kicker \"Recuperar senha\", \"ESQUECEU A SENHA?\", \"Acontece nas melhores\n// garagens…\", o campo de e-mail, o botão preto \"Enviar link\" e \"Voltar para o login\".\n// Etapa 2 (`step: \"sent\"`): StepIndicator em 2, o quadrado preto com envelope, kicker \"Quase lá\", \"CONFIRA SEU E-MAIL\",\n// \"Se existir uma conta com **[e-mail]**, você vai receber um link… O link vale por [X] minutos.\", o aviso com barra preta\n// sobre spam/promoções, o botão preto \"Voltar para o login\" e, centralizado, \"Não chegou? Reenviar em 0:59\" / \"Usar outro e-mail\".\n// Nunca diz se o e-mail tem cadastro: o texto da etapa 2 é o mesmo em qualquer caso.\n// Fluxo: \"Enviar link\" confere o e-mail, emite `onSubmit` {email} e passa sozinho para a etapa 2 (`autoAdvance: false` desliga).\n// \"Usar outro e-mail\" volta para a etapa 1 com o e-mail preenchido (`onChangeEmail`); \"Reenviar\" emite `onResend`.\n// As etapas 3 (Nova senha) e 4 (Pronto) ainda não estão no design system.\n// Não desenha etapas, campo, aviso, botão nem ícone: usa StepIndicator, FormField, Notice, ResendCode, Button e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst EMAIL = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nconst store = (d2) => (d2.root ? (d2.root.__lf || (d2.root.__lf = { email: '' })) : { email: '' });\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.fp { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-700: #45474b; --line: #e4e4e2;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: flex; flex-direction: column; gap: 18px; width: 100%; height: 100%; padding: 56px; border: 1px solid var(--line); background: var(--white); color: var(--ink); }\np, h1 { margin: 0; }\n.steps { margin-bottom: 12px; }\n.mark { width: 56px; height: 56px; background: var(--ink); color: var(--white); display: flex; align-items: center; justify-content: center; }\n.kicker { display: flex; align-items: center; gap: 12px; font-size: 12px; font-weight: 700; letter-spacing: .3em; line-height: 1.3; text-transform: uppercase; color: var(--red-500); }\n.kicker::before { content: ''; width: 22px; height: 3px; background: var(--red-500); flex: none; }\n.title { font-size: 40px; font-weight: 800; font-stretch: 115%; line-height: 1; letter-spacing: -.01em; text-transform: uppercase; }\n.text { margin: -4px 0 6px; font-size: 16px; line-height: 1.55; color: var(--grey-700); }\n.text b { color: var(--ink); }\n.btn { height: 52px; margin-top: 4px; }\n.back { align-self: center; min-height: 36px; display: inline-flex; align-items: center; font-size: 15px; font-weight: 700; color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }\n.back:hover { color: var(--red-500); }\n.back:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.l-tablet { padding: 40px; }\n.l-tablet .title { font-size: 34px; }\n.l-mobile { padding: 0; border: 0; gap: 16px; }\n.l-mobile .kicker { font-size: 11px; letter-spacing: .26em; }\n.l-mobile .title { font-size: 30px; font-stretch: 112%; letter-spacing: 0; }\n.l-mobile .text { font-size: 15px; }\n`,\n\n  mounted(d2) {\n    FONT();\n    d2.on('.back', 'click', (e, el) => emit(d2, 'onBack', el.getAttribute('href')));\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const R = { st: refOf(d2.param('stepIndicator')), ff: refOf(d2.param('formField')), nt: refOf(d2.param('notice')),\n      rs: refOf(d2.param('resendCode')), btn: refOf(d2.param('button')), icon: refOf(d2.param('iconComponent')) };\n    const s = store(d2);\n    if (!s.email && p.email) s.email = String(p.email);\n    const step = d2.state.step || (p.step === 'sent' ? 'sent' : 'request');\n    const sent = step === 'sent';\n    const loginHref = p.loginHref || '/entrar';\n    const err = sent ? '' : (d2.state.err || p.emailError || '');\n\n    const submit = () => {\n      const email = String(store(d2).email || '').trim();\n      const e = !email ? 'Informe o e-mail da sua conta.' : (!EMAIL.test(email) ? 'Confira o e-mail: falta o @ ou o domínio.' : '');\n      d2.state.err = e;\n      if (e) return;\n      emit(d2, 'onSubmit', { email });\n      if (p.autoAdvance == null || p.autoAdvance === '' || truthy(p.autoAdvance)) d2.state.step = 'sent';\n    };\n    const back = () => { d2.state.err = ''; d2.state.step = 'request'; emit(d2, 'onChangeEmail', store(d2).email); };\n\n    const steps = R.st ? `<div class=\"steps\">${d2.render(R.st, { current: sent ? 2 : 1, ariaLabel: 'Etapas para recuperar a senha', layout }, { key: 'st-' + step, style: 'height:auto' })}</div>` : '';\n    const mark = sent && R.icon ? `<span class=\"mark\" aria-hidden=\"true\">${d2.render(R.icon, { name: 'mail', size: 24, iconColor: '#ffffff' }, { key: 'mail', width: 24, height: 24 })}</span>` : '';\n    const btn = (key, label, href, onClick) => R.btn ? `<div class=\"btn\">${d2.render(R.btn, { label, variant: 'primary', size: 'lg', fullWidth: 'always', href: href || '', layout }, { key, height: 52, onClick })}</div>` : '';\n\n    let body;\n    if (sent) {\n      const email = esc(store(d2).email || '[e-mail informado]');\n      const notice = R.nt ? d2.render(R.nt, { tone: 'accent', iconName: 'mail', layout, iconComponent: R.icon, body: p.noticeText || 'Não achou? Dá uma olhada no spam ou na aba de promoções.' }, { key: 'notice', style: 'height:auto' }) : '';\n      const resend = R.rs ? d2.render(R.rs, { layout, align: 'center', seconds: p.resendSeconds == null || p.resendSeconds === '' ? 59 : p.resendSeconds, resendLabel: 'Reenviar link' }, {\n        key: 'resend', style: 'height:auto', onResend: () => emit(d2, 'onResend', store(d2).email), onChangeEmail: back\n      }) : '';\n      body = `${steps}${mark}\n        <p class=\"kicker\">Quase lá</p>\n        <h1 class=\"title\">Confira seu e‑mail</h1>\n        <p class=\"text\" role=\"status\">Se existir uma conta com <b>${email}</b>, você vai receber um link para criar uma senha nova. O link vale por ${esc(p.linkValidity || '[X]')} minutos.</p>\n        ${notice}\n        ${btn('back', 'Voltar para o login', loginHref, () => emit(d2, 'onBack', loginHref))}\n        ${resend}`;\n    } else {\n      const field = R.ff ? d2.render(R.ff, {\n        label: 'E-mail', type: 'email', name: 'email', autoComplete: 'email', inputMode: 'email', placeholder: 'seuemail@exemplo.com',\n        value: store(d2).email, error: err, layout, iconComponent: R.icon\n      }, { key: 'email' + (err ? '-e' + err.length : ''), style: 'height:auto', onInput: (v) => { store(d2).email = v; } }) : '';\n      body = `${steps}\n        <p class=\"kicker\">Recuperar senha</p>\n        <h1 class=\"title\">Esqueceu a senha?</h1>\n        <p class=\"text\">${esc(p.description || 'Acontece nas melhores garagens. Digite o e-mail da sua conta que a gente manda um link para você criar uma senha nova.')}</p>\n        ${field}\n        ${btn('submit', p.submitLabel || 'Enviar link', '', submit)}\n        <a class=\"back\" href=\"${esc(loginHref)}\">Voltar para o login</a>`;\n    }\n    return `<div class=\"fp l-${layout} step-${step}\" role=\"form\" aria-label=\"Recuperar senha\">${body}</div>`;\n  }\n};"}},"autoAdvance":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"autoAdvance"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"description":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"description"}}}},"email":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"email"}}}},"emailError":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"emailError"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"linkValidity":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"linkValidity"}}}},"loginHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"loginHref"}}}},"notice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notice"}}}},"noticeText":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"noticeText"}}}},"onBack":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onBack"}}}},"onChangeEmail":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChangeEmail"}}}},"onResend":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onResend"}}}},"onSubmit":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSubmit"}}}},"resendCode":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"resendCode"}}}},"resendSeconds":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"resendSeconds"}}}},"step":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"step"}}}},"stepIndicator":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"stepIndicator"}}}},"submitLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"submitLabel"}}}}}}}}}},{"_id":"6abd1fc47e17d43be42a5943","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"StatusBadge","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// StatusBadge — Loja Lucas Fontana\n// O status do pedido, diferenciado por preenchimento e borda além da cor (quem não enxerga cor também distingue):\n// `shipped` \"Enviado\" — preenchido de preto.\n// `pending` \"Aguardando pagamento\" — contorno e texto vermelhos (é o que pede ação).\n// `paid` \"Pagamento aprovado\" — contorno preto.\n// `delivered` \"Entregue\" — fundo grey-100.\n// `canceled` \"Cancelado\" — contorno cinza tracejado.\n// `refused` \"Recusado ou expirado\" e `refunded` \"Estornado\" — os dois status de pagamento do documento de requisitos (5.2),\n// com o mesmo visual tracejado do cancelado.\n// 28px de altura, 11px em caixa alta. `label` troca o texto padrão.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst arr = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\n\nconst STATUS = {\n  shipped: 'Enviado', pending: 'Aguardando pagamento', paid: 'Pagamento aprovado', delivered: 'Entregue',\n  canceled: 'Cancelado', refused: 'Recusado ou expirado', refunded: 'Estornado'\n};\n\nexport default {\n  css: `\n:host { display: inline-block; }\n* { box-sizing: border-box; }\n.st { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-100: #ececea; --grey-400: #8e9095; --grey-500: #6b6e73;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: inline-flex; align-items: center; height: 28px; padding: 0 10px; font-size: 11px; font-weight: 800; letter-spacing: .12em; line-height: 1;\n  text-transform: uppercase; white-space: nowrap; border: 1.5px solid transparent; }\n.s-shipped { background: var(--ink); color: var(--white); }\n.s-pending { background: var(--white); color: var(--red-500); border-color: var(--red-500); }\n.s-paid { background: var(--white); color: var(--ink); border-color: var(--ink); }\n.s-delivered { background: var(--grey-100); color: var(--ink); }\n.s-canceled, .s-refused, .s-refunded { background: var(--white); color: var(--grey-500); border: 1.5px dashed var(--grey-400); }\n`,\n  mounted() { FONT(); },\n  render(d2) {\n    const p = d2.params || {};\n    const st = STATUS[p.status] ? p.status : 'paid';\n    return `<span class=\"st s-${st}\">${esc(p.label || STATUS[st])}</span>`;\n  }\n};\n"}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"status":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"status"}}}}}}}}}},{"_id":"6abd1fc4e6552f4472d7dacf","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"PanelHeader","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// PanelHeader — Loja Lucas Fontana\n// O título de um painel da conta: largo em caixa alta, 28px (24px no mobile), com uma linha cinza embaixo\n// (\"Clique em um pedido para ver os itens, o pagamento e o rastreio.\").\n// `title`, `text`, `layout`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst arr = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.ph { --ink: #0b0b0c; --grey-500: #6b6e73; font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: flex; flex-direction: column; gap: 6px; width: 100%; }\nh2 { margin: 0; font-size: 28px; font-weight: 800; font-stretch: 115%; line-height: 1.05; text-transform: uppercase; color: var(--ink); overflow-wrap: break-word; }\np { margin: 0; font-size: 15px; line-height: 1.45; color: var(--grey-500); }\n.l-mobile h2 { font-size: 24px; font-stretch: 112%; }\n`,\n  mounted() { FONT(); },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    return `<div class=\"ph l-${layout}\"><h2>${esc(p.title || 'Meus pedidos')}</h2>${p.text ? `<p>${esc(p.text)}</p>` : ''}</div>`;\n  }\n};\n"}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"text":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"text"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}}}}}}}},{"_id":"6abd1fc4edeff59159dbcd8e","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"OrderList","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// OrderList — Loja Lucas Fontana\n// Os pedidos da pessoa, do mais novo para o mais antigo.\n// Desktop: tabela (Pedido · Data · Itens · Total · Status) com régua preta no cabeçalho, linhas de 80px e um botão com\n// contorno \"Ver pedido\" por linha. Tablet: cards em duas colunas. Mobile: uma coluna.\n// Pedido aguardando pagamento ganha o link vermelho \"Pagar com Pix\" (dentro do card no tablet e no mobile).\n// `orders: [{ number, date, items, total, status, statusLabel, href, payHref }]` — `status` segue o StatusBadge.\n// Sem pedidos, mostra o estado vazio (\"Nenhum pedido por aqui ainda\" + \"Ver produtos\"); textos em `empty`.\n// Avisa `onView` e `onPay` com { number, href } quando o pedido não tem link próprio.\n// Não desenha status, botão, link nem ícone: usa StatusBadge, Button, TextLink e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst arr = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\n\nconst byNumberDesc = (a, b) => String(b.number).localeCompare(String(a.number), 'pt-BR', { numeric: true });\nconst itemsTxt = (n) => { const k = Number(n) || 0; return k + (k === 1 ? ' item' : ' itens'); };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.ol { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-500: #6b6e73; --grey-700: #45474b; --line: #e4e4e2;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased; width: 100%; background: var(--white); }\ntable { width: 100%; border-collapse: collapse; }\nth { text-align: left; padding: 0 16px 12px; border-bottom: 2px solid var(--ink); font-size: 12px; font-weight: 800; letter-spacing: .14em;\n  text-transform: uppercase; color: var(--ink); white-space: nowrap; }\ntd { height: 80px; padding: 0 16px; border-bottom: 1px solid var(--line); font-size: 15px; color: var(--grey-700); white-space: nowrap; vertical-align: middle; }\nth:first-child, td:first-child { padding-left: 0; }\nth:last-child, td:last-child { padding-right: 0; }\ntd.num { font-size: 16px; font-weight: 800; color: var(--ink); }\ntd.total { font-weight: 700; color: var(--ink); }\ntd.act { text-align: right; }\n.bw { display: flex; align-items: center; height: 28px; overflow: hidden; flex: none; }\n.actions { display: inline-flex; align-items: center; justify-content: flex-end; gap: 16px; }\n.pay { font-size: 14px; font-weight: 700; color: var(--red-500); text-decoration: underline; text-underline-offset: 3px; white-space: nowrap; }\n.pay:hover { color: var(--ink); }\n.pay:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }\n.cards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }\n.l-mobile .cards { grid-template-columns: minmax(0, 1fr); gap: 12px; }\n.card { display: flex; flex-direction: column; gap: 14px; padding: 20px; border: 1px solid var(--line); background: var(--white); min-width: 0; }\n.top { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }\n.top h3 { margin: 0; font-size: 18px; font-weight: 800; line-height: 1.2; color: var(--ink); }\n.row { display: flex; justify-content: space-between; gap: 12px; font-size: 14px; color: var(--grey-700); }\n.row b { color: var(--ink); }\n.foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; }\n.foot .view { margin-left: auto; }\n.empty { display: flex; flex-direction: column; align-items: flex-start; gap: 16px; padding: 40px; border: 1px solid var(--line); background: var(--white); }\n.l-mobile .empty { padding: 28px 20px; align-items: stretch; }\n.empty .sq { width: 56px; height: 56px; background: var(--ink); color: var(--white); display: flex; align-items: center; justify-content: center; }\n.empty h3 { margin: 4px 0 0; font-size: 24px; font-weight: 800; font-stretch: 112%; line-height: 1.1; text-transform: uppercase; color: var(--ink); }\n.empty p { margin: 0; max-width: 520px; font-size: 15px; line-height: 1.5; color: var(--grey-700); }\n.empty .cta { margin-top: 8px; }\n`,\n\n  mounted(d2) {\n    FONT();\n    d2.on('.pay', 'click', (e, el) => {\n      const number = el.getAttribute('data-num');\n      if (!el.getAttribute('data-href')) e.preventDefault();\n      emit(d2, 'onPay', { number, href: el.getAttribute('data-href') || '' });\n    });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const R = { st: refOf(d2.param('statusBadge')), btn: refOf(d2.param('button')), link: refOf(d2.param('textLink')), icon: refOf(d2.param('iconComponent')) };\n    const orders = arr(p.orders).map(obj).filter((o) => o.number != null).sort(byNumberDesc);\n\n    if (!orders.length) {\n      const e = obj(p.empty);\n      const sq = R.icon ? d2.render(R.icon, { name: 'bag', size: 26, iconColor: '#ffffff' }, { key: 'e-ic', width: 26, height: 26, style: 'flex:none' }) : '';\n      const cta = R.btn ? d2.render(R.btn, {\n        label: e.ctaLabel || 'Ver produtos', href: e.ctaHref || '/produtos', variant: 'primary', arrow: true, fullWidth: 'mobile', layout\n      }, { key: 'e-cta' }) : '';\n      return `<div class=\"ol l-${layout}\"><div class=\"empty\">\n        <span class=\"sq\" aria-hidden=\"true\">${sq}</span>\n        <h3>${esc(e.title || 'Nenhum pedido por aqui ainda')}</h3>\n        <p>${esc(e.text || 'Quando você fizer a primeira compra, é aqui que acompanha o pagamento, o envio e o código de rastreio.')}</p>\n        <div class=\"cta\">${cta}</div>\n      </div></div>`;\n    }\n\n    const badge = (o, where) => R.st ? '<div class=\"bw\">' + d2.render(R.st, { status: o.status, label: o.statusLabel || '' },\n      { key: 'st-' + where + '-' + o.number + '-' + o.status + '-' + (o.statusLabel || ''), style: 'display:inline-flex;vertical-align:middle;flex:none' }) + '</div>' : '';\n    const pay = (o) => (o.status === 'pending' && o.payHref !== null)\n      ? `<a class=\"pay\" href=\"${esc(o.payHref || '#')}\" data-num=\"${esc(o.number)}\" data-href=\"${esc(o.payHref || '')}\">Pagar com Pix</a>` : '';\n    const view = (o) => emit(d2, 'onView', { number: String(o.number), href: o.href || '' });\n\n    if (layout === 'desktop') {\n      const rows = orders.map((o) => {\n        const btn = R.btn ? d2.render(R.btn, { label: 'Ver pedido', variant: 'outline', size: 'sm', href: o.href || '', layout },\n          { key: 'v-' + o.number + (o.href ? '-l' : ''), onClick: () => view(o) }) : '';\n        return `<tr data-key=\"${esc(o.number)}\">\n          <td class=\"num\">#${esc(o.number)}</td><td>${esc(o.date)}</td><td>${esc(itemsTxt(o.items))}</td><td class=\"total\">${esc(o.total)}</td>\n          <td>${badge(o, 't')}</td>\n          <td class=\"act\"><span class=\"actions\">${pay(o)}${btn}</span></td>\n        </tr>`;\n      }).join('');\n      return `<div class=\"ol l-${layout}\"><table>\n        <thead><tr><th scope=\"col\">Pedido</th><th scope=\"col\">Data</th><th scope=\"col\">Itens</th><th scope=\"col\">Total</th><th scope=\"col\">Status</th><th><span class=\"sr\">Ações</span></th></tr></thead>\n        <tbody>${rows}</tbody></table></div>`;\n    }\n\n    const cards = orders.map((o) => {\n      const link = R.link ? d2.render(R.link, { label: 'Ver pedido', arrow: true, href: o.href || '', layout },\n        { key: 'l-' + o.number + (o.href ? '-l' : ''), onClick: () => view(o) }) : '';\n      return `<article class=\"card\" data-key=\"${esc(o.number)}\">\n        <div class=\"top\"><h3>Pedido #${esc(o.number)}</h3>${badge(o, 'c')}</div>\n        <div class=\"row\"><span>${esc(o.date)} · ${esc(itemsTxt(o.items))}</span><b>${esc(o.total)}</b></div>\n        <div class=\"foot\">${pay(o)}<span class=\"view\">${link}</span></div>\n      </article>`;\n    }).join('');\n    return `<div class=\"ol l-${layout}\"><div class=\"cards\">${cards}</div></div>`;\n  }\n};\n"}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"empty":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"empty"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onPay":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onPay"}}}},"onView":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onView"}}}},"orders":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"orders"}}}},"statusBadge":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"statusBadge"}}}},"textLink":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"textLink"}}}}}}}}}},{"_id":"6abd1fc4b32542bffaceb415","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"AccountLayout","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// AccountLayout — Loja Lucas Fontana\n// A moldura de \"Minha conta\": breadcrumb, \"Olá, [Nome]!\" (44/36/28px) e o subtítulo, depois a navegação da conta e o painel.\n// Desktop: menu lateral de 264px (Meus pedidos · Meus dados · Endereços, uma linha fina e Sair), com o item atual\n// preenchido de preto. Tablet e mobile: o menu vira uma barra de abas embaixo da saudação (rola para o lado no mobile);\n// no mobile o \"Sair\" sai da barra e vai para o fim da página.\n// O painel começa com o PanelHeader (`panelTitle`, `panelText`) e segue com o componente do conteúdo, que chega por\n// `content` com os parâmetros em `contentParams` (Meus pedidos: OrderList + { orders }). Assim a mesma moldura\n// serve para Meus dados e Endereços.\n// `name`, `title`, `subtitle`, `crumbs`, `current` (pedidos | dados | enderecos), `nav` (troca os itens), `logoutHref`.\n// Avisa `onNavigate` (item), `onLogout`, e repassa `onView`, `onPay`, `onChange` e `onSubmit` do conteúdo.\n// Não desenha breadcrumb, título do painel nem ícone: usa Breadcrumb, PanelHeader e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst arr = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\n\nconst NAV = [\n  { key: 'pedidos', label: 'Meus pedidos', icon: 'bag', href: '/minha-conta/pedidos' },\n  { key: 'dados', label: 'Meus dados', icon: 'user', href: '/minha-conta/dados' },\n  { key: 'enderecos', label: 'Endereços', icon: 'pin', href: '/minha-conta/enderecos' }\n];\n// Filhos aninhados não recebem parâmetros novos depois de montados: a chave muda quando o conteúdo muda.\nconst hash = (v) => { const t = JSON.stringify(v) || ''; let h = 0; for (let i = 0; i < t.length; i++) h = (h * 31 + t.charCodeAt(i)) | 0; return (h >>> 0).toString(36); };\nconst PAD = { desktop: '32px 96px 120px', tablet: '28px 40px 88px', mobile: '20px 20px 64px' };\nconst CRUMB_H = { desktop: 24, tablet: 24, mobile: 30 };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.ac { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-50: #f5f5f3; --grey-500: #6b6e73; --grey-700: #45474b; --line: #e4e4e2;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased; width: 100%; background: var(--white); color: var(--ink); }\n.in { display: flex; flex-direction: column; }\n.head { display: flex; flex-direction: column; gap: 12px; padding-bottom: 32px; border-bottom: 1px solid var(--line); }\n.hello { margin: 4px 0 0; font-size: 44px; font-weight: 800; font-stretch: 115%; line-height: 1; letter-spacing: -.01em; text-transform: uppercase; overflow-wrap: break-word; }\n.sub { margin: 0; font-size: 16px; line-height: 1.45; color: var(--grey-700); }\n.body { display: grid; grid-template-columns: 264px minmax(0, 1fr); gap: 56px; padding-top: 40px; align-items: start; }\n.side { display: flex; flex-direction: column; }\n.side a { display: flex; align-items: center; gap: 14px; height: 52px; padding: 0 16px; font-size: 16px; font-weight: 700; line-height: 1;\n  color: var(--ink); text-decoration: none; cursor: pointer; }\n.side a:hover { background: var(--grey-50); }\n.side a[aria-current=\"page\"], .side a[aria-current=\"page\"]:hover { background: var(--ink); color: var(--white); }\n.side a:focus-visible, .tabs a:focus-visible, .out:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.side hr { width: 100%; height: 1px; border: 0; background: var(--line); margin: 12px 0; }\n.main { display: flex; flex-direction: column; gap: 24px; min-width: 0; }\n.tabs { display: none; gap: 32px; border-bottom: 1px solid var(--line); overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }\n.tabs::-webkit-scrollbar { display: none; }\n.tabs a { position: relative; flex-shrink: 0; display: inline-flex; align-items: center; height: 52px; font-size: 13px; font-weight: 800; line-height: 1;\n  letter-spacing: .14em; text-transform: uppercase; color: var(--grey-500); text-decoration: none; white-space: nowrap; }\n.tabs a:hover, .tabs a[aria-current=\"page\"] { color: var(--ink); }\n.tabs a[aria-current=\"page\"]::after { content: ''; position: absolute; left: 0; right: 0; bottom: -1px; height: 3px; background: var(--red-500); }\n.out { display: none; align-items: center; gap: 12px; align-self: flex-start; min-height: 44px; margin-top: 8px; font-size: 15px; font-weight: 700;\n  color: var(--ink); text-decoration: none; }\n.out:hover { color: var(--red-500); }\n\n.l-tablet .head { padding-bottom: 24px; border-bottom: 0; }\n.l-tablet .hello { font-size: 36px; }\n.l-tablet .body, .l-mobile .body { grid-template-columns: minmax(0, 1fr); gap: 32px; padding-top: 0; }\n.l-tablet .side, .l-mobile .side { display: none; }\n.l-tablet .tabs, .l-mobile .tabs { display: flex; }\n.l-mobile .head { padding-bottom: 24px; border-bottom: 0; }\n.l-mobile .hello { font-size: 28px; font-stretch: 112%; letter-spacing: 0; }\n.l-mobile .sub { font-size: 15px; }\n.l-mobile .body { gap: 24px; }\n.l-mobile .tabs { gap: 28px; margin: 0 -20px; padding: 0 20px; }\n.l-mobile .tabs .t-out { display: none; }\n.l-mobile .out { display: inline-flex; }\n`,\n\n  mounted(d2) {\n    FONT();\n    // No tablet e no mobile, a barra de abas rola sozinha até a aba atual (ex.: \"Endereços\" não fica cortado na borda)\n    const showCurrent = () => { const t = d2.$('.tabs [aria-current=\"page\"]'); if (t && t.parentNode) t.parentNode.scrollLeft = Math.max(0, t.offsetLeft - 20); };\n    setTimeout(showCurrent, 0);\n    d2.root && (d2.root.__lfShowTab = showCurrent);\n    d2.on('[data-nav]', 'click', (e, el) => emit(d2, 'onNavigate', { key: el.getAttribute('data-nav'), href: el.getAttribute('href') }));\n    d2.on('[data-out]', 'click', (e, el) => emit(d2, 'onLogout', { href: el.getAttribute('href') }));\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const R = { bc: refOf(d2.param('breadcrumb')), ph: refOf(d2.param('panelHeader')), icon: refOf(d2.param('iconComponent')), content: refOf(d2.param('content')) };\n    const nav = arr(p.nav).length ? arr(p.nav).map(obj) : NAV;\n    const current = p.current || 'pedidos';\n    const logoutHref = p.logoutHref || '/sair';\n    const crumbs = arr(p.crumbs).length ? arr(p.crumbs) : [{ label: 'Início', href: '/' }, { label: 'Minha conta' }];\n    const title = p.title || ('Olá, ' + (p.name || '[Nome]') + '!');\n    const sub = p.subtitle || 'Aqui você acompanha seus pedidos e mantém seus dados em dia.';\n    const ic = (name, key, color) => R.icon\n      ? d2.render(R.icon, { name, size: 20, iconColor: color }, { key, width: 20, height: 20, style: 'flex:none' }) : '';\n\n    const crumb = R.bc ? `<div style=\"height:${CRUMB_H[layout]}px\">${d2.render(R.bc, { items: crumbs, layout },\n      { key: 'bc', onNavigate: (h) => emit(d2, 'onNavigate', { key: 'breadcrumb', href: h }) })}</div>` : '';\n\n    const side = layout === 'desktop' ? `<nav class=\"side\" aria-label=\"Minha conta\">\n      ${nav.map((n) => {\n        const on = n.key === current;\n        return `<a href=\"${esc(n.href || '#')}\" data-nav=\"${esc(n.key)}\"${on ? ' aria-current=\"page\"' : ''}>${ic(n.icon || 'bag', 'n-' + n.key + (on ? '-on' : ''), on ? '#ffffff' : '#0b0b0c')}${esc(n.label)}</a>`;\n      }).join('')}\n      <hr>\n      <a href=\"${esc(logoutHref)}\" data-out=\"1\">${ic('logout', 'n-out', '#0b0b0c')}Sair</a>\n    </nav>` : '';\n\n    const tabs = layout === 'desktop' ? '' : `<nav class=\"tabs\" aria-label=\"Minha conta\">\n      ${nav.map((n) => `<a href=\"${esc(n.href || '#')}\" data-nav=\"${esc(n.key)}\"${n.key === current ? ' aria-current=\"page\"' : ''}>${esc(n.label)}</a>`).join('')}\n      <a class=\"t-out\" href=\"${esc(logoutHref)}\" data-out=\"1\">Sair</a>\n    </nav>`;\n\n    const panel = R.ph ? d2.render(R.ph, { title: p.panelTitle || 'Meus pedidos', text: p.panelText == null ? 'Clique em um pedido para ver os itens, o pagamento e o rastreio.' : p.panelText, layout },\n      { key: 'ph-' + layout + '-' + (p.panelTitle || '') }) : '';\n\n    const cp = obj(p.contentParams);\n    const content = R.content ? d2.render(R.content, Object.assign({}, cp, { layout }), {\n      key: 'ct-' + layout + '-' + hash(cp),\n      onView: (v) => emit(d2, 'onView', v), onPay: (v) => emit(d2, 'onPay', v),\n      onChange: (v) => emit(d2, 'onChange', v), onSubmit: (v) => emit(d2, 'onSubmit', v)\n    }) : '';\n\n    const out = layout === 'mobile' ? `<a class=\"out\" href=\"${esc(logoutHref)}\" data-out=\"1\">${ic('logout', 'm-out', '#0b0b0c')}Sair da conta</a>` : '';\n\n    return `<div class=\"ac l-${layout}\"><div class=\"in\" style=\"padding:${PAD[layout]}\">\n      <div class=\"head\">${crumb}<h1 class=\"hello\">${esc(title)}</h1><p class=\"sub\">${esc(sub)}</p></div>\n      <div class=\"body\">${side}<div class=\"main\">${tabs}${panel}${content}${out}</div></div>\n    </div></div>`;\n  }\n};\n"}},"breadcrumb":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"breadcrumb"}}}},"content":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"content"}}}},"contentParams":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"contentParams"}}}},"crumbs":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"crumbs"}}}},"current":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"current"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"logoutHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"logoutHref"}}}},"name":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"name"}}}},"nav":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"nav"}}}},"onChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChange"}}}},"onLogout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onLogout"}}}},"onNavigate":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onNavigate"}}}},"onPay":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onPay"}}}},"onSubmit":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSubmit"}}}},"onView":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onView"}}}},"panelHeader":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"panelHeader"}}}},"panelText":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"panelText"}}}},"panelTitle":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"panelTitle"}}}},"subtitle":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"subtitle"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}}}}}}}},{"_id":"6abd39a2edeff59159dc0d8a","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"AccountDataForm","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// AccountDataForm — Loja Lucas Fontana\n// O conteúdo do painel \"Meus dados\" (entra no AccountLayout por `content`), na ordem do design system:\n// Notice cinza com cadeado (\"Não guardamos dados de cartão…\") → CPF ou CNPJ → Nome completo → E-mail + WhatsApp →\n// \"Comunicações\" (linha fina acima, consentimento por e-mail e por WhatsApp e a linha cinza sobre os avisos de pedido)\n// → botão preto \"Salvar alterações\" → rodapé da conta (\"Quer trocar a senha?…\" e o link \"Quero excluir minha conta\").\n// Salvar valida documento (dígitos conferidos), nome, e-mail e WhatsApp; cada erro some quando a pessoa corrige o campo.\n// Com tudo certo, avisa `onSubmit` com { docKind, doc, name, email, whatsapp, optEmail, optWhatsapp } e mostra o Notice\n// de destaque \"Dados salvos.\" acima do botão (some quando a pessoa mexe de novo).\n// \"Quero excluir minha conta\" abre a confirmação ali mesmo (régua vermelha, o que é apagado, \"Sim, excluir minha conta\" /\n// \"Cancelar\"); só o \"Sim\" avisa `onDelete` e troca a confirmação pelo aviso de pedido recebido.\n// `values`: { docKind, doc, name, email, whatsapp, optEmail, optWhatsapp } — o que vem do cadastro.\n// `status`: \"saving\" trava o botão; \"error\" mostra o aviso de falha acima dele; \"saved\" força o aviso de salvo.\n// Não desenha nada: usa FormSection, FormField, TaxIdField, Radio, Checkbox, Button, Notice e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\nconst rich = (t) => esc(t).replace(/\\*\\*(.+?)\\*\\*/g, '<b>$1</b>');\n\n// Mesma conferência de dígitos do TaxIdField (CPF e CNPJ, inclusive o alfanumérico)\nconst validCPF = (d) => {\n  if (!/^\\d{11}$/.test(d) || /^(\\d)\\1+$/.test(d)) return false;\n  const calc = (n) => { let s = 0; for (let i = 0; i < n; i++) s += Number(d[i]) * (n + 1 - i); const r = (s * 10) % 11; return r === 10 ? 0 : r; };\n  return calc(9) === Number(d[9]) && calc(10) === Number(d[10]);\n};\nconst validCNPJ = (raw) => {\n  const d = String(raw || '').toUpperCase();\n  if (!/^[A-Z0-9]{12}\\d{2}$/.test(d) || /^(.)\\1+$/.test(d)) return false;\n  const val = (c) => c.charCodeAt(0) - 48;\n  const calc = (n) => { const w = n === 12 ? [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2] : [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]; let s = 0; for (let i = 0; i < n; i++) s += val(d[i]) * w[i]; const r = s % 11; return r < 2 ? 0 : 11 - r; };\n  return calc(12) === Number(d[12]) && calc(13) === Number(d[13]);\n};\nconst docDigits = (kind, v) => (kind === 'cnpj' ? String(v || '').toUpperCase().replace(/[^A-Z0-9]/g, '') : String(v || '').replace(/\\D/g, ''));\nconst EMAIL = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]{2,}$/;\n// Filhos aninhados não recebem parâmetros novos depois de montados: a chave muda quando o que eles mostram muda.\nconst hash = (v) => { const t = JSON.stringify(v) || ''; let h = 0; for (let i = 0; i < t.length; i++) h = (h * 31 + t.charCodeAt(i)) | 0; return (h >>> 0).toString(36); };\nconst box = (d2) => { const r = d2.root || d2; if (!r.__lfv) r.__lfv = {}; return r; };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.ad { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-50: #f5f5f3; --grey-700: #45474b; --line: #e4e4e2;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased; display: flex; flex-direction: column; gap: 24px; width: 100%; background: var(--white); }\n.save { display: flex; flex-direction: column; gap: 16px; align-items: flex-start; }\n.l-mobile .save { align-items: stretch; }\n.foot { display: flex; flex-direction: column; gap: 20px; padding-top: 24px; border-top: 1px solid var(--line); font-size: 15px; line-height: 1.5; color: var(--grey-700); }\n.foot p { margin: 0; }\n.foot b { color: var(--ink); }\n.danger { align-self: flex-start; min-height: 44px; margin: -12px 0 0; padding: 0; border: 0; background: none; font: 600 14px ${FF}; color: var(--grey-700);\n  text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }\n.danger:hover { color: var(--red-500); }\n.danger:focus-visible, .confirm button:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.confirm { display: flex; flex-direction: column; gap: 12px; padding: 20px 20px 22px; background: var(--grey-50); border-left: 4px solid var(--red-500); }\n.confirm h3 { margin: 0; font-size: 18px; font-weight: 800; font-stretch: 112%; line-height: 1.2; text-transform: uppercase; color: var(--ink); }\n.confirm p { margin: 0; font-size: 15px; line-height: 1.5; color: var(--grey-700); }\n.confirm .acts { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 4px; }\n.confirm .acts > * { flex: 0 0 auto; width: auto !important; }\n.l-mobile .confirm .acts > * { width: 100% !important; }\n.l-mobile .confirm { padding: 18px 16px 20px; }\n.l-mobile .confirm .acts { flex-direction: column; }\n`,\n\n  mounted(d2) {\n    FONT();\n    d2.on('.danger', 'click', () => { d2.state.confirm = true; d2.state.deleted = false; });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const R = {\n      fs: refOf(d2.param('formSection')), ff: refOf(d2.param('formField')), tx: refOf(d2.param('taxIdField')), rd: refOf(d2.param('radio')),\n      cb: refOf(d2.param('checkbox')), btn: refOf(d2.param('button')), notice: refOf(d2.param('notice')), icon: refOf(d2.param('iconComponent'))\n    };\n    const b = box(d2);\n    if (!b.__lfSeeded) {\n      b.__lfSeeded = true;\n      const iv = obj(p.values);\n      Object.assign(b.__lfv, {\n        doc: { kind: iv.docKind === 'cnpj' ? 'cnpj' : 'cpf', value: iv.doc || '' },\n        name: iv.name || '', email: iv.email || '', whatsapp: iv.whatsapp || '',\n        optEmail: iv.optEmail == null ? true : truthy(iv.optEmail), optWhatsapp: truthy(iv.optWhatsapp)\n      });\n    }\n    const v = b.__lfv;\n    const gen = d2.state.gen || 0;\n    const errors = d2.state.errors || {};\n    const status = String(p.status || '');\n    const saving = status === 'saving';\n    const saved = status === 'saved' || !!d2.state.saved;\n\n    const clearErr = (key) => {\n      if (!errors[key]) return;\n      const next = Object.assign({}, errors); delete next[key]; d2.state.errors = next;\n    };\n    const onInput = (e) => {\n      if (!e || !e.key) return;\n      if (e.key === 'doc') v.doc = { kind: (e.value && e.value.kind) || v.doc.kind, value: (e.value && e.value.value) || '' };\n      else v[e.key] = e.value;\n      if (d2.state.saved) d2.state.saved = false;\n      clearErr(e.key);\n    };\n\n    const validate = () => {\n      const e = {};\n      const d = docDigits(v.doc.kind, v.doc.value);\n      const label = v.doc.kind === 'cnpj' ? 'CNPJ' : 'CPF';\n      if (!d) e.doc = 'Informe seu ' + label + ': ele vai na nota fiscal.';\n      else if (!(v.doc.kind === 'cnpj' ? validCNPJ(d) : validCPF(d))) e.doc = label + ' inválido. Confere os números.';\n      if (!String(v.name || '').trim()) e.name = 'Informe seu nome completo, como está no documento.';\n      const mail = String(v.email || '').trim();\n      if (!mail) e.email = 'Deixa um e-mail: é por ele que você entra na conta.';\n      else if (!EMAIL.test(mail)) e.email = 'Confere o e-mail: falta o @ ou o domínio.';\n      const w = String(v.whatsapp || '').replace(/\\D/g, '');\n      if (!w) e.whatsapp = 'Informe o WhatsApp para os avisos do pedido.';\n      else if (w.length < 10) e.whatsapp = 'Confere o número: faltam dígitos (com DDD).';\n      return e;\n    };\n    const submit = () => {\n      if (saving) return;\n      const e = validate();\n      d2.state.errors = e;\n      if (Object.keys(e).length) { d2.state.saved = false; return; }\n      emit(d2, 'onSubmit', {\n        docKind: v.doc.kind, doc: v.doc.value, name: String(v.name).trim(), email: String(v.email).trim(), whatsapp: v.whatsapp,\n        optEmail: !!v.optEmail, optWhatsapp: !!v.optWhatsapp\n      });\n      d2.state.saved = true;\n    };\n\n    const notice = R.notice ? d2.render(R.notice, {\n      iconName: 'lock', layout, iconComponent: R.icon,\n      body: p.noticeBody || 'Esses dados são usados para emitir sua nota fiscal. **Não guardamos dados de cartão** — o pagamento é feito com segurança pelo Mercado Pago.'\n    }, { key: 'info' }) : '';\n\n    const dataErr = { doc: errors.doc, name: errors.name, email: errors.email, whatsapp: errors.whatsapp };\n    const data = R.fs ? d2.render(R.fs, {\n      layout, formField: R.ff, taxIdField: R.tx, radio: R.rd, iconComponent: R.icon, version: String(gen),\n      values: { doc: v.doc, name: v.name, email: v.email, whatsapp: v.whatsapp }, errors: dataErr,\n      rows: [\n        { fields: [{ key: 'doc', kind: 'taxid', name: 'documento' }] },\n        { fields: [{ key: 'name', label: 'Nome completo', placeholder: 'Como está no seu documento', autoComplete: 'name' }] },\n        { fields: [\n          { key: 'email', label: 'E-mail', type: 'email', placeholder: 'seuemail@exemplo.com', autoComplete: 'email' },\n          { key: 'whatsapp', label: 'WhatsApp', type: 'tel', mask: 'phone', placeholder: '(00) 00000-0000', hint: 'Para avisos do pedido.', autoComplete: 'tel' }\n        ] }\n      ]\n    }, { key: 'data-' + gen + '-' + hash(dataErr), onInput, onBlur: onInput }) : '';\n\n    const comms = R.fs ? d2.render(R.fs, {\n      layout, checkbox: R.cb, iconComponent: R.icon, title: 'Comunicações', plain: true, divider: true, version: String(gen),\n      values: { optEmail: v.optEmail, optWhatsapp: v.optWhatsapp },\n      note: 'Avisos sobre os seus pedidos (confirmação, pagamento e envio) continuam chegando normalmente.',\n      rows: [{ fields: [\n        { key: 'optEmail', kind: 'checkbox', label: 'Quero receber novidades, lançamentos e ofertas por **e-mail**.' },\n        { key: 'optWhatsapp', kind: 'checkbox', label: 'Quero receber novidades e ofertas por **WhatsApp**.' }\n      ] }]\n    }, { key: 'comms-' + gen, onInput }) : '';\n\n    const okNote = saved && R.notice ? d2.render(R.notice, {\n      tone: 'accent', iconName: 'check', live: true, layout, iconComponent: R.icon,\n      body: p.savedBody || '**Dados salvos.** As alterações já valem para os próximos pedidos e notas fiscais.'\n    }, { key: 'saved' }) : '';\n    const failNote = status === 'error' && R.notice ? d2.render(R.notice, {\n      tone: 'accent', iconName: 'message', live: true, layout, iconComponent: R.icon,\n      body: p.errorBody || '**Não deu pra salvar agora.** Confere sua conexão e tenta de novo — o que você mudou continua aqui.'\n    }, { key: 'fail' }) : '';\n    const btn = R.btn ? d2.render(R.btn, {\n      label: saving ? 'Salvando…' : 'Salvar alterações', variant: 'primary', isDisabled: saving, fullWidth: 'mobile', layout\n    }, { key: 'save-' + (saving ? 's' : 'i'), onClick: submit }) : '';\n\n    let del = '<button type=\"button\" class=\"danger\">Quero excluir minha conta</button>';\n    if (d2.state.deleted) {\n      del = R.notice ? d2.render(R.notice, {\n        tone: 'accent', iconName: 'mail', live: true, layout, iconComponent: R.icon,\n        body: p.deletedBody || '**Pedido de exclusão recebido.** A confirmação chega no e-mail cadastrado, e a gente encerra a conta em seguida.'\n      }, { key: 'deleted' }) : '';\n    } else if (d2.state.confirm) {\n      const yes = R.btn ? d2.render(R.btn, { label: 'Sim, excluir minha conta', variant: 'primary', fullWidth: 'mobile', layout },\n        { key: 'del-yes', onClick: () => { d2.state.confirm = false; d2.state.deleted = true; emit(d2, 'onDelete', { email: String(v.email || '').trim() }); } }) : '';\n      const no = R.btn ? d2.render(R.btn, { label: 'Cancelar', variant: 'outline', fullWidth: 'mobile', layout },\n        { key: 'del-no', onClick: () => { d2.state.confirm = false; } }) : '';\n      del = `<div class=\"confirm\" role=\"alertdialog\" aria-labelledby=\"del-t\" aria-describedby=\"del-d\">\n        <h3 id=\"del-t\">Excluir sua conta?</h3>\n        <p id=\"del-d\">${rich(p.deleteBody || 'Isso apaga seu cadastro, seus endereços e o histórico de pedidos da conta, e **não dá pra desfazer**. As notas fiscais já emitidas continuam guardadas, como a lei exige.')}</p>\n        <div class=\"acts\">${yes}${no}</div>\n      </div>`;\n    }\n\n    return `<div class=\"ad l-${layout}\">\n      ${notice}${data}${comms}\n      <div class=\"save\">${okNote}${failNote}${btn}</div>\n      <div class=\"foot\">\n        <p>${rich(p.passwordText || 'Quer trocar a senha? Saia da conta e use **“Esqueci minha senha”** na tela de login.')}</p>\n        ${del}\n      </div>\n    </div>`;\n  }\n};\n"}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"checkbox":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkbox"}}}},"deleteBody":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"deleteBody"}}}},"deletedBody":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"deletedBody"}}}},"errorBody":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"errorBody"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"formSection":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formSection"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"notice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notice"}}}},"noticeBody":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"noticeBody"}}}},"onDelete":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onDelete"}}}},"onSubmit":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSubmit"}}}},"passwordText":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"passwordText"}}}},"radio":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"radio"}}}},"savedBody":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"savedBody"}}}},"status":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"status"}}}},"taxIdField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"taxIdField"}}}},"values":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"values"}}}}}}}}}},{"_id":"6abd4565edeff59159dc322b","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"AddressCard","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// AddressCard — Loja Lucas Fontana\n// Um endereço salvo: pino + nome (\"Casa\"), quem recebe em negrito, as linhas da rua e o CEP, e as ações separadas por\n// uma linha fina: \"Editar\" · \"Excluir\" (cinza) · \"Definir como principal\".\n// `main: true` é o endereço principal: borda preta de 2px, selo vermelho \"Principal\" e sem \"Definir como principal\".\n// `confirming: true` troca as ações pela confirmação \"Excluir este endereço?\" com \"Excluir\" e \"Cancelar\".\n// `note` mostra uma linha acima das ações (ex.: \"Esse é o principal. Defina outro como principal antes de excluir.\").\n// `lines` (lista de textos) ou os campos soltos `street`, `number`, `complement`, `district`, `city`, `uf`.\n// `addressId` identifica o endereço nos avisos (`id` é nome reservado do bloco).\n// Avisa `onEdit`, `onDelete`, `onMakeMain`, `onConfirmDelete` e `onCancelDelete` com o `addressId`.\n// Não desenha selo, botão nem ícone: usa Badge, Button e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst arr = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst rich = (t) => esc(t).replace(/\\*\\*(.+?)\\*\\*/g, '<b>$1</b>');\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.ac { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-500: #6b6e73; --grey-700: #45474b; --line: #e4e4e2;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: flex; flex-direction: column; gap: 14px; height: 100%; padding: 22px; border: 1px solid var(--line); background: var(--white); }\n.ac.main { border: 2px solid var(--ink); padding: 21px; }\n.top { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 24px; }\nh3 { display: flex; align-items: center; gap: 10px; margin: 0; font-size: 17px; font-weight: 800; line-height: 1.2; color: var(--ink); overflow-wrap: anywhere; }\naddress { margin: 0; font-style: normal; font-size: 15px; line-height: 1.6; color: var(--grey-700); overflow-wrap: anywhere; }\naddress b { color: var(--ink); }\n.foot { display: flex; flex-direction: column; gap: 12px; margin-top: auto; padding-top: 14px; border-top: 1px solid var(--line); }\n.note { margin: 0; font-size: 14px; line-height: 1.45; color: var(--ink); }\n.acts { display: flex; flex-wrap: wrap; gap: 8px 24px; }\n.acts button { padding: 0; min-height: 28px; border: 0; background: none; font: 700 14px/1 ${FF}; color: var(--ink);\n  text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }\n.acts .del { color: var(--grey-500); font-weight: 600; }\n.acts button:hover { color: var(--red-500); }\n.acts button:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.confirm { display: flex; flex-direction: column; gap: 12px; }\n.confirm p { margin: 0; font-size: 15px; font-weight: 700; color: var(--ink); }\n.confirm .btns { display: flex; flex-wrap: wrap; gap: 10px; }\n.confirm .btns > * { flex: 0 0 auto; width: auto !important; }\n.l-mobile .acts { gap: 8px 20px; }\n.l-mobile .acts button { min-height: 36px; }\n`,\n\n  mounted(d2) {\n    FONT();\n    d2.on('[data-act]', 'click', (e, el) => {\n      const a = el.getAttribute('data-act');\n      const id = el.getAttribute('data-id') || (d2.params || {}).addressId;\n      if (a === 'edit') emit(d2, 'onEdit', id);\n      if (a === 'del') emit(d2, 'onDelete', id);\n      if (a === 'main') emit(d2, 'onMakeMain', id);\n    });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const main = truthy(p.main);\n    const id = p.addressId == null ? '' : String(p.addressId);\n    const R = { badge: refOf(d2.param('badge')), btn: refOf(d2.param('button')), icon: refOf(d2.param('iconComponent')) };\n    const lines = arr(p.lines).length ? arr(p.lines) : [\n      [p.street, p.number].filter(Boolean).join(', ') + (p.complement ? ' — ' + p.complement : ''),\n      [p.district, [p.city, p.uf].filter(Boolean).join('/')].filter(Boolean).join(' — ')\n    ].filter((l) => l && l.trim());\n    const pin = R.icon ? d2.render(R.icon, { name: 'pin', size: 20, iconColor: '#0b0b0c' }, { key: 'pin', width: 20, height: 20, style: 'flex:none' }) : '';\n    const badge = main && R.badge ? d2.render(R.badge, { label: 'Principal', tone: 'red', layout: 'desktop' }, { key: 'badge', height: 24, style: 'flex:none;width:auto' }) : '';\n\n    let foot;\n    if (truthy(p.confirming)) {\n      const yes = R.btn ? d2.render(R.btn, { label: 'Excluir', variant: 'primary', size: 'sm', layout }, { key: 'yes', onClick: () => emit(d2, 'onConfirmDelete', id) }) : '';\n      const no = R.btn ? d2.render(R.btn, { label: 'Cancelar', variant: 'outline', size: 'sm', layout }, { key: 'no', onClick: () => emit(d2, 'onCancelDelete', id) }) : '';\n      foot = `<div class=\"confirm\" role=\"alertdialog\" aria-label=\"Excluir este endereço?\"><p>Excluir este endereço?</p><div class=\"btns\">${yes}${no}</div></div>`;\n    } else {\n      foot = `${p.note ? `<p class=\"note\" role=\"status\">${rich(p.note)}</p>` : ''}\n        <div class=\"acts\">\n          <button type=\"button\" data-act=\"edit\" data-id=\"${esc(id)}\">Editar</button>\n          <button type=\"button\" class=\"del\" data-act=\"del\" data-id=\"${esc(id)}\">Excluir</button>\n          ${main ? '' : `<button type=\"button\" data-act=\"main\" data-id=\"${esc(id)}\">Definir como principal</button>`}\n        </div>`;\n    }\n\n    return `<article class=\"ac l-${layout}${main ? ' main' : ''}\">\n      <div class=\"top\"><h3>${pin}${esc(p.label || 'Endereço')}</h3>${badge}</div>\n      <address>${p.recipient ? `<b>${esc(p.recipient)}</b>` : ''}${lines.map((l) => '<br>' + esc(l)).join('')}${p.cep ? '<br>CEP ' + esc(p.cep) : ''}</address>\n      <div class=\"foot\">${foot}</div>\n    </article>`;\n  }\n};"}},"addressId":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"addressId"}}}},"badge":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"badge"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"cep":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"cep"}}}},"city":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"city"}}}},"complement":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"complement"}}}},"confirming":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"confirming"}}}},"district":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"district"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"lines":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"lines"}}}},"main":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"main"}}}},"note":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"note"}}}},"number":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"number"}}}},"onCancelDelete":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCancelDelete"}}}},"onConfirmDelete":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onConfirmDelete"}}}},"onDelete":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onDelete"}}}},"onEdit":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onEdit"}}}},"onMakeMain":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onMakeMain"}}}},"recipient":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"recipient"}}}},"street":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"street"}}}},"uf":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"uf"}}}}}}}}}},{"_id":"6abd45657e17d43be42abc07","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"AddAddressCard","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// AddAddressCard — Loja Lucas Fontana\n// O espaço tracejado que adiciona um endereço novo: um quadrado preto de 44px com \"+\" sobre \"Adicionar endereço\".\n// 180px de altura mínima (120px no mobile); a borda fica preta no hover. `label` troca o texto.\n// Avisa `onClick`. Não desenha o \"+\": usa o Icon pelo parâmetro `iconComponent`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\nbutton { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-400: #8e9095;\n  -webkit-font-smoothing: antialiased; width: 100%; height: 100%; margin: 0;\n  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; min-height: 180px; padding: 24px;\n  border: 1.5px dashed var(--grey-400); background: var(--white); font: 800 13px/1 ${FF}; letter-spacing: .12em; text-transform: uppercase;\n  color: var(--ink); cursor: pointer; }\nbutton:hover { border-color: var(--ink); }\nbutton:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\ni { width: 44px; height: 44px; background: var(--ink); color: var(--white); display: flex; align-items: center; justify-content: center; }\n.l-mobile { min-height: 120px; }\n`,\n  mounted(d2) { FONT(); d2.on('button', 'click', () => emit(d2, 'onClick')); },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const iconRef = refOf(d2.param('iconComponent'));\n    const plus = iconRef ? d2.render(iconRef, { name: 'plus', size: 18, iconColor: '#ffffff' }, { key: 'plus', width: 18, height: 18, style: 'flex:none' }) : '+';\n    return `<button type=\"button\" class=\"l-${layout}\"><i aria-hidden=\"true\">${plus}</i>${esc(p.label || 'Adicionar endereço')}</button>`;\n  }\n};\n"}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onClick":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onClick"}}}}}}}}}},{"_id":"6abd4566b32542bffacf1a2b","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"AddressBook","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// AddressBook — Loja Lucas Fontana\n// O conteúdo do painel \"Endereços\" (entra no AccountLayout por `content`).\n// Lista: os AddressCards em duas colunas no desktop e no tablet (16px) e uma no mobile (12px), o principal primeiro,\n// e o AddAddressCard no fim. Sem endereços: uma linha explicando que o primeiro vira o principal + o AddAddressCard.\n// Formulário (ao adicionar ou editar, no lugar da lista): \"Novo endereço\" / \"Editar endereço\" → nome do endereço em chips\n// (Casa · Trabalho · Outro; \"Outro\" abre um campo curto) → quem recebe → CEP (com \"Não sei meu CEP\") → rua → número +\n// complemento → bairro + cidade → estado → \"Usar como endereço principal\" → \"Salvar endereço\" / \"Cancelar\".\n// Busca de CEP: com os 8 números digitados, consulta o ViaCEP e preenche rua, bairro, cidade e estado; o cursor vai para\n// o número. CEP não encontrado, sem rua (CEP geral da cidade) ou busca fora do ar avisa embaixo do campo do CEP, e dá para\n// preencher tudo à mão.\n// Regras: o primeiro endereço já é o principal; o principal não pode ser excluído enquanto houver outros (\"Defina outro\n// como principal antes de excluir\"); excluir pede confirmação no próprio card.\n// Depois de salvar, trocar o principal ou excluir, mostra um Notice de destaque acima da lista.\n// `addresses: [{ id, label, recipient, cep, street, number, complement, district, city, uf, main }]`.\n// Avisa `onSave`, `onDelete` e `onMakeMain` com { address, addresses }, e `onChange` com a lista a cada mudança.\n// `startMode: \"new\" | \"edit\"` (+ `startEditId`) abre direto no formulário, para pré-visualizar. `cepLookup: false` desliga a busca.\n// Não desenha nada: usa AddressCard, AddAddressCard, FormSection, FormField, ChipGroup, Checkbox, Button, Notice, Badge e Icon.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst arr = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\nconst rich = (t) => esc(t).replace(/\\*\\*(.+?)\\*\\*/g, '<b>$1</b>');\n\nconst LABELS = [{ value: 'Casa', label: 'Casa' }, { value: 'Trabalho', label: 'Trabalho' }, { value: 'outro', label: 'Outro' }];\n// As 27 siglas, a mesma conferência do cadastro (SignupForm)\nconst UFS = 'AC AL AP AM BA CE DF ES GO MA MT MS MG PA PB PR PE PI RJ RN RS RO RR SC SP SE TO'.split(' ');\nconst hash = (v) => { const t = JSON.stringify(v) || ''; let h = 0; for (let i = 0; i < t.length; i++) h = (h * 31 + t.charCodeAt(i)) | 0; return (h >>> 0).toString(36); };\nconst box = (d2) => d2.root || d2;\nconst cepDigits = (v) => String(v || '').replace(/\\D/g, '');\nconst sortMain = (list) => list.slice().sort((a, b) => (b.main ? 1 : 0) - (a.main ? 1 : 0));\n// Procura dentro dos shadow roots aninhados (AddressBook → FormSection → FormField → input)\nconst deepFind = (root, sel) => {\n  if (!root) return null;\n  const hit = root.querySelector ? root.querySelector(sel) : null;\n  if (hit) return hit;\n  const all = root.querySelectorAll ? root.querySelectorAll('*') : [];\n  for (const el of all) { if (el.shadowRoot) { const r = deepFind(el.shadowRoot, sel); if (r) return r; } }\n  return null;\n};\nconst EMPTY = { labelChoice: 'Casa', labelOther: '', recipient: '', cep: '', street: '', number: '', complement: '', district: '', city: '', uf: '', main: false };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.ab { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-500: #6b6e73; --grey-700: #45474b; --line: #e4e4e2;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased; display: flex; flex-direction: column; gap: 24px; width: 100%; background: var(--white); }\n.grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; align-items: stretch; }\n.l-mobile .grid { grid-template-columns: minmax(0, 1fr); gap: 12px; }\n.grid > * { min-width: 0; }\n.empty { margin: 0; font-size: 15px; line-height: 1.5; color: var(--grey-700); }\n.form { display: flex; flex-direction: column; gap: 20px; }\n.form h3 { margin: 0; font-size: 20px; font-weight: 800; font-stretch: 115%; line-height: 1.05; text-transform: uppercase; color: var(--ink); }\n.btns { display: flex; flex-wrap: wrap; gap: 12px; padding-top: 4px; }\n.btns > * { flex: 0 0 auto; width: auto !important; }\n.l-mobile .btns { flex-direction: column; }\n.l-mobile .btns > * { width: 100% !important; }\n`,\n\n  mounted(d2) { FONT(); },\n\n  updated(d2) {\n    const b = box(d2);\n    if (!b.__focus) return;\n    const sel = b.__focus; b.__focus = '';\n    setTimeout(() => { const el = deepFind(d2.root && d2.root.shadowRoot ? d2.root.shadowRoot : d2.root, sel) || deepFind(document, sel); if (el) try { el.focus({ preventScroll: false }); } catch (e) { /* sem foco */ } }, 60);\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const R = {\n      card: refOf(d2.param('addressCard')), add: refOf(d2.param('addAddressCard')), fs: refOf(d2.param('formSection')), ff: refOf(d2.param('formField')),\n      chip: refOf(d2.param('chipGroup')), cb: refOf(d2.param('checkbox')), btn: refOf(d2.param('button')), notice: refOf(d2.param('notice')),\n      badge: refOf(d2.param('badge')), icon: refOf(d2.param('iconComponent'))\n    };\n    const b = box(d2);\n    if (!b.__lfSeeded) {\n      b.__lfSeeded = true;\n      b.__list = sortMain(arr(p.addresses).map(obj).map((a, i) => Object.assign({}, a, { id: String(a.id || 'end-' + (i + 1)), main: truthy(a.main) })));\n      if (b.__list.length && !b.__list.some((a) => a.main)) b.__list[0].main = true;\n      b.__seq = b.__list.length;\n      b.__form = Object.assign({}, EMPTY);\n      if (p.startMode === 'new' || p.startMode === 'edit') {\n        const target = p.startMode === 'edit' ? (b.__list.find((a) => a.id === String(p.startEditId)) || b.__list[0]) : null;\n        b.__startMode = target ? 'edit' : 'new';\n        b.__startId = target ? target.id : '';\n      }\n    }\n    const list = b.__list;\n    const mode = d2.state.mode || b.__startMode || 'list';\n    const editId = d2.state.editId !== undefined ? d2.state.editId : (b.__startId || '');\n    if (mode !== 'list' && !b.__formFor) {\n      // abre o formulário com os dados do endereço (ou vazio)\n      const a = mode === 'edit' ? list.find((x) => x.id === editId) : null;\n      const isStd = a && (a.label === 'Casa' || a.label === 'Trabalho');\n      b.__form = a ? Object.assign({}, EMPTY, a, { labelChoice: isStd ? a.label : 'outro', labelOther: isStd ? '' : (a.label || '') }) : Object.assign({}, EMPTY, { main: list.length === 0 });\n      b.__formFor = mode + ':' + (editId || 'new');\n    }\n    const f = b.__form;\n    const gen = d2.state.gen || 0;\n    const errors = d2.state.errors || {};\n\n    const changed = (action, address) => {\n      const addresses = b.__list.map((a) => Object.assign({}, a));\n      if (action) emit(d2, action, { address, addresses });\n      emit(d2, 'onChange', addresses);\n    };\n    const toList = (flash) => {\n      b.__formFor = ''; b.__startMode = ''; b.__startId = '';\n      d2.state.errors = {}; d2.state.cep = ''; d2.state.confirmId = ''; d2.state.noteId = '';\n      d2.state.flash = flash || ''; d2.state.editId = ''; d2.state.mode = 'list';\n    };\n    const open = (m, id) => {\n      b.__formFor = ''; d2.state.flash = ''; d2.state.confirmId = ''; d2.state.noteId = ''; d2.state.errors = {}; d2.state.cep = '';\n      d2.state.editId = id || ''; d2.state.mode = m; d2.state.gen = gen + 1;\n    };\n\n    // ---------- busca de CEP\n    const lookup = (digits) => {\n      if (p.cepLookup === false || p.cepLookup === 'false' || typeof fetch !== 'function') return;\n      if (b.__lastCep === digits) return;\n      b.__lastCep = digits;\n      d2.state.cep = 'loading';\n      fetch('https://viacep.com.br/ws/' + digits + '/json/')\n        .then((r) => (r.ok ? r.json() : Promise.reject(new Error('http'))))\n        .then((j) => {\n          if (cepDigits(b.__form.cep) !== digits) return;\n          const e = Object.assign({}, d2.state.errors || {});\n          if (!j || j.erro) {\n            e.cep = 'CEP não encontrado. Confere o número ou preenche o endereço à mão.';\n            b.__focus = 'input[name=\"cep\"]';\n            d2.state.errors = e; d2.state.cep = 'notfound'; d2.state.gen = (d2.state.gen || 0) + 1;\n            return;\n          }\n          Object.assign(b.__form, { street: j.logradouro || b.__form.street, district: j.bairro || b.__form.district, city: j.localidade || b.__form.city, uf: j.uf || b.__form.uf });\n          delete e.cep;\n          ['street', 'district', 'city', 'uf'].forEach((x) => { if (b.__form[x]) delete e[x]; });\n          b.__focus = j.logradouro ? 'input[name=\"number\"]' : 'input[name=\"street\"]';\n          d2.state.errors = e;\n          d2.state.cep = j.logradouro ? 'found' : 'city';\n          d2.state.gen = (d2.state.gen || 0) + 1;\n        })\n        .catch(() => {\n          if (cepDigits(b.__form.cep) !== digits) return;\n          b.__focus = 'input[name=\"street\"]';\n          d2.state.cep = 'error'; d2.state.gen = (d2.state.gen || 0) + 1;\n        });\n    };\n\n    const onField = (e) => {\n      if (!e || !e.key) return;\n      f[e.key] = e.value;\n      if (e.key === 'cep') {\n        const d = cepDigits(e.value);\n        if (d.length === 8) lookup(d);\n        else { b.__lastCep = ''; }\n      }\n      if (errors[e.key]) { const n = Object.assign({}, errors); delete n[e.key]; d2.state.errors = n; }\n    };\n\n    const validate = () => {\n      const e = {};\n      if (f.labelChoice === 'outro' && !String(f.labelOther || '').trim()) e.labelOther = 'Dá um nome pra esse endereço (ex.: Casa da mãe).';\n      if (!String(f.recipient || '').trim()) e.recipient = 'Informe o nome de quem vai receber.';\n      if (cepDigits(f.cep).length !== 8) e.cep = 'Confere o CEP: são 8 números.';\n      if (!String(f.street || '').trim()) e.street = 'Informe a rua ou avenida.';\n      if (!String(f.number || '').trim()) e.number = 'Informe o número (ou S/N).';\n      if (!String(f.district || '').trim()) e.district = 'Informe o bairro.';\n      if (!String(f.city || '').trim()) e.city = 'Informe a cidade.';\n      const uf = String(f.uf || '').trim().toUpperCase();\n      if (!uf) e.uf = 'Informe o estado.'; else if (UFS.indexOf(uf) < 0) e.uf = 'Use a sigla do estado (ex.: SP).';\n      return e;\n    };\n    const save = () => {\n      const e = validate();\n      d2.state.errors = e;\n      if (Object.keys(e).length) return;\n      const label = f.labelChoice === 'outro' ? String(f.labelOther).trim() : f.labelChoice;\n      const clean = {\n        label, recipient: String(f.recipient).trim(), cep: String(f.cep).trim(), street: String(f.street).trim(), number: String(f.number).trim(),\n        complement: String(f.complement || '').trim(), district: String(f.district).trim(), city: String(f.city).trim(), uf: String(f.uf).trim().toUpperCase()\n      };\n      let saved;\n      if (mode === 'edit') {\n        const cur = b.__list.find((a) => a.id === editId);\n        saved = Object.assign(cur || {}, clean);\n        if (truthy(f.main) && !saved.main) { b.__list.forEach((a) => { a.main = false; }); saved.main = true; }\n      } else {\n        b.__seq = (b.__seq || 0) + 1;\n        saved = Object.assign({ id: 'end-' + b.__seq + '-' + Date.now().toString(36) }, clean, { main: b.__list.length === 0 || truthy(f.main) });\n        if (saved.main) b.__list.forEach((a) => { a.main = false; });\n        b.__list.push(saved);\n      }\n      b.__list = sortMain(b.__list);\n      changed('onSave', Object.assign({}, saved));\n      toList('saved');\n    };\n\n    // ---------- notice acima da lista\n    const FLASH = {\n      saved: '**Endereço salvo.** Ele já aparece na hora de finalizar a compra.',\n      main: '**Endereço principal atualizado.** É ele que vem preenchido no checkout.',\n      deleted: '**Endereço excluído.**'\n    };\n    const flash = d2.state.flash && R.notice ? d2.render(R.notice, {\n      tone: 'accent', iconName: 'check', live: true, layout, iconComponent: R.icon, body: FLASH[d2.state.flash] || ''\n    }, { key: 'flash-' + d2.state.flash + '-' + gen }) : '';\n\n    if (mode === 'list') {\n      const confirmId = d2.state.confirmId || '';\n      const noteId = d2.state.noteId || '';\n      const cards = b.__list.map((a) => {\n        const cp = {\n          addressId: a.id, label: a.label, main: !!a.main, recipient: a.recipient, cep: a.cep, street: a.street, number: a.number, complement: a.complement,\n          district: a.district, city: a.city, uf: a.uf, lines: arr(a.lines), confirming: confirmId === a.id,\n          note: noteId === a.id ? 'Esse é o seu **principal**. Defina outro como principal antes de excluir.' : '', layout\n        };\n        return R.card ? d2.render(R.card, Object.assign({ badge: R.badge, button: R.btn, iconComponent: R.icon }, cp), {\n          key: 'card-' + hash(cp), style: 'height:auto;min-width:0',\n          onEdit: (id) => open('edit', id),\n          onDelete: (id) => {\n            const t = b.__list.find((x) => x.id === id);\n            d2.state.flash = '';\n            if (t && t.main && b.__list.length > 1) { d2.state.confirmId = ''; d2.state.noteId = id; return; }\n            d2.state.noteId = ''; d2.state.confirmId = id;\n          },\n          onCancelDelete: () => { d2.state.confirmId = ''; },\n          onConfirmDelete: (id) => {\n            const t = b.__list.find((x) => x.id === id);\n            b.__list = b.__list.filter((x) => x.id !== id);\n            changed('onDelete', t ? Object.assign({}, t) : { id });\n            toList('deleted');\n          },\n          onMakeMain: (id) => {\n            b.__list.forEach((x) => { x.main = x.id === id; });\n            b.__list = sortMain(b.__list);\n            const t = b.__list.find((x) => x.id === id);\n            changed('onMakeMain', t ? Object.assign({}, t) : { id });\n            toList('main');\n          }\n        }) : '';\n      }).join('');\n      const add = R.add ? d2.render(R.add, { layout, iconComponent: R.icon, label: 'Adicionar endereço' }, { key: 'add', style: 'height:auto;min-width:0', onClick: () => open('new') }) : '';\n      const empty = b.__list.length ? '' : `<p class=\"empty\">${rich(p.emptyText || 'Você ainda não salvou nenhum endereço. O primeiro que você cadastrar vira o **principal** e já vem preenchido no checkout.')}</p>`;\n      return `<div class=\"ab l-${layout}\">${flash}${empty}<div class=\"grid\">${cards}${add}</div></div>`;\n    }\n\n    // ---------- formulário\n    const k = (name, keys) => name + '-' + gen + '-' + hash((keys || []).map((x) => errors[x] || ''));\n    const chips = R.chip ? d2.render(R.chip, {\n      label: 'Nome do endereço', options: LABELS, value: f.labelChoice, name: 'apelido', layout\n    }, { key: 'chips-' + gen, onChange: (v) => { f.labelChoice = v; if (errors.labelOther) { const n = Object.assign({}, errors); delete n.labelOther; d2.state.errors = n; } d2.state.labelChoice = v; } }) : '';\n    const other = (d2.state.labelChoice || f.labelChoice) === 'outro' && R.ff ? d2.render(R.ff, {\n      label: 'Como você quer chamar esse endereço?', name: 'labelOther', placeholder: 'Ex.: Casa da mãe, Oficina', maxLength: 30,\n      value: f.labelOther, error: errors.labelOther || '', layout, iconComponent: R.icon\n    }, { key: k('other', ['labelOther']), onInput: (v) => onField({ key: 'labelOther', value: v }) }) : '';\n\n    const cepState = d2.state.cep || '';\n    const cepHint = cepState === 'found' ? 'Endereço encontrado. Confere e completa com o número.'\n      : cepState === 'city' ? 'Esse CEP vale para a cidade toda: preenche a rua e o bairro.'\n      : cepState === 'error' ? 'Não deu pra buscar o CEP agora. Preenche o endereço à mão.' : '';\n    const fieldsKeys = ['recipient', 'cep', 'street', 'number', 'complement', 'district', 'city', 'uf'];\n    const fs = R.fs ? d2.render(R.fs, {\n      layout, formField: R.ff, iconComponent: R.icon, version: String(gen),\n      values: fieldsKeys.reduce((o, x) => { o[x] = f[x] || ''; return o; }, {}),\n      errors: fieldsKeys.reduce((o, x) => { if (errors[x]) o[x] = errors[x]; return o; }, {}),\n      rows: [\n        { fields: [{ key: 'recipient', label: 'Nome de quem recebe', placeholder: 'Quem vai estar lá pra receber', autoComplete: 'name' }] },\n        { fields: [{ key: 'cep', label: 'CEP', mask: 'cep', placeholder: '00000-000', autoComplete: 'postal-code', hint: cepHint,\n          linkLabel: 'Não sei meu CEP', linkHref: 'https://buscacepinter.correios.com.br/app/endereco/index.php' }, { kind: 'spacer' }] },\n        { fields: [{ key: 'street', label: 'Rua / avenida', autoComplete: 'address-line1' }] },\n        { keep: true, fields: [{ key: 'number', label: 'Número', placeholder: 'Ou S/N' }, { key: 'complement', label: 'Complemento', optional: true, placeholder: 'Apto, bloco, referência', autoComplete: 'address-line2' }] },\n        { fields: [{ key: 'district', label: 'Bairro' }, { key: 'city', label: 'Cidade', autoComplete: 'address-level2' }] },\n        { fields: [{ key: 'uf', label: 'Estado', mask: 'uf', placeholder: 'UF', maxLength: 2, autoComplete: 'address-level1' }, { kind: 'spacer' }] }\n      ]\n    }, { key: 'fs-' + gen + '-' + hash(errors), onInput: onField, onBlur: onField }) : '';\n    const editingMain = mode === 'edit' && (list.find((a) => a.id === editId) || {}).main;\n    const first = mode === 'new' && list.length === 0;\n    const mainCb = editingMain || !R.cb ? '' : d2.render(R.cb, {\n      name: 'principal', checked: first || truthy(f.main), disabled: first, top: true, layout, iconComponent: R.icon,\n      label: first ? 'Usar como endereço principal ((o primeiro endereço já vira o principal))' : 'Usar como endereço principal'\n    }, { key: 'main-' + gen + (first ? '-f' : ''), onChange: (v) => { f.main = !!v; } });\n\n    const saveBtn = R.btn ? d2.render(R.btn, { label: 'Salvar endereço', variant: 'primary', layout }, { key: 'save', onClick: save }) : '';\n    const cancel = R.btn ? d2.render(R.btn, { label: 'Cancelar', variant: 'outline', layout }, { key: 'cancel', onClick: () => toList('') }) : '';\n\n    return `<div class=\"ab l-${layout}\"><div class=\"form\">\n      <h3>${mode === 'edit' ? 'Editar endereço' : 'Novo endereço'}</h3>\n      ${chips}${other}${fs}${mainCb}\n      <div class=\"btns\">${saveBtn}${cancel}</div>\n    </div></div>`;\n  }\n};\n"}},"addAddressCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"addAddressCard"}}}},"addressCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"addressCard"}}}},"addresses":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"addresses"}}}},"badge":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"badge"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"cepLookup":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"cepLookup"}}}},"checkbox":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkbox"}}}},"chipGroup":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"chipGroup"}}}},"emptyText":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"emptyText"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"formSection":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formSection"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"notice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notice"}}}},"onChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChange"}}}},"onDelete":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onDelete"}}}},"onMakeMain":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onMakeMain"}}}},"onSave":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSave"}}}},"startEditId":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"startEditId"}}}},"startMode":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"startMode"}}}}}}}}}},{"_id":"6abd5edc8dad80a86684540b","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"BackLink","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// BackLink — Loja Lucas Fontana\n// O link \"← Voltar para …\" em caixa alta, acima do título de uma página de detalhe (\"← Voltar para meus pedidos\").\n// 13px em negrito espaçado, seta de 16px, 36px de área de toque; fica vermelho no hover.\n// `label`, `href`. Sem `href`, avisa `onClick`. Não desenha a seta: usa o Icon pelo parâmetro `iconComponent`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\n\nexport default {\n  css: `\n:host { display: block; }\n* { box-sizing: border-box; }\na { --red-500: #c8102e; --ink: #0b0b0c; font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  display: inline-flex; align-items: center; gap: 10px; min-height: 36px; font-size: 13px; font-weight: 800; letter-spacing: .12em;\n  line-height: 1; text-transform: uppercase; color: var(--ink); text-decoration: none; cursor: pointer; }\na:hover { color: var(--red-500); }\na:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.ar { display: flex; flex: none; }\n`,\n  mounted(d2) {\n    FONT();\n    d2.on('a', 'click', (e, el) => { if (!el.getAttribute('data-href')) e.preventDefault(); emit(d2, 'onClick', el.getAttribute('data-href') || ''); });\n  },\n  render(d2) {\n    const p = d2.params || {};\n    const iconRef = refOf(d2.param('iconComponent'));\n    const ar = iconRef ? d2.render(iconRef, { name: 'arrow-left', size: 16, iconColor: 'currentColor' }, { key: 'ar', width: 16, height: 16, style: 'flex:none' }) : '←';\n    return `<a href=\"${esc(p.href || '#')}\" data-href=\"${esc(p.href || '')}\"><span class=\"ar\" aria-hidden=\"true\">${ar}</span>${esc(p.label || 'Voltar')}</a>`;\n  }\n};\n"}},"href":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"href"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onClick":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onClick"}}}}}}}}}},{"_id":"6abd5edd5d6e585d083bb06b","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"OrderProgress","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// OrderProgress — Loja Lucas Fontana\n// A linha do tempo do pedido: Pedido confirmado → Pagamento aprovado → Enviado → Entregue.\n// Etapa feita (`done`): quadrado preto de 32px com check, ligado à próxima por uma linha preta.\n// Etapa atual (`current`): quadrado vermelho sólido. Etapa que falta (`pending`): quadrado vazio\n// com borda cinza e texto cinza. Na horizontal no desktop e no tablet; na vertical no mobile.\n// `steps: [{ label, date, state }]`. Sem `steps`, mostra as 4 etapas do pedido como pendentes.\n// Não desenha o check: usa o Icon pelo parâmetro `iconComponent`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst arr = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\n\nconst DEFAULT = [{ label: 'Pedido confirmado' }, { label: 'Pagamento aprovado' }, { label: 'Enviado' }, { label: 'Entregue' }];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\nol { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-500: #6b6e73; --grey-700: #45474b; --line: #e4e4e2; --line-strong: #d9d9d6;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased;\n  list-style: none; margin: 0; padding: 32px 24px 28px; border: 1px solid var(--line); background: var(--white);\n  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }\nli { position: relative; display: flex; flex-direction: column; gap: 12px; min-width: 0; padding-right: 12px; }\n.mark { position: relative; z-index: 1; width: 32px; height: 32px; border: 2px solid var(--line-strong); background: var(--white); color: var(--white);\n  display: flex; align-items: center; justify-content: center; flex: none; }\n.done .mark { background: var(--ink); border-color: var(--ink); }\n.current .mark { background: var(--red-500); border-color: var(--red-500); }\nli::before { content: ''; position: absolute; top: 15px; left: 44px; right: 12px; height: 2px; background: var(--line); }\nli:last-child::before { display: none; }\n.done::before { background: var(--ink); }\nb { display: block; font-size: 15px; font-weight: 700; line-height: 1.3; color: var(--ink); }\nspan.d { display: block; margin-top: 2px; font-size: 13px; line-height: 1.4; color: var(--grey-700); }\n.pending b, .pending span.d { color: var(--grey-500); }\n.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }\n.l-mobile { grid-auto-flow: row; padding: 20px; }\n.l-mobile li { flex-direction: row; gap: 14px; padding: 0 0 20px; }\n.l-mobile li:last-child { padding-bottom: 0; }\n.l-mobile li::before { top: 32px; bottom: 0; left: 15px; right: auto; width: 2px; height: auto; }\n`,\n  mounted() { FONT(); },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const iconRef = refOf(d2.param('iconComponent'));\n    const steps = arr(p.steps).length ? arr(p.steps).map(obj) : DEFAULT;\n    const NAME = { done: 'feito', current: 'etapa atual', pending: 'ainda não' };\n    const items = steps.map((s, i) => {\n      const st = ['done', 'current', 'pending'].indexOf(s.state) >= 0 ? s.state : 'pending';\n      const ck = st === 'done' && iconRef ? d2.render(iconRef, { name: 'check', size: 16, iconColor: '#ffffff' }, { key: 'ck-' + i, width: 16, height: 16, style: 'flex:none' }) : '';\n      return `<li class=\"${st}\"${st === 'current' ? ' aria-current=\"step\"' : ''}>\n        <span class=\"mark\" aria-hidden=\"true\">${ck}</span>\n        <div><b>${esc(s.label)}<span class=\"sr\"> — ${NAME[st]}</span></b>${s.date ? `<span class=\"d\">${esc(s.date)}</span>` : ''}</div>\n      </li>`;\n    }).join('');\n    return `<ol class=\"l-${layout}\" aria-label=\"${esc(p.label || 'Andamento do pedido')}\">${items}</ol>`;\n  }\n};\n"}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"steps":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"steps"}}}}}}}}}},{"_id":"6abd5edd5d6e585d083bb070","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"OrderSummary","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// OrderSummary — Loja Lucas Fontana\n// O resumo do pedido em grey-50: \"RESUMO DO PEDIDO\", as linhas (subtotal, frete), o total em 18px negrito com linha acima,\n// e blocos com título (Pagamento, Endereço de entrega, Forma de envio), cada um separado por uma linha.\n// `rows: [[rótulo, valor]]`, `total`, `sections: [{ title, lines, mutedFrom }]` — `mutedFrom` deixa em cinza as linhas a\n// partir daquela posição (ex.: \"Processado pelo Mercado Pago\"). Trechos entre **asteriscos duplos** saem em negrito.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst arr = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\nconst rich = (t) => esc(t).replace(/\\*\\*(.+?)\\*\\*/g, '<b>$1</b>');\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\nsection { --ink: #0b0b0c; --grey-50: #f5f5f3; --grey-700: #45474b; --line-strong: #d9d9d6;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased; display: flex; flex-direction: column; width: 100%; padding: 24px; background: var(--grey-50); }\nh2, h3 { margin: 0; font-size: 13px; font-weight: 800; letter-spacing: .2em; text-transform: uppercase; color: var(--ink); }\nh2 { margin-bottom: 16px; }\n.row { display: flex; justify-content: space-between; gap: 12px; padding: 3px 0; font-size: 15px; line-height: 1.45; color: var(--grey-700); }\n.row span:last-child { white-space: nowrap; }\n.total { margin-top: 10px; padding: 14px 0 20px; border-top: 1px solid var(--line-strong); font-size: 18px; font-weight: 800; color: var(--ink); }\n.sec { display: flex; flex-direction: column; gap: 8px; padding: 18px 0; border-top: 1px solid var(--line-strong); }\n.sec:last-child { padding-bottom: 0; }\n.sec h3 { font-size: 11px; margin-bottom: 4px; }\n.sec p { margin: 0; font-size: 15px; line-height: 1.55; color: var(--ink); overflow-wrap: anywhere; }\n.sec p.muted { color: var(--grey-700); }\n.l-mobile, .l-tablet { padding: 20px; }\n`,\n  mounted() { FONT(); },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const rows = arr(p.rows).map((r) => (Array.isArray(r) ? r : [obj(r).label, obj(r).value]));\n    const secs = arr(p.sections).map(obj);\n    return `<section class=\"l-${layout}\" aria-label=\"${esc(p.title || 'Resumo do pedido')}\">\n      <h2>${esc(p.title || 'Resumo do pedido')}</h2>\n      ${rows.map((r) => `<div class=\"row\"><span>${esc(r[0])}</span><span>${esc(r[1])}</span></div>`).join('')}\n      ${p.total ? `<div class=\"row total\"><span>Total</span><span>${esc(p.total)}</span></div>` : ''}\n      ${secs.map((s) => {\n        const from = s.mutedFrom == null || s.mutedFrom === '' ? -1 : Number(s.mutedFrom);\n        return `<div class=\"sec\"><h3>${esc(s.title)}</h3>${arr(s.lines).map((l, k) => `<p${from >= 0 && k >= from ? ' class=\"muted\"' : ''}>${rich(l)}</p>`).join('')}</div>`;\n      }).join('')}\n    </section>`;\n  }\n};\n"}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"rows":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"rows"}}}},"sections":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"sections"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}},"total":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"total"}}}}}}}}}},{"_id":"6abd5f228b5295df285a9df2","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"ShipmentCard","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// ShipmentCard — Loja Lucas Fontana\n// Um pacote do pedido: kicker vermelho (\"Envio 1 de 2\", com o selo vermelho \"Parceiro\" nos envios da BPower), quem envia\n// (\"Enviado pela Loja Lucas Fontana\" / \"Enviado pelo parceiro BPower Motorsport\"), o status, a caixa cinza de rastreio\n// (transportadora, código, botão de copiar e o botão preto \"Rastrear →\") e os itens (foto de 88px — 72px no mobile —,\n// nome, variação, quantidade e preço).\n// Sem código de rastreio, a caixa mostra \"O código de rastreio aparece aqui quando o pedido for enviado.\" (troca em\n// `trackingPendingText`) e não mostra o \"Rastrear\".\n// Copiar: o botão vira um check por 2 segundos e avisa \"Código copiado\" para leitor de tela.\n// `title`, `partner` (true ou o texto do selo), `from`, `status`, `statusLabel`, `tracking: { carrier, code, href }`,\n// `items: [{ name, meta: [..], qty, price, image }]`. Avisa `onCopy` e, quando o rastreio não tem link, `onTrack`.\n// Não desenha selo, botão nem ícone: usa StatusBadge, Badge, Button e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst arr = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\nsection { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-50: #f5f5f3; --grey-100: #ececea; --grey-500: #6b6e73; --grey-700: #45474b;\n  --line: #e4e4e2; --line-strong: #d9d9d6;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased; display: flex; flex-direction: column; gap: 20px; width: 100%; padding: 24px;\n  border: 1px solid var(--line); background: var(--white); }\n.head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }\n.kicker { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; font-size: 12px; font-weight: 800; letter-spacing: .24em; line-height: 1.3;\n  text-transform: uppercase; color: var(--red-500); }\n.from { margin: 0; font-size: 17px; font-weight: 700; line-height: 1.3; color: var(--ink); }\n.bw { display: flex; align-items: center; height: 28px; flex: none; }\n.track { display: flex; align-items: center; gap: 12px; padding: 16px 16px 16px 20px; background: var(--grey-50); }\n.code { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }\n.code small { font-size: 13px; color: var(--grey-500); }\n.code b { font-size: 17px; font-weight: 800; letter-spacing: .06em; color: var(--ink); overflow-wrap: anywhere; }\n.copy { width: 44px; height: 44px; flex: none; margin: 0; padding: 0; border: 1px solid var(--line-strong); background: var(--white); color: var(--ink);\n  display: flex; align-items: center; justify-content: center; cursor: pointer; }\n.copy:hover { border-color: var(--ink); }\n.copy:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.copy.ok { background: var(--ink); border-color: var(--ink); }\n.trk { flex: none; }\n.pending { display: flex; align-items: center; gap: 12px; padding: 16px 20px; background: var(--grey-50); font-size: 15px; line-height: 1.45; color: var(--grey-700); }\n.pending i { display: flex; flex: none; color: var(--ink); }\n.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }\nul { list-style: none; margin: 0; padding: 0; }\nli { display: grid; grid-template-columns: 88px minmax(0, 1fr) auto; gap: 16px; align-items: start; padding: 20px 0; border-top: 1px solid var(--line); }\nli:last-child { padding-bottom: 0; }\n.img { width: 88px; height: 88px; background: var(--grey-100); display: flex; align-items: center; justify-content: center; overflow: hidden; }\n.img img { width: 100%; height: 100%; object-fit: cover; }\n.ph { font-size: 9px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--grey-500); }\n.name { margin: 0 0 6px; font-size: 16px; font-weight: 700; line-height: 1.3; color: var(--ink); }\n.meta { margin: 0; font-size: 14px; line-height: 1.5; color: var(--grey-700); }\n.price { font-size: 16px; font-weight: 800; color: var(--ink); white-space: nowrap; }\n.l-mobile { padding: 20px; gap: 16px; }\n.l-mobile .head { flex-direction: column; gap: 12px; }\n.l-mobile .track { flex-wrap: wrap; padding: 16px; }\n.l-mobile .code { flex-basis: 100%; }\n.l-mobile .trk { flex: 1; }\n.l-mobile li { grid-template-columns: 72px minmax(0, 1fr) auto; gap: 12px; }\n.l-mobile .img { width: 72px; height: 72px; }\n.l-mobile .name { font-size: 15px; }\n`,\n\n  mounted(d2) {\n    FONT();\n    d2.on('.copy', 'click', (e, el) => {\n      const code = el.getAttribute('data-code') || '';\n      try { if (navigator.clipboard) navigator.clipboard.writeText(code); } catch (err) { /* sem área de transferência */ }\n      emit(d2, 'onCopy', code);\n      d2.state.copied = true;\n      clearTimeout(d2.root && d2.root.__lfT);\n      const t = setTimeout(() => { d2.state.copied = false; }, 2000);\n      if (d2.root) d2.root.__lfT = t;\n    });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const R = { st: refOf(d2.param('statusBadge')), badge: refOf(d2.param('badge')), btn: refOf(d2.param('button')), icon: refOf(d2.param('iconComponent')) };\n    const t = obj(p.tracking);\n    const copied = !!d2.state.copied;\n    const partner = p.partner === true || p.partner === 'true' ? 'Parceiro' : (typeof p.partner === 'string' && p.partner && p.partner !== 'false' ? p.partner : '');\n    const ic = (name, size, color, key) => R.icon ? d2.render(R.icon, { name, size, iconColor: color }, { key, width: size, height: size, style: 'flex:none' }) : '';\n    const badge = partner && R.badge ? d2.render(R.badge, { label: partner, tone: 'red', layout: 'desktop' }, { key: 'pb', height: 22, style: 'flex:none;width:auto' }) : '';\n    const status = p.status && R.st ? `<div class=\"bw\">${d2.render(R.st, { status: p.status, label: p.statusLabel || '' }, { key: 'st-' + p.status + (p.statusLabel || ''), style: 'display:inline-flex;flex:none' })}</div>` : '';\n\n    let track = '';\n    if (t.code) {\n      const btn = R.btn ? `<span class=\"trk\">${d2.render(R.btn, { label: 'Rastrear', variant: 'primary', size: 'sm', arrow: true, href: t.href || '', newTab: !!t.href, fullWidth: layout === 'mobile' ? 'always' : '', layout },\n        { key: 'trk-' + (t.href ? 'l' : 'b'), onClick: () => emit(d2, 'onTrack', t.code) })}</span>` : '';\n      track = `<div class=\"track\">\n        <div class=\"code\"><small>Código de rastreio${t.carrier ? ' · ' + esc(t.carrier) : ''}</small><b>${esc(t.code)}</b></div>\n        <button type=\"button\" class=\"copy${copied ? ' ok' : ''}\" data-code=\"${esc(t.code)}\" aria-label=\"Copiar código de rastreio\">${copied ? ic('check', 18, '#ffffff', 'ok') : ic('copy', 18, '#0b0b0c', 'cp')}</button>\n        <span class=\"sr\" aria-live=\"polite\">${copied ? 'Código copiado' : ''}</span>\n        ${btn}\n      </div>`;\n    } else if (p.tracking !== false && p.tracking !== 'false') {\n      track = `<div class=\"pending\"><i aria-hidden=\"true\">${ic('truck', 20, '#0b0b0c', 'tr')}</i><span>${esc(p.trackingPendingText || 'O código de rastreio aparece aqui quando o pedido for enviado.')}</span></div>`;\n    }\n\n    const items = arr(p.items).map(obj);\n    const list = items.length ? `<ul>${items.map((it) => `<li>\n        <span class=\"img\">${it.image ? `<img src=\"${esc(it.image)}\" alt=\"\">` : '<span class=\"ph\">Foto</span>'}</span>\n        <div><p class=\"name\">${esc(it.name)}</p>${arr(it.meta).map((m) => `<p class=\"meta\">${esc(m)}</p>`).join('')}${it.qty != null && it.qty !== '' ? `<p class=\"meta\">Qtd.: ${esc(it.qty)}</p>` : ''}</div>\n        <span class=\"price\">${esc(it.price)}</span>\n      </li>`).join('')}</ul>` : '';\n\n    return `<section class=\"l-${layout}\" aria-label=\"${esc(p.title || 'Envio')}\">\n      <div class=\"head\"><div>${p.title || badge ? `<span class=\"kicker\">${esc(p.title || '')}${badge}</span>` : ''}${p.from ? `<p class=\"from\">${esc(p.from)}</p>` : ''}</div>${status}</div>\n      ${track}${list}\n    </section>`;\n  }\n};\n"}},"badge":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"badge"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"from":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"from"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"items":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"items"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onCopy":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCopy"}}}},"onTrack":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onTrack"}}}},"partner":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"partner"}}}},"status":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"status"}}}},"statusBadge":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"statusBadge"}}}},"statusLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"statusLabel"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}},"tracking":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"tracking"}}}},"trackingPendingText":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"trackingPendingText"}}}}}}}}}},{"_id":"6abd5f247830b24ef504f6ae","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"OrderLayout","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// OrderLayout — Loja Lucas Fontana\n// O corpo da página de um pedido: breadcrumb, \"← Voltar para meus pedidos\", \"Pedido #1045\" (44/36/28px) com a data e o\n// selo de status, o andamento (OrderProgress) e, embaixo, os envios (um ShipmentCard por remetente) ao lado de uma coluna\n// fixa (sticky) de 380px com o resumo (OrderSummary) e o HelpCard. No tablet e no mobile a coluna desce para baixo dos envios.\n// Avisos por status, logo abaixo do título:\n// `pending` → \"Falta pagar.\" com o botão \"Pagar com Pix\" (`payHref`; sem link, avisa `onPay`), prazo em `payUntil`.\n// `canceled`, `refused`, `refunded` → o aviso do que aconteceu, e o andamento some (não faz sentido nesses casos).\n// `alert: { body, iconName }` troca o texto do aviso; `showProgress: true` mantém o andamento mesmo cancelado.\n// `number`, `date`, `status`, `statusLabel`, `crumbs`, `back: { label, href }`, `steps` (do OrderProgress),\n// `shipments` (parâmetros de cada ShipmentCard), `summary` (parâmetros do OrderSummary), `help` (parâmetros do HelpCard).\n// Repassa `onBack`, `onCopy`, `onTrack`, `onSac` e `onPay`.\n// Não desenha nada: usa Breadcrumb, BackLink, StatusBadge, OrderProgress, ShipmentCard, OrderSummary, HelpCard, Notice,\n// Button, Badge e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst FONT = () => {\n  if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n    const l = document.createElement('link');\n    l.id = 'lf-archivo-font';\n    l.rel = 'stylesheet';\n    l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n    document.head.appendChild(l);\n  }\n};\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst arr = (v) => {\n  if (Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } }\n  return [];\n};\nconst obj = (v) => {\n  if (v && typeof v === 'object' && !Array.isArray(v)) return v;\n  if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } }\n  return {};\n};\nconst hash = (v) => { const t = JSON.stringify(v) || ''; let h = 0; for (let i = 0; i < t.length; i++) h = (h * 31 + t.charCodeAt(i)) | 0; return (h >>> 0).toString(36); };\n\nconst PAD = { desktop: '32px 96px 120px', tablet: '28px 40px 88px', mobile: '20px 20px 64px' };\nconst CRUMB_H = { desktop: 24, tablet: 24, mobile: 30 };\nconst ALERTS = {\n  canceled: { iconName: 'close', body: '**Pedido cancelado.** Se já tinha pago, o valor volta pelo mesmo meio de pagamento. Qualquer dúvida, fala com o SAC informando o número do pedido.' },\n  refused: { iconName: 'close', body: '**Pagamento recusado ou expirado.** O pedido não foi confirmado e nada foi cobrado. Se ainda quiser os produtos, é só fazer um pedido novo.' },\n  refunded: { iconName: 'swap', body: '**Pagamento estornado.** O valor volta pelo mesmo meio de pagamento: no Pix, na hora; no cartão, no prazo do seu banco.' }\n};\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.ol { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-700: #45474b;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased; width: 100%; background: var(--white); color: var(--ink); }\n.in { display: flex; flex-direction: column; gap: 24px; }\n.top { display: flex; flex-direction: column; gap: 12px; }\n.head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; flex-wrap: wrap; }\nh1 { margin: 0 0 8px; font-size: 44px; font-weight: 800; font-stretch: 115%; line-height: 1; letter-spacing: -.01em; text-transform: uppercase; }\n.date { margin: 0; font-size: 15px; color: var(--grey-700); }\n.bw { display: flex; align-items: center; height: 28px; flex: none; margin-bottom: 2px; }\n.alert { display: flex; flex-direction: column; gap: 16px; align-items: flex-start; }\n.grid { display: grid; grid-template-columns: minmax(0, 1fr) 380px; gap: 32px; align-items: start; }\n.main { display: flex; flex-direction: column; gap: 20px; min-width: 0; }\n.aside { display: flex; flex-direction: column; gap: 16px; position: sticky; top: 24px; min-width: 0; }\n.l-tablet h1 { font-size: 36px; }\n.l-tablet .grid, .l-mobile .grid { grid-template-columns: minmax(0, 1fr); gap: 20px; }\n.l-tablet .aside, .l-mobile .aside { position: static; }\n.l-mobile .in { gap: 16px; }\n.l-mobile h1 { font-size: 28px; font-stretch: 112%; letter-spacing: 0; }\n.l-mobile .date { font-size: 14px; }\n.l-mobile .alert { align-items: stretch; }\n`,\n\n  mounted() { FONT(); },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const R = {\n      bc: refOf(d2.param('breadcrumb')), back: refOf(d2.param('backLink')), st: refOf(d2.param('statusBadge')), prog: refOf(d2.param('orderProgress')),\n      ship: refOf(d2.param('shipmentCard')), sum: refOf(d2.param('orderSummary')), help: refOf(d2.param('helpCard')), notice: refOf(d2.param('notice')),\n      btn: refOf(d2.param('button')), badge: refOf(d2.param('badge')), icon: refOf(d2.param('iconComponent'))\n    };\n    const number = p.number || '0000';\n    const status = p.status || '';\n    const crumbs = arr(p.crumbs).length ? arr(p.crumbs) : [{ label: 'Início', href: '/' }, { label: 'Minha conta', href: '/minha-conta/pedidos' }, { label: 'Meus pedidos', href: '/minha-conta/pedidos' }, { label: 'Pedido #' + number }];\n    const back = Object.assign({ label: 'Voltar para meus pedidos', href: '/minha-conta/pedidos' }, obj(p.back));\n\n    const crumb = R.bc ? `<div style=\"height:${CRUMB_H[layout]}px\">${d2.render(R.bc, { items: crumbs, layout }, { key: 'bc' })}</div>` : '';\n    const backLink = R.back ? d2.render(R.back, { label: back.label, href: back.href, iconComponent: R.icon }, { key: 'back', height: 36, onClick: (h) => emit(d2, 'onBack', h) }) : '';\n    const badge = status && R.st ? `<div class=\"bw\">${d2.render(R.st, { status, label: p.statusLabel || '' }, { key: 'st-' + status + (p.statusLabel || ''), style: 'display:inline-flex;flex:none' })}</div>` : '';\n\n    // aviso por status\n    const al = obj(p.alert);\n    let alert = '';\n    if (status === 'pending' && R.notice) {\n      const note = d2.render(R.notice, {\n        tone: 'accent', iconName: al.iconName || 'card', live: true, layout, iconComponent: R.icon,\n        body: al.body || ('**Falta pagar.** O pedido fica reservado até ' + (p.payUntil || '[prazo]') + '. Assim que o pagamento for confirmado, a gente começa a separar.')\n      }, { key: 'al-pending-' + hash(al) + (p.payUntil || ''), style: 'height:auto;width:100%' });\n      const pay = R.btn ? d2.render(R.btn, { label: 'Pagar com Pix', variant: 'primary', arrow: true, href: p.payHref || '', fullWidth: 'mobile', layout },\n        { key: 'pay-' + (p.payHref ? 'l' : 'b'), onClick: () => emit(d2, 'onPay', number) }) : '';\n      alert = `<div class=\"alert\">${note}${pay}</div>`;\n    } else if (ALERTS[status] && R.notice) {\n      const a = ALERTS[status];\n      alert = `<div class=\"alert\">${d2.render(R.notice, { tone: 'accent', iconName: al.iconName || a.iconName, live: true, layout, iconComponent: R.icon, body: al.body || a.body },\n        { key: 'al-' + status + '-' + hash(al), style: 'height:auto;width:100%' })}</div>`;\n    }\n    const hideProg = !!ALERTS[status] && !(p.showProgress === true || p.showProgress === 'true');\n    const prog = !hideProg && R.prog ? d2.render(R.prog, { steps: arr(p.steps), layout, iconComponent: R.icon }, { key: 'prog-' + hash(arr(p.steps)), style: 'height:auto' }) : '';\n\n    const ships = arr(p.shipments).map(obj).map((s, i) => R.ship ? d2.render(R.ship, Object.assign({}, s, {\n      layout, statusBadge: R.st, badge: R.badge, button: R.btn, iconComponent: R.icon\n    }), { key: 'ship-' + i + '-' + hash(s), style: 'height:auto', onCopy: (c) => emit(d2, 'onCopy', c), onTrack: (c) => emit(d2, 'onTrack', c) }) : '').join('');\n    const sum = R.sum ? d2.render(R.sum, Object.assign({}, obj(p.summary), { layout }), { key: 'sum-' + hash(obj(p.summary)), style: 'height:auto' }) : '';\n    const help = R.help ? d2.render(R.help, Object.assign({}, obj(p.help), { layout, button: R.btn }), { key: 'help-' + hash(obj(p.help)), style: 'height:auto', onCta: (h) => emit(d2, 'onSac', h) }) : '';\n\n    return `<div class=\"ol l-${layout}\"><div class=\"in\" style=\"padding:${PAD[layout]}\">\n      <div class=\"top\">${crumb}${backLink}</div>\n      <div class=\"head\"><div><h1>Pedido #${esc(number)}</h1>${p.date ? `<p class=\"date\">${esc(p.date)}</p>` : ''}</div>${badge}</div>\n      ${alert}${prog}\n      <div class=\"grid\"><div class=\"main\">${ships}</div><aside class=\"aside\">${sum}${help}</aside></div>\n    </div></div>`;\n  }\n};\n"}},"alert":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"alert"}}}},"back":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"back"}}}},"backLink":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"backLink"}}}},"badge":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"badge"}}}},"breadcrumb":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"breadcrumb"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"crumbs":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"crumbs"}}}},"date":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"date"}}}},"help":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"help"}}}},"helpCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"helpCard"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"notice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notice"}}}},"number":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"number"}}}},"onBack":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onBack"}}}},"onCopy":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCopy"}}}},"onPay":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onPay"}}}},"onSac":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSac"}}}},"onTrack":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onTrack"}}}},"orderProgress":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"orderProgress"}}}},"orderSummary":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"orderSummary"}}}},"payHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"payHref"}}}},"payUntil":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"payUntil"}}}},"shipmentCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"shipmentCard"}}}},"shipments":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"shipments"}}}},"showProgress":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"showProgress"}}}},"status":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"status"}}}},"statusBadge":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"statusBadge"}}}},"statusLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"statusLabel"}}}},"steps":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"steps"}}}},"summary":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"summary"}}}}}}}}}},{"_id":"6abd7b31650a71c6b67049e5","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"FilterChip","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// FilterChip — Loja Lucas Fontana\n// Um filtro aplicado: chip preto de 36px com o nome do filtro e um ×. Clicar remove o filtro.\n// Um por filtro ativo, seguido do link \"Limpar filtros\" (na CatalogToolbar). Nome acessível: \"Remover filtro …\".\n// Emite `onRemove` com o `value`. Não desenha o ×: usa o Icon pelo parâmetro `iconComponent`.\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\n\nexport default {\n  css: `\n:host { display: inline-block; }\nbutton { display: inline-flex; align-items: center; gap: 12px; height: 36px; margin: 0; padding: 0 10px 0 14px; border: 0; background: #0b0b0c; color: #ffffff;\n  font: 600 14px/1 ${FF}; -webkit-font-smoothing: antialiased; cursor: pointer; white-space: nowrap; }\nbutton:hover { background: #1c1d1f; }\nbutton:focus-visible { outline: 2px solid #c8102e; outline-offset: 2px; }\n`,\n  mounted(d2) { d2.on('button', 'click', () => emit(d2, 'onRemove', (d2.params || {}).value || (d2.params || {}).label)); },\n  render(d2) {\n    const p = d2.params || {};\n    const iconRef = refOf(d2.param('iconComponent'));\n    const x = iconRef ? d2.render(iconRef, { name: 'close', size: 16, iconColor: '#ffffff' }, { key: 'x', width: 16, height: 16 }) : '×';\n    return `<button type=\"button\" aria-label=\"Remover filtro ${esc(p.label)}\"><span>${esc(p.label || 'Filtro')}</span>${x}</button>`;\n  }\n};"}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"onRemove":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onRemove"}}}},"value":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"value"}}}}}}}}}},{"_id":"6abd7b437bb89d4f862ec861","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"FilterGroup","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// FilterGroup — Loja Lucas Fontana\n// Uma seção de filtro: título em caixa alta de 12px (800, .24em) seguido de uma hairline até a borda, e as opções.\n// `type: \"checkbox\"` (padrão) usa o Checkbox, com a contagem cinza à direita (\"Lavagem 12\"); `type: \"radio\"` usa o Radio\n// empilhado (ex.: \"Ordenar por\" na FilterSheet). As opções chegam por `options` [{value, label, count, checked}].\n// Ordem na loja: Categoria, Marca, Preço, Disponibilidade (a FilterSheet põe \"Ordenar por\" antes).\n// Emite `onChange`: {value, checked} no checkbox; {value} no radio. Usa Checkbox, Radio e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => { if (Array.isArray(v)) return v; if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } } return []; };\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst DEMO = [{ value: 'Cuidado automotivo', label: 'Cuidado automotivo', count: 9, checked: true }, { value: 'Performance', label: 'Performance', count: 2 }, { value: 'Bonés', label: 'Bonés', count: 1 }];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\nfieldset { border: 0; margin: 0; padding: 0; min-width: 0; font-family: ${FF}; -webkit-font-smoothing: antialiased; }\nlegend { display: flex; align-items: center; gap: 12px; width: 100%; padding: 0; margin: 0 0 12px; font-size: 12px; font-weight: 800; letter-spacing: .24em; line-height: 1.3; text-transform: uppercase; color: #0b0b0c; }\nlegend::after { content: ''; flex: 1; height: 1px; background: #e4e4e2; }\n.body { display: flex; flex-direction: column; }\n`,\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const cbRef = refOf(d2.param('checkbox')); const rdRef = refOf(d2.param('radio')); const icon = refOf(d2.param('iconComponent'));\n    const opts = list(p.options).length ? list(p.options) : DEMO;\n    const name = p.name || 'filtro';\n    let body;\n    if (p.type === 'radio') {\n      const val = p.value != null && p.value !== '' ? String(p.value) : String((opts.find((o) => truthy(o.checked)) || opts[0] || {}).value || '');\n      body = rdRef ? d2.render(rdRef, { name, value: val, inline: false, layout, options: opts.map((o) => ({ value: o.value, label: o.label })) },\n        { key: 'rd-' + val, style: 'height:auto', onChange: (v) => emit(d2, 'onChange', { value: v }) }) : '';\n    } else {\n      body = opts.map((o, i) => cbRef ? d2.render(cbRef, {\n        name, value: String(o.value), label: o.label, count: o.count == null ? '' : String(o.count), checked: truthy(o.checked), layout, iconComponent: icon\n      }, { key: 'cb-' + i + '-' + (truthy(o.checked) ? 1 : 0), style: 'height:auto', onChange: (c) => emit(d2, 'onChange', { value: o.value, checked: !!c }) }) : '').join('');\n    }\n    return `<fieldset class=\"l-${layout}\"><legend>${esc(p.title || 'Categoria')}</legend><div class=\"body\">${body}</div></fieldset>`;\n  }\n};"}},"checkbox":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkbox"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"name":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"name"}}}},"onChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChange"}}}},"options":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"options"}}}},"radio":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"radio"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}},"type":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"type"}}}},"value":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"value"}}}}}}}}}},{"_id":"6abd7b56edeff59159dcd070","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"PriceFilter","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// PriceFilter — Loja Lucas Fontana\n// O grupo de preço: título \"PREÇO\" com hairline, campos \"Mínimo\" e \"Máximo\" (só números) com um botão preto de seta para\n// aplicar, e as faixas prontas como Radio: Até R$ 100 · R$ 100 a R$ 300 · R$ 300 a R$ 1.000 · Acima de R$ 1.000.\n// Emite `onApply` {min, max} (números ou null) e `onRange` com o `value` da faixa (\"0-100\", \"100-300\", \"300-1000\", \"1000-\").\n// Usa FormField, Radio e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => { if (Array.isArray(v)) return v; if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } } return []; };\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst RANGES = [{ value: '0-100', label: 'Até R$ 100' }, { value: '100-300', label: 'R$ 100 a R$ 300' }, { value: '300-1000', label: 'R$ 300 a R$ 1.000' }, { value: '1000-', label: 'Acima de R$ 1.000' }];\nconst numOrNull = (v) => { const n = parseInt(String(v == null ? '' : v).replace(/\\D/g, ''), 10); return isFinite(n) ? n : null; };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\nfieldset { border: 0; margin: 0; padding: 0; min-width: 0; font-family: ${FF}; -webkit-font-smoothing: antialiased; }\nlegend { display: flex; align-items: center; gap: 12px; width: 100%; padding: 0; margin: 0 0 12px; font-size: 12px; font-weight: 800; letter-spacing: .24em; line-height: 1.3; text-transform: uppercase; color: #0b0b0c; }\nlegend::after { content: ''; flex: 1; height: 1px; background: #e4e4e2; }\n.inputs { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 44px; gap: 8px; align-items: end; margin-bottom: 6px; }\n.go { width: 44px; height: 48px; margin: 0; padding: 0; border: 0; border-radius: 2px; background: #0b0b0c; color: #ffffff; display: flex; align-items: center; justify-content: center; cursor: pointer; }\n.go:hover { background: #1c1d1f; }\n.go:focus-visible { outline: 2px solid #c8102e; outline-offset: 2px; }\n`,\n  mounted(d2) {\n    d2.on('.go', 'click', () => { const s = (d2.root && d2.root.__lf) || {}; emit(d2, 'onApply', { min: numOrNull(s.min), max: numOrNull(s.max) }); });\n  },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const ffRef = refOf(d2.param('formField')); const rdRef = refOf(d2.param('radio')); const icon = refOf(d2.param('iconComponent'));\n    const s = d2.root ? (d2.root.__lf || (d2.root.__lf = { min: p.min == null ? '' : String(p.min), max: p.max == null ? '' : String(p.max) })) : { min: '', max: '' };\n    const name = p.name || 'preco';\n    const ranges = list(p.ranges).length ? list(p.ranges) : RANGES;\n    const field = (k, label, ph) => ffRef ? d2.render(ffRef, { label, name: name + '-' + k, mask: 'digits', inputMode: 'numeric', placeholder: ph, value: s[k] || '', layout, iconComponent: icon },\n      { key: k, style: 'height:auto', onInput: (v) => { if (d2.root && d2.root.__lf) d2.root.__lf[k] = v; } }) : '';\n    const go = icon ? d2.render(icon, { name: 'arrow-right', size: 18, iconColor: '#ffffff' }, { key: 'go', width: 18, height: 18 }) : '→';\n    const val = p.value == null ? '' : String(p.value);\n    const radios = rdRef ? d2.render(rdRef, { name, value: val || '__none__', inline: false, layout, options: ranges.map((r) => ({ value: r.value, label: r.label })) },\n      { key: 'r-' + (val || 'none'), style: 'height:auto', onChange: (v) => emit(d2, 'onRange', v) }) : '';\n    return `<fieldset class=\"l-${layout}\"><legend>${esc(p.title || 'Preço')}</legend>\n      <div class=\"inputs\">${field('min', 'Mínimo', 'R$ 0')}${field('max', 'Máximo', 'R$ 5.000')}<button type=\"button\" class=\"go\" aria-label=\"Aplicar faixa de preço\">${go}</button></div>\n      ${radios}\n    </fieldset>`;\n  }\n};"}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"max":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"max"}}}},"min":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"min"}}}},"name":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"name"}}}},"onApply":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onApply"}}}},"onRange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onRange"}}}},"radio":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"radio"}}}},"ranges":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ranges"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}},"value":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"value"}}}}}}}}}},{"_id":"6abd7b63e43d37dad5dd5e38","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"LoadMore","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// LoadMore — Loja Lucas Fontana\n// Paginação das listagens: botão de contorno \"Carregar mais produtos\" (52px; largura toda no mobile) e, embaixo,\n// \"Mostrando 9 de [N] produtos\" (anunciado por leitor de tela quando muda).\n// `done: true` esconde o botão (acabaram os produtos). `loading: true` mostra \"Carregando…\".\n// Emite `onClick`. Usa o Button pelo parâmetro `button`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.more { display: flex; flex-direction: column; align-items: center; gap: 16px; padding-top: 24px; font-family: ${FF}; -webkit-font-smoothing: antialiased; }\n.btn { width: 300px; height: 52px; }\np { margin: 0; font-size: 14px; color: #6b6e73; }\n.l-mobile .btn { width: 100%; }\n`,\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const btnRef = refOf(d2.param('button'));\n    const loading = truthy(p.loading);\n    const btn = !truthy(p.done) && btnRef ? `<div class=\"btn\">${d2.render(btnRef, {\n      label: loading ? 'Carregando…' : (p.label || 'Carregar mais produtos'), variant: 'outline', size: 'lg', fullWidth: 'always', isDisabled: loading, layout\n    }, { key: 'b-' + (loading ? 'l' : 'n'), height: 52, onClick: () => emit(d2, 'onClick', true) })}</div>` : '';\n    return `<div class=\"more l-${layout}\">${btn}${p.countLabel ? `<p aria-live=\"polite\">${esc(p.countLabel)}</p>` : ''}</div>`;\n  }\n};"}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"countLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"countLabel"}}}},"done":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"done"}}}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"loading":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"loading"}}}},"onClick":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onClick"}}}}}}}}}},{"_id":"6abd7b7a070cf08086c28d5c","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"FilterPanel","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// FilterPanel — Loja Lucas Fontana\n// A lateral de filtros do desktop (264px, na CatalogLayout): título \"FILTRAR\" com o ícone de filtro e o link \"Limpar tudo\",\n// depois os grupos, 28px entre eles. Abaixo de 1200px os mesmos grupos vão para a FilterSheet.\n// Os grupos chegam por `groups`: [{id, kind: \"checkbox\" | \"radio\" | \"price\", title, options, value, min, max, ranges}].\n// Emite `onChange` {group, value, checked}, `onPrice` {group, min, max}, `onRange` {group, value} e `onClear`.\n// `showClear: false` esconde \"Limpar tudo\". Usa FilterGroup, PriceFilter, Checkbox, Radio, FormField e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => { if (Array.isArray(v)) return v; if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } } return []; };\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst DEMO = [\n  { id: 'categoria', title: 'Categoria', options: [{ value: 'Cuidado automotivo', label: 'Cuidado automotivo', count: 9, checked: true }, { value: 'Performance', label: 'Performance', count: 2 }, { value: 'Bonés', label: 'Bonés', count: 1 }] },\n  { id: 'marca', title: 'Marca', options: [{ value: 'Lucas Fontana', label: 'Lucas Fontana', count: 10 }, { value: 'BPower Motorsport', label: 'BPower Motorsport', count: 2 }] },\n  { id: 'preco', kind: 'price', title: 'Preço' },\n  { id: 'estoque', title: 'Disponibilidade', options: [{ value: 'em-estoque', label: 'Mostrar só produtos em estoque' }] }\n];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.fp { display: flex; flex-direction: column; gap: 28px; font-family: ${FF}; -webkit-font-smoothing: antialiased; }\n.head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }\nh2 { display: flex; align-items: center; gap: 12px; margin: 0; font-size: 15px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; color: #0b0b0c; }\n.clear { margin: 0; padding: 0; border: 0; background: none; font: 600 14px/1.2 ${FF}; color: #0b0b0c; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }\n.clear:hover { color: #c8102e; }\n.clear:focus-visible { outline: 2px solid #c8102e; outline-offset: 2px; }\n`,\n  mounted(d2) { d2.on('.clear', 'click', () => emit(d2, 'onClear', true)); },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const R = { fg: refOf(d2.param('filterGroup')), pf: refOf(d2.param('priceFilter')), cb: refOf(d2.param('checkbox')), rd: refOf(d2.param('radio')), ff: refOf(d2.param('formField')), icon: refOf(d2.param('iconComponent')) };\n    const groups = list(p.groups).length ? list(p.groups) : DEMO;\n    const ver = p.version == null ? '0' : String(p.version);\n    const title = R.icon ? d2.render(R.icon, { name: 'filter', size: 20, iconColor: '#0b0b0c' }, { key: 'fi', width: 20, height: 20 }) : '';\n    const body = groups.map((g) => {\n      if (g.kind === 'price') {\n        return R.pf ? d2.render(R.pf, { title: g.title || 'Preço', name: g.id, min: g.min == null ? '' : String(g.min), max: g.max == null ? '' : String(g.max), value: g.value || '', ranges: g.ranges || [], layout, formField: R.ff, radio: R.rd, iconComponent: R.icon }, {\n          key: 'p-' + g.id + '-' + ver, style: 'height:auto',\n          onApply: (v) => emit(d2, 'onPrice', Object.assign({ group: g.id }, v || {})), onRange: (v) => emit(d2, 'onRange', { group: g.id, value: v })\n        }) : '';\n      }\n      return R.fg ? d2.render(R.fg, { title: g.title, name: g.id, type: g.kind === 'radio' ? 'radio' : 'checkbox', options: g.options || [], value: g.value || '', layout, checkbox: R.cb, radio: R.rd, iconComponent: R.icon }, {\n        key: 'g-' + g.id + '-' + ver, style: 'height:auto',\n        onChange: (v) => emit(d2, 'onChange', Object.assign({ group: g.id }, v || {}))\n      }) : '';\n    }).join('');\n    const showClear = p.showClear == null || p.showClear === '' ? true : truthy(p.showClear);\n    return `<div class=\"fp l-${layout}\">\n      ${truthy(p.hideHead) ? '' : `<div class=\"head\"><h2>${title}${esc(p.title || 'Filtrar')}</h2>${showClear ? `<button type=\"button\" class=\"clear\">${esc(p.clearLabel || 'Limpar tudo')}</button>` : ''}</div>`}\n      ${body}\n    </div>`;\n  }\n};"}},"checkbox":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkbox"}}}},"clearLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"clearLabel"}}}},"filterGroup":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"filterGroup"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"groups":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"groups"}}}},"hideHead":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"hideHead"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChange"}}}},"onClear":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onClear"}}}},"onPrice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onPrice"}}}},"onRange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onRange"}}}},"priceFilter":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"priceFilter"}}}},"radio":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"radio"}}}},"showClear":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"showClear"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}},"version":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"version"}}}}}}}}}},{"_id":"6abd7b998b5295df285aea5c","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"FilterSheet","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// FilterSheet — Loja Lucas Fontana\n// A gaveta de filtrar e ordenar do tablet e do mobile: cabeçalho \"FILTRAR E ORDENAR\" com o botão de fechar, os grupos\n// rolando (começa por \"Ordenar por\", depois os mesmos grupos da FilterPanel) e o rodapé fixo com \"Limpar\" (contorno)\n// e \"Ver resultados\" (preto). Borda vermelha de 3px no topo.\n// Mobile: sobe por cima de um fundo escuro, deixando 48px da página à mostra no topo. Tablet: painel de 420px pela direita.\n// Fecha no Esc, no fundo escuro e no ×; trava a rolagem da página enquanto aberta.\n// `open` mostra; `static: true` desenha no lugar (para documentação). Os grupos chegam por `groups` (como na FilterPanel)\n// e a ordenação por `sortOptions`/`sortValue`. Emite `onClose`, `onClear`, `onApply`, `onSort` e os eventos dos grupos.\n// Usa FilterPanel, FilterGroup, PriceFilter, Checkbox, Radio, FormField, Button e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => { if (Array.isArray(v)) return v; if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } } return []; };\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst SORTS = [{ value: 'relevancia', label: 'Relevância' }, { value: 'menor-preco', label: 'Menor preço' }, { value: 'maior-preco', label: 'Maior preço' }, { value: 'mais-vendidos', label: 'Mais vendidos' }];\n\nexport default {\n  css: `\n:host { display: block; }\n* { box-sizing: border-box; }\n.sheet { position: fixed; inset: 0; z-index: 1000; display: flex; justify-content: flex-end; font-family: ${FF}; -webkit-font-smoothing: antialiased; }\n.static { position: relative; inset: auto; height: 844px; }\n.scrim { position: absolute; inset: 0; margin: 0; padding: 0; border: 0; background: rgba(11, 11, 12, .6); cursor: pointer; }\n.panel { position: relative; display: flex; flex-direction: column; width: 420px; max-width: 100%; height: 100%; background: #ffffff; border-top: 3px solid #c8102e; outline: none; }\n.head { flex: none; display: flex; align-items: center; justify-content: space-between; gap: 12px; height: 64px; padding: 0 12px 0 20px; border-bottom: 1px solid #e4e4e2; }\nh2 { display: flex; align-items: center; gap: 12px; margin: 0; font-size: 18px; font-weight: 800; font-stretch: 112%; text-transform: uppercase; color: #0b0b0c; }\n.close { width: 44px; height: 44px; margin: 0; padding: 0; border: 0; background: transparent; color: #0b0b0c; display: flex; align-items: center; justify-content: center; cursor: pointer; }\n.close:focus-visible { outline: 2px solid #c8102e; outline-offset: -2px; }\n.body { flex: 1; overflow-y: auto; padding: 16px 20px 24px; display: flex; flex-direction: column; gap: 24px; }\n.foot { flex: none; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px; padding: 16px 20px; border-top: 1px solid #e4e4e2; background: #ffffff; }\n.fb { height: 52px; }\n.l-mobile .panel { width: 100%; height: calc(100% - 48px); margin-top: 48px; }\n`,\n  mounted(d2) {\n    d2.on('.scrim, .close', 'click', () => emit(d2, 'onClose', true));\n    const onKey = (e) => { const p = d2.params || {}; if (e.key === 'Escape' && truthy(p.open) && !truthy(p.static)) emit(d2, 'onClose', true); };\n    document.addEventListener('keydown', onKey);\n    d2.onUnmount(() => { document.removeEventListener('keydown', onKey); document.body.style.overflow = ''; });\n  },\n  updated(d2) {\n    const p = d2.params || {};\n    const on = truthy(p.open) && !truthy(p.static);\n    document.body.style.overflow = on ? 'hidden' : '';\n    if (on) { const el = d2.$('.panel'); if (el && d2.root && !d2.root.__focused) { el.focus(); d2.root.__focused = true; } }\n    else if (d2.root) d2.root.__focused = false;\n  },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'mobile';\n    const open = truthy(p.open) || truthy(p.static);\n    if (!open) return '';\n    const R = { fp: refOf(d2.param('filterPanel')), fg: refOf(d2.param('filterGroup')), pf: refOf(d2.param('priceFilter')), cb: refOf(d2.param('checkbox')), rd: refOf(d2.param('radio')), ff: refOf(d2.param('formField')), btn: refOf(d2.param('button')), icon: refOf(d2.param('iconComponent')) };\n    const ver = p.version == null ? '0' : String(p.version);\n    const sorts = list(p.sortOptions).length ? list(p.sortOptions) : SORTS;\n    const sortVal = p.sortValue || 'relevancia';\n    const sort = R.fg ? d2.render(R.fg, { title: 'Ordenar por', name: 'ordenar', type: 'radio', options: sorts, value: sortVal, layout, radio: R.rd, iconComponent: R.icon },\n      { key: 's-' + sortVal, style: 'height:auto', onChange: (v) => emit(d2, 'onSort', v && v.value) }) : '';\n    const groups = R.fp ? d2.render(R.fp, { groups: list(p.groups), hideHead: true, version: ver, layout, filterGroup: R.fg, priceFilter: R.pf, checkbox: R.cb, radio: R.rd, formField: R.ff, iconComponent: R.icon }, {\n      key: 'fp-' + ver, style: 'height:auto',\n      onChange: (v) => emit(d2, 'onChange', v), onPrice: (v) => emit(d2, 'onPrice', v), onRange: (v) => emit(d2, 'onRange', v)\n    }) : '';\n    const fi = R.icon ? d2.render(R.icon, { name: 'filter', size: 20, iconColor: '#0b0b0c' }, { key: 'fi', width: 20, height: 20 }) : '';\n    const x = R.icon ? d2.render(R.icon, { name: 'close', size: 22, iconColor: '#0b0b0c' }, { key: 'x', width: 22, height: 22 }) : '×';\n    const fb = (k, label, variant, evt) => R.btn ? `<div class=\"fb\">${d2.render(R.btn, { label, variant, size: 'lg', fullWidth: 'always', layout }, { key: k, height: 52, onClick: () => emit(d2, evt, true) })}</div>` : '';\n    return `<div class=\"sheet l-${layout}${truthy(p.static) ? ' static' : ''}\">\n      <button type=\"button\" class=\"scrim\" aria-label=\"Fechar filtros\" tabindex=\"-1\"></button>\n      <div class=\"panel\" role=\"dialog\"${truthy(p.static) ? '' : ' aria-modal=\"true\"'} aria-label=\"${esc(p.title || 'Filtrar e ordenar')}\" tabindex=\"-1\">\n        <div class=\"head\"><h2>${fi}${esc(p.title || 'Filtrar e ordenar')}</h2><button type=\"button\" class=\"close\" aria-label=\"Fechar\">${x}</button></div>\n        <div class=\"body\">${sort}${groups}</div>\n        <div class=\"foot\">${fb('clr', p.clearLabel || 'Limpar', 'outline', 'onClear')}${fb('apply', p.applyLabel || 'Ver resultados', 'primary', 'onApply')}</div>\n      </div>\n    </div>`;\n  }\n};"}},"applyLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"applyLabel"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"checkbox":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkbox"}}}},"clearLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"clearLabel"}}}},"filterGroup":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"filterGroup"}}}},"filterPanel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"filterPanel"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"groups":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"groups"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onApply":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onApply"}}}},"onChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChange"}}}},"onClear":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onClear"}}}},"onClose":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onClose"}}}},"onPrice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onPrice"}}}},"onRange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onRange"}}}},"onSort":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSort"}}}},"open":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"open"}}}},"priceFilter":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"priceFilter"}}}},"radio":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"radio"}}}},"sortOptions":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"sortOptions"}}}},"sortValue":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"sortValue"}}}},"static":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"static"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}},"version":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"version"}}}}}}}}}},{"_id":"6abd7bb3e43d37dad5dd5f05","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"CatalogToolbar","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// CatalogToolbar — Loja Lucas Fontana\n// A linha acima dos resultados: filtros ativos, contagem e ordenação.\n// Desktop: FilterChips ativos + \"Limpar filtros\" à esquerda, \"Ordenar por\" à direita (a contagem fica no PageHeader).\n// Tablet: botão de contorno \"Filtrar (n)\", a contagem e \"Ordenar por\"; os chips numa segunda linha.\n// Mobile: \"Filtrar (n)\" e o seletor de ordenação dividem a largura; depois os chips e, embaixo, a contagem.\n// Chips chegam por `chips` [{id, label}]; `filterCount` (padrão: quantidade de chips); `countLabel` (\"Mostrando 9 de 42 produtos\");\n// ordenação por `sortOptions` [{value, label}] e `sortValue`.\n// Emite `onRemove` (id do chip), `onClear`, `onOpenFilters` e `onSort` (value). Usa FilterChip, FormField e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => { if (Array.isArray(v)) return v; if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } } return []; };\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst SORTS = [{ value: 'relevancia', label: 'Relevância' }, { value: 'menor-preco', label: 'Menor preço' }, { value: 'maior-preco', label: 'Maior preço' }, { value: 'mais-vendidos', label: 'Mais vendidos' }];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.tb { display: flex; flex-direction: column; gap: 16px; font-family: ${FF}; -webkit-font-smoothing: antialiased; color: #0b0b0c; }\n.row { display: flex; align-items: center; gap: 16px; min-height: 48px; }\n.chips { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; }\n.clear { margin: 0; padding: 0; border: 0; background: none; font: 600 14px/1.2 ${FF}; color: #0b0b0c; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }\n.clear:hover { color: #c8102e; }\n.count { font-size: 15px; color: #6b6e73; }\n.sort { margin-left: auto; display: flex; align-items: center; gap: 12px; }\n.sort > span { font-size: 14px; font-weight: 700; white-space: nowrap; }\n.sel { width: 200px; }\n.filter { display: inline-flex; align-items: center; justify-content: center; gap: 10px; height: 48px; margin: 0; padding: 0 20px; border: 1px solid #0b0b0c; background: #ffffff; color: #0b0b0c;\n  font: 800 13px/1 ${FF}; letter-spacing: .12em; text-transform: uppercase; cursor: pointer; }\n.filter:hover { background: #0b0b0c; color: #ffffff; }\n.filter:focus-visible, .clear:focus-visible { outline: 2px solid #c8102e; outline-offset: 2px; }\n.l-mobile { gap: 12px; }\n.l-mobile .row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px; }\n.l-mobile .sort { margin-left: 0; }\n.l-mobile .sort > span { display: none; }\n.l-mobile .sel { width: 100%; }\n.l-mobile .filter { width: 100%; padding: 0 12px; }\n`,\n  mounted(d2) {\n    d2.on('.clear', 'click', () => emit(d2, 'onClear', true));\n    d2.on('.filter', 'click', () => emit(d2, 'onOpenFilters', true));\n  },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const R = { fc: refOf(d2.param('filterChip')), ff: refOf(d2.param('formField')), icon: refOf(d2.param('iconComponent')) };\n    const chips = list(p.chips);\n    const n = p.filterCount == null || p.filterCount === '' ? chips.length : Number(p.filterCount) || 0;\n    const sorts = list(p.sortOptions).length ? list(p.sortOptions) : SORTS;\n    const sortVal = p.sortValue || 'relevancia';\n    const chipHtml = chips.length ? `<div class=\"chips\">${chips.map((c, i) => R.fc ? d2.render(R.fc, { label: c.label, value: c.id, iconComponent: R.icon }, { key: 'c-' + (c.id || i), width: 'auto', height: 36, onRemove: () => emit(d2, 'onRemove', c.id) }) : '').join('')}<button type=\"button\" class=\"clear\">Limpar filtros</button></div>` : '';\n    const sel = R.ff ? `<div class=\"sel\">${d2.render(R.ff, { ariaLabel: 'Ordenar por', name: 'ordenar', options: sorts, value: sortVal, layout, iconComponent: R.icon }, { key: 'sort-' + sortVal, style: 'height:auto', onChange: (v) => emit(d2, 'onSort', v) })}</div>` : '';\n    const sort = `<div class=\"sort\"><span>Ordenar por</span>${sel}</div>`;\n    const fi = R.icon ? d2.render(R.icon, { name: 'filter', size: 20, iconColor: 'currentColor' }, { key: 'fi', width: 20, height: 20 }) : '';\n    const filterBtn = `<button type=\"button\" class=\"filter\" aria-haspopup=\"dialog\">${fi}Filtrar${n ? ' (' + n + ')' : ''}</button>`;\n    const count = p.countLabel ? `<span class=\"count\">${esc(p.countLabel)}</span>` : '';\n    let html;\n    if (layout === 'desktop') html = `<div class=\"row\">${chipHtml || '<span></span>'}${sort}</div>`;\n    else if (layout === 'tablet') html = `<div class=\"row\">${filterBtn}${count}${sort}</div>${chipHtml}`;\n    else html = `<div class=\"row\">${filterBtn}${sort}</div>${chipHtml}${count}`;\n    return `<div class=\"tb l-${layout}\">${html}</div>`;\n  }\n};"}},"chips":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"chips"}}}},"countLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"countLabel"}}}},"filterChip":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"filterChip"}}}},"filterCount":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"filterCount"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onClear":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onClear"}}}},"onOpenFilters":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onOpenFilters"}}}},"onRemove":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onRemove"}}}},"onSort":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSort"}}}},"sortOptions":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"sortOptions"}}}},"sortValue":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"sortValue"}}}}}}}}}},{"_id":"6abd7bcc8b5295df285aeadc","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"EmptyState","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// EmptyState — Loja Lucas Fontana\n// O que a busca sem resultado mostra, centralizado: quadrado preto com o ícone de busca riscada, kicker vermelho\n// \"Nenhum resultado\", título citando a busca (44/36/28px), uma linha no tom do Lucas, a busca grande (56px, borda preta,\n// mantém o botão \"Buscar\" em qualquer largura), chips de sugestão (\"Tente buscar por: shampoo · cera · pretinho · BPower · boné\")\n// e o botão vermelho \"Ver todos os produtos\". Na página, vem seguido da faixa cinza \"Os mais vendidos da loja\".\n// `query` monta o título padrão (\"Nada encontrado para “…”\"). Emite `onSearch` (texto) e `onSuggestion` (sugestão clicada).\n// Usa SearchBar, Button e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => { if (Array.isArray(v)) return v; if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } } return []; };\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst PAD = { desktop: '80px 96px 96px', tablet: '64px 40px 80px', mobile: '48px 20px 64px' };\nconst SUGG = ['shampoo', 'cera', 'pretinho', 'BPower', 'boné'];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.es { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 20px; width: 100%; background: #ffffff; color: #0b0b0c; font-family: ${FF}; -webkit-font-smoothing: antialiased; }\np, h1 { margin: 0; }\n.mark { width: 56px; height: 56px; margin-bottom: 8px; background: #0b0b0c; color: #ffffff; display: flex; align-items: center; justify-content: center; }\n.kicker { display: flex; align-items: center; gap: 12px; font-size: 12px; font-weight: 700; letter-spacing: .3em; text-transform: uppercase; color: #c8102e; }\n.kicker::before { content: ''; width: 22px; height: 3px; background: #c8102e; }\nh1 { max-width: 960px; font-size: 44px; font-weight: 800; font-stretch: 115%; line-height: 1; letter-spacing: -.01em; text-transform: uppercase; overflow-wrap: break-word; }\n.text { max-width: 540px; font-size: 17px; line-height: 1.6; color: #45474b; }\n.search { width: 100%; max-width: 584px; height: 56px; margin-top: 8px; }\n.sugg { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 12px; }\n.sugg > span { font-size: 15px; color: #6b6e73; margin-right: 4px; }\n.chip { display: inline-flex; align-items: center; height: 40px; margin: 0; padding: 0 16px; border: 1px solid #d9d9d6; background: #ffffff; color: #0b0b0c; font: 600 15px/1 ${FF}; cursor: pointer; }\n.chip:hover { border-color: #0b0b0c; }\n.chip:focus-visible { outline: 2px solid #c8102e; outline-offset: 2px; }\n.cta { height: 52px; margin-top: 12px; min-width: 280px; }\n.l-tablet h1 { font-size: 36px; }\n.l-mobile { gap: 16px; }\n.l-mobile .kicker { font-size: 11px; letter-spacing: .26em; }\n.l-mobile h1 { font-size: 28px; font-stretch: 112%; line-height: 1.02; letter-spacing: 0; }\n.l-mobile .text { font-size: 15px; }\n.l-mobile .search { height: 52px; }\n.l-mobile .sugg { gap: 8px; }\n.l-mobile .sugg > span { flex-basis: 100%; margin: 0 0 4px; }\n.l-mobile .chip { height: 44px; padding: 0 14px; font-size: 14px; }\n.l-mobile .cta { width: 100%; min-width: 0; }\n`,\n  mounted(d2) { d2.on('.chip', 'click', (e, el) => emit(d2, 'onSuggestion', el.getAttribute('data-q'))); },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const R = { sb: refOf(d2.param('searchBar')), btn: refOf(d2.param('button')), icon: refOf(d2.param('iconComponent')) };\n    const q = String(p.query || '').trim();\n    const title = p.title || (q ? `Nada encontrado para “${q}”` : 'Nenhum produto por aqui');\n    const sugg = list(p.suggestions).length ? list(p.suggestions) : SUGG;\n    const mark = R.icon ? d2.render(R.icon, { name: p.iconName || 'search-x', size: 26, iconColor: '#ffffff' }, { key: 'm', width: 26, height: 26 }) : '';\n    const search = R.sb ? `<div class=\"search\">${d2.render(R.sb, { size: 'lg', showButton: true, layout, placeholder: 'Busque por produto, categoria ou marca', shortPlaceholder: 'Buscar produto ou marca', button: R.btn, searchIcon: R.icon }, { key: 'sb', onSearch: (v) => emit(d2, 'onSearch', v) })}</div>` : '';\n    const cta = R.btn && p.ctaLabel !== '' ? `<div class=\"cta\">${d2.render(R.btn, { label: p.ctaLabel || 'Ver todos os produtos', variant: 'brand', size: 'lg', fullWidth: 'always', arrow: true, href: p.ctaHref || '/lista-de-produtos/q', layout }, { key: 'cta', height: 52 })}</div>` : '';\n    return `<div class=\"es l-${layout}\" style=\"padding:${PAD[layout]}\" role=\"status\">\n      <span class=\"mark\" aria-hidden=\"true\">${mark}</span>\n      <p class=\"kicker\">${esc(p.eyebrow || 'Nenhum resultado')}</p>\n      <h1>${esc(title)}</h1>\n      <p class=\"text\">${esc(p.description || 'Nem o Lucas achou isso na garagem. Confira se escreveu certinho ou tente um termo mais simples.')}</p>\n      ${search}\n      <div class=\"sugg\"><span>${esc(p.suggestionsLabel || 'Tente buscar por:')}</span>${sugg.map((t) => `<button type=\"button\" class=\"chip\" data-q=\"${esc(t)}\">${esc(t)}</button>`).join('')}</div>\n      ${cta}\n    </div>`;\n  }\n};"}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"ctaHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ctaHref"}}}},"ctaLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ctaLabel"}}}},"description":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"description"}}}},"eyebrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"eyebrow"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"iconName":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconName"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onSearch":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSearch"}}}},"onSuggestion":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSuggestion"}}}},"query":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"query"}}}},"searchBar":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"searchBar"}}}},"suggestions":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"suggestions"}}}},"suggestionsLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"suggestionsLabel"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}}}}}}}},{"_id":"6abd7c5d7bb89d4f862ecb61","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"CatalogLayout","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// CatalogLayout — Loja Lucas Fontana\n// O corpo da página de LISTA DE PRODUTOS — serve para categoria e para resultado de busca (a mesma página):\n// PageHeader (título, breadcrumb e \"Mostrando 9 de N produtos\"), e embaixo:\n// Desktop: a FilterPanel numa coluna de 264px presa na rolagem, 48px dos resultados.\n// Tablet e mobile: a lateral some; o botão \"Filtrar (n)\" da CatalogToolbar abre a FilterSheet.\n// Resultados: CatalogToolbar, grade de ProductCards com contorno (3 colunas no desktop e tablet, 2 no mobile) e LoadMore.\n// Sem resultado: o EmptyState e a faixa cinza \"Os mais vendidos da loja\".\n// Dados: `dataset` recebe o DataSet da tabela Produtos (`@produtosDataSet`) — o componente carrega todas as páginas.\n// `products` (lista) serve de alternativa. Produtos com `ativo: false` não aparecem.\n// A página filtra, ordena e pagina aqui mesmo: busca (`query` ou `?q=` na URL), Categoria, Marca, Preço (faixas ou mínimo/máximo),\n// \"Só em estoque\", e ordenação Relevância · Menor preço · Maior preço · Mais vendidos. `category` abre já filtrado. Os filtros também ficam na URL (`?q=`, `?categoria=slug`, `?marca=slug`, `?preco=100-300`, `?estoque=1`, `?ordem=`): a página lê ao abrir e atualiza a cada mudança.\n// Não desenha nada disso: usa PageHeader, Breadcrumb, FilterPanel, FilterSheet, FilterGroup, PriceFilter, CatalogToolbar,\n// FilterChip, ProductCard, LoadMore, EmptyState, SectionHeader, SearchBar, Checkbox, Radio, FormField, Button, Badge, Price e Icon.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => { if (Array.isArray(v)) return v; if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } } return []; };\nconst obj = (v) => { if (v && typeof v === 'object' && !Array.isArray(v)) return v; if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } } return {}; };\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst fold = (s) => String(s == null ? '' : s).normalize('NFD').replace(/[\\u0300-\\u036f]/g, '').toLowerCase().trim();\nconst brl = (n) => 'R$ ' + Number(n).toLocaleString('pt-BR', { minimumFractionDigits: 0, maximumFractionDigits: 0 });\nconst PAD = { desktop: '40px 96px 120px', tablet: '32px 40px 88px', mobile: '24px 20px 64px' };\nconst CARD_H = { desktop: 500, tablet: 470, mobile: 384 };\nconst SORTS = [{ value: 'relevancia', label: 'Relevância' }, { value: 'menor-preco', label: 'Menor preço' }, { value: 'maior-preco', label: 'Maior preço' }, { value: 'mais-vendidos', label: 'Mais vendidos' }];\nconst RANGES = [{ value: '0-100', label: 'Até R$ 100' }, { value: '100-300', label: 'R$ 100 a R$ 300' }, { value: '300-1000', label: 'R$ 300 a R$ 1.000' }, { value: '1000-', label: 'Acima de R$ 1.000' }];\nconst DESCR = { 'Cuidado automotivo': 'Tudo que o Lucas usa pra deixar o carro brilhando — e mais um pouco.', Performance: 'As peças de performance dos parceiros, testadas no canal.', 'Bonés': 'Pra quem é da garagem até no visual.', 'Vestuário': 'Pra quem é da garagem até no visual.', 'Acessórios': 'Bonés, chaveiros e adesivos pra quem é da garagem.' };\nconst blankSel = () => ({ categoria: [], subcategoria: [], marca: [], estoque: false, range: '', min: null, max: null });\n// Categorias ativas (tabela Categorias); Produtos.categoria é um lookup, então o nome vem daqui\nlet CATS = null; let CATS_LOADING = null;\n// Produtos ativos da loja (serviço público produtosLoja); usado quando não há DataSet legível\nlet PRODS = null; let PRODS_LOADING = null;\n// Sacola no navegador (mesma chave da página Sacola): [{sku, qty}]\nconst addToBag = (sku, qty) => {\n  if (!sku) return;\n  try {\n    const bag = JSON.parse(localStorage.getItem('lf-sacola') || '[]');\n    const list2 = Array.isArray(bag) ? bag : [];\n    const f = list2.find((y) => y && y.sku === sku);\n    if (f) f.qty = (Number(f.qty) || 0) + (Number(qty) || 1); else list2.push({ sku, qty: Number(qty) || 1 });\n    localStorage.setItem('lf-sacola', JSON.stringify(list2));\n    window.dispatchEvent(new CustomEvent('lf-sacola', { detail: { count: list2.reduce((s, y) => s + (Number(y.qty) || 0), 0) } }));\n  } catch (e) { /* sem storage */ }\n};\n// Mantém a posição da rolagem quando os filtros mudam e a lista é redesenhada\nconst holdScroll = (d2) => {\n  try {\n    if (typeof window === 'undefined' || typeof document === 'undefined') return () => {};\n    let sc = null;\n    let n = d2.root;\n    while (n && !sc) {\n      n = n.parentNode || (n.getRootNode && n.getRootNode().host) || null;\n      if (n && n.nodeType === 1) {\n        const cs = window.getComputedStyle(n);\n        if (/(auto|scroll)/.test(cs.overflowY) && n.scrollHeight > n.clientHeight) sc = n;\n      }\n    }\n    const el = sc || document.scrollingElement || document.documentElement;\n    const y = el.scrollTop;\n    const restore = () => { try { if (Math.abs(el.scrollTop - y) > 2) el.scrollTop = y; } catch (e) { /* sem rolagem */ } };\n    return () => {\n      if (typeof requestAnimationFrame === 'function') requestAnimationFrame(() => { restore(); requestAnimationFrame(restore); });\n      [120, 300, 600].forEach((ms) => setTimeout(restore, ms));\n    };\n  } catch (e) { return () => {}; }\n};\nconst slugify = (s) => fold(s).replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');\nconst csv = (v) => String(v || '').split(',').map((x) => x.trim()).filter(Boolean);\n// Filtros na URL: ?q= &categoria=slug,slug &marca=slug &preco=100-300 &estoque=1 &ordem=menor-preco\nconst readUrl = () => {\n  try {\n    const u = new URLSearchParams((typeof location !== 'undefined' && location.search) || '');\n    const out = {};\n    const q = u.get('q'); if (q) out.q = q;\n    const s = blankSel(); let has = false;\n    const c = csv(u.get('categoria')); if (c.length) { s.categoria = c; has = true; }\n    const m = csv(u.get('marca')); if (m.length) { s.marca = m; has = true; }\n    const sc = csv(u.get('subcategoria')); if (sc.length) { s.subcategoria = sc; has = true; }\n    const pr = u.get('preco');\n    if (pr && /^\\d*-\\d*$/.test(pr) && pr !== '-') {\n      if (RANGES.some((x) => x.value === pr)) s.range = pr; else { const b = rangeBounds(pr); s.min = b[0]; s.max = b[1]; }\n      has = true;\n    }\n    if (u.get('estoque') === '1') { s.estoque = true; has = true; }\n    if (has) out.sel = s;\n    const o = u.get('ordem'); if (o && SORTS.some((x) => x.value === o)) out.sort = o;\n    return out;\n  } catch (e) { return {}; }\n};\nconst writeUrl = (st, cats) => {\n  try {\n    if (typeof history === 'undefined' || !history.replaceState || typeof location === 'undefined') return;\n    const slugByName = {}; (cats || []).forEach((c) => { slugByName[c.nome] = c.slug; });\n    const u = new URLSearchParams();\n    const sel = st.sel || blankSel();\n    if (st.q) u.set('q', st.q);\n    if (sel.categoria.length) u.set('categoria', sel.categoria.map((n) => slugByName[n] || slugify(n)).join(','));\n    if (sel.subcategoria && sel.subcategoria.length) u.set('subcategoria', sel.subcategoria.map(slugify).join(','));\n    if (sel.marca.length) u.set('marca', sel.marca.map(slugify).join(','));\n    if (sel.range) u.set('preco', sel.range);\n    else if (sel.min != null || sel.max != null) u.set('preco', (sel.min == null ? '' : sel.min) + '-' + (sel.max == null ? '' : sel.max));\n    if (sel.estoque) u.set('estoque', '1');\n    if (st.sort && st.sort !== 'relevancia') u.set('ordem', st.sort);\n    const qs = u.toString().replace(/%2C/gi, ',');\n    history.replaceState(history.state, '', location.pathname + (qs ? '?' + qs : '') + (location.hash || ''));\n  } catch (e) { /* sem history */ }\n};\nconst rangeBounds = (r) => { if (!r) return [null, null]; const [a, b] = r.split('-'); return [a === '' ? null : Number(a), b === '' || b == null ? null : Number(b)]; };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.cat { width: 100%; background: #ffffff; font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased; }\n.in { display: grid; grid-template-columns: 264px minmax(0, 1fr); gap: 48px; align-items: start; }\n.side { position: sticky; top: 24px; min-width: 0; }\n.main { display: flex; flex-direction: column; gap: 24px; min-width: 0; }\n.grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }\n.l-tablet .in, .l-mobile .in { grid-template-columns: minmax(0, 1fr); }\n.l-tablet .main { gap: 20px; }\n.l-tablet .grid { gap: 16px; }\n.l-mobile .main { gap: 16px; }\n.l-mobile .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }\n.best { background: #f5f5f3; }\n.best .bin { display: flex; flex-direction: column; gap: 40px; }\n.best .grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }\n.l-tablet .best .grid, .l-mobile .best .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }\n.l-mobile .best .bin { gap: 24px; }\n`,\n\n  mounted(d2) {\n    // Traz todos os produtos da tabela (todas as páginas do DataSet)\n    try { const dh = d2.param('dataset') && d2.data ? d2.data('dataset') : null; if (dh && typeof dh.loadAll === 'function') dh.loadAll(); } catch (e) { /* sem DataSet */ }\n    if (!CATS) {\n      if (!CATS_LOADING) {\n        CATS_LOADING = d2.rush('categoriasLoja').invoke({}).then((res) => { CATS = (res && res.data !== undefined ? res.data : res) || []; }).catch(() => { CATS_LOADING = null; });\n      }\n      const pr = CATS_LOADING;\n      if (pr) pr.then(() => { d2.state.catsTick = Date.now(); });\n    }\n    if (!PRODS) {\n      if (!PRODS_LOADING) {\n        PRODS_LOADING = d2.rush('produtosLoja').invoke({}).then((res) => { PRODS = (res && res.data !== undefined ? res.data : res) || []; }).catch(() => { PRODS_LOADING = null; });\n      }\n      const pr2 = PRODS_LOADING;\n      if (pr2) pr2.then(() => { d2.state.catsTick = Date.now(); });\n    }\n    // Lê o filtro inicial da URL (?q= e ?categoria=), se houver\n    try {\n      const url = readUrl();\n      if (url.q) d2.state.q = url.q;\n      if (url.sel) d2.state.sel = url.sel;\n      if (url.sort) d2.state.sort = url.sort;\n    } catch (e) { /* sem URL */ }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    void d2.state.catsTick;\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const desk = layout === 'desktop';\n    const r = (n) => refOf(d2.param(n));\n    const R = {\n      ph: r('pageHeader'), bc: r('breadcrumb'), fp: r('filterPanel'), fs: r('filterSheet'), fg: r('filterGroup'), pf: r('priceFilter'),\n      tb: r('catalogToolbar'), fc: r('filterChip'), pc: r('productCard'), lm: r('loadMore'), es: r('emptyState'), sh: r('sectionHeader'),\n      sb: r('searchBar'), cb: r('checkbox'), rd: r('radio'), ff: r('formField'), btn: r('button'), badge: r('badge'), price: r('priceComponent'), icon: r('iconComponent')\n    };\n    const pageSize = Number(p.pageSize) > 0 ? Number(p.pageSize) : 9;\n    const descr = Object.assign({}, DESCR, obj(p.categoryDescriptions));\n\n    // ——— Estado (com valores iniciais vindos dos parâmetros)\n    const selRaw = d2.state.sel || (() => { const s = blankSel(); if (p.category) s.categoria = [String(p.category)]; return s; })();\n    const q = d2.state.q != null ? String(d2.state.q) : String(p.query || '');\n    const sort = d2.state.sort || p.sort || 'relevancia';\n    const pages = d2.state.pages || 1;\n    const ver = String(d2.state.ver || 0);\n    const set = (patch) => {\n      const keep = holdScroll(d2);\n      const base = { sel: d2.state.sel || sel, q: d2.state.q != null ? d2.state.q : q, sort: d2.state.sort || sort, pages: d2.state.pages || pages };\n      const next = Object.assign(base, patch);\n      if (patch.sel || patch.q != null || patch.sort) next.pages = patch.pages || 1;\n      d2.state.sel = next.sel; d2.state.q = next.q; d2.state.sort = next.sort; d2.state.pages = next.pages;\n      d2.state.ver = (d2.state.ver || 0) + 1;\n      writeUrl({ q: next.q, sel: next.sel, sort: next.sort }, CATS);\n      emit(d2, 'onFiltersChange', { query: next.q, sort: next.sort, filters: next.sel });\n      keep();\n    };\n    const toggle = (group, value, on) => {\n      const s = JSON.parse(JSON.stringify(sel));\n      if (group === 'estoque') s.estoque = !!on;\n      else { const arr = s[group] || []; const i = arr.indexOf(value); if (on && i < 0) arr.push(value); if (!on && i >= 0) arr.splice(i, 1); s[group] = arr;\n        if (group === 'categoria' && arr.length && s.subcategoria && s.subcategoria.length) { const okSub = all.filter((x) => arr.indexOf(x.categoria) >= 0).map((x) => x.subcategoria); s.subcategoria = s.subcategoria.filter((v) => okSub.indexOf(v) >= 0); }\n      }\n      set({ sel: s });\n    };\n\n    // ——— Dados\n    const dsRef = d2.param('dataset');\n    const dh = dsRef && d2.data ? d2.data('dataset') : null;\n    const rows = dh && typeof dh.records === 'function' ? dh.records() : null;\n    const rawRows = (rows && rows.length ? rows : (PRODS && PRODS.length ? PRODS : list(p.products)));\n    const catById = {}; (CATS || []).forEach((c) => { catById[String(c._id)] = c.nome; });\n    const catOf = (v) => { if (!CATS) return ''; const id = v && typeof v === 'object' ? (v._id || '') : v; return catById[String(id)] !== undefined ? catById[String(id)] : ''; };\n    const all = rawRows.filter((x) => x && x.ativo !== false && x.ativo !== 'false').map((x) => Object.assign({}, x, { categoria: catOf(x.categoria) })).filter((x) => !CATS || x.categoria);\n    // Valores que vêm da URL (slug) viram o nome da categoria/marca; o que não existe é ignorado\n    const catBySlug = {}; (CATS || []).forEach((c) => { catBySlug[slugify(c.nome)] = c.nome; if (c.slug) catBySlug[slugify(c.slug)] = c.nome; });\n    const catNames = (CATS || []).map((c) => c.nome);\n    const marcaBySlug = {}; all.forEach((x) => { if (x.marca) marcaBySlug[slugify(x.marca)] = x.marca; });\n    const subBySlug = {}; all.forEach((x) => { if (x.subcategoria) subBySlug[slugify(x.subcategoria)] = x.subcategoria; });\n    const sel = Object.assign({}, selRaw, {\n      categoria: selRaw.categoria.map((v) => catBySlug[slugify(v)] || v).filter((v) => !CATS || catNames.indexOf(v) >= 0),\n      marca: selRaw.marca.map((v) => marcaBySlug[slugify(v)] || v).filter((v) => !all.length || all.some((x) => x.marca === v)),\n      subcategoria: (selRaw.subcategoria || []).map((v) => subBySlug[slugify(v)] || v).filter((v) => !all.length || all.some((x) => x.subcategoria === v))\n    });\n    const tokens = fold(q).split(/\\s+/).filter(Boolean);\n    const matchQ = (x) => !tokens.length || tokens.every((t) => fold([x.nome, x.marca, x.categoria, x.subcategoria, x.sku].join(' ')).indexOf(t) >= 0);\n    const base = all.filter(matchQ);\n    const [rMin, rMax] = sel.range ? rangeBounds(sel.range) : [sel.min, sel.max];\n    const pass = (x, skip) => {\n      if (skip !== 'categoria' && sel.categoria.length && sel.categoria.indexOf(x.categoria) < 0) return false;\n      if (skip !== 'subcategoria' && sel.subcategoria.length && sel.subcategoria.indexOf(x.subcategoria) < 0) return false;\n      if (skip !== 'marca' && sel.marca.length && sel.marca.indexOf(x.marca) < 0) return false;\n      if (sel.estoque && !(Number(x.estoque) > 0)) return false;\n      const pr = Number(x.preco) || 0;\n      if (rMin != null && pr < rMin) return false;\n      if (rMax != null && pr > rMax) return false;\n      return true;\n    };\n    const results = base.filter((x) => pass(x));\n    const sorters = {\n      'menor-preco': (a, b) => (a.preco || 0) - (b.preco || 0),\n      'maior-preco': (a, b) => (b.preco || 0) - (a.preco || 0),\n      'mais-vendidos': (a, b) => (b.vendas || 0) - (a.vendas || 0),\n      relevancia: (a, b) => (b.destaque ? 1 : 0) - (a.destaque ? 1 : 0) || (b.vendas || 0) - (a.vendas || 0)\n    };\n    results.sort(sorters[sort] || sorters.relevancia);\n    const total = results.length;\n    const shown = Math.min(total, pageSize * pages);\n    const countLabel = total ? `Mostrando ${shown} de ${total} ${total === 1 ? 'produto' : 'produtos'}` : '';\n    const loading = (dh && dh.loading && !all.length) || (!!CATS_LOADING && !CATS) || (!rawRows.length && !!PRODS_LOADING && !PRODS);\n\n    // ——— Opções dos filtros (contagem sobre a busca, sem o próprio grupo)\n    const facet = (key) => {\n      const counts = {};\n      base.filter((x) => pass(x, key)).forEach((x) => { const v = x[key]; if (v) counts[v] = (counts[v] || 0) + 1; });\n      sel[key].forEach((v) => { if (!(v in counts)) counts[v] = 0; });\n      return Object.keys(counts).sort((a, b) => a.localeCompare(b, 'pt-BR')).map((v) => ({ value: v, label: v, count: counts[v], checked: sel[key].indexOf(v) >= 0 }));\n    };\n    const groups = [\n      { id: 'categoria', title: 'Categoria', options: facet('categoria') },\n      ...(facet('subcategoria').length ? [{ id: 'subcategoria', title: 'Subcategoria', options: facet('subcategoria') }] : []),\n      { id: 'marca', title: 'Marca', options: facet('marca') },\n      { id: 'preco', kind: 'price', title: 'Preço', ranges: RANGES, value: sel.range || '', min: sel.range ? '' : (sel.min == null ? '' : sel.min), max: sel.range ? '' : (sel.max == null ? '' : sel.max) },\n      { id: 'estoque', title: 'Disponibilidade', options: [{ value: 'em-estoque', label: 'Mostrar só produtos em estoque', checked: sel.estoque }] }\n    ];\n    const onGroup = (v) => { if (!v) return; toggle(v.group, v.value, v.checked); };\n    const onPrice = (v) => { const s = JSON.parse(JSON.stringify(sel)); s.range = ''; s.min = v && v.min != null ? v.min : null; s.max = v && v.max != null ? v.max : null; set({ sel: s }); };\n    const onRange = (v) => { const s = JSON.parse(JSON.stringify(sel)); s.range = (v && v.value) || ''; s.min = null; s.max = null; set({ sel: s }); };\n    const clearAll = () => set({ sel: blankSel() });\n\n    // ——— Chips ativos\n    const chips = [];\n    sel.categoria.forEach((v) => chips.push({ id: 'categoria|' + v, label: v }));\n    sel.subcategoria.forEach((v) => chips.push({ id: 'subcategoria|' + v, label: v }));\n    sel.marca.forEach((v) => chips.push({ id: 'marca|' + v, label: v }));\n    if (sel.range) chips.push({ id: 'preco|', label: (RANGES.find((x) => x.value === sel.range) || {}).label || 'Preço' });\n    else if (sel.min != null || sel.max != null) chips.push({ id: 'preco|', label: sel.min != null && sel.max != null ? `${brl(sel.min)} a ${brl(sel.max)}` : (sel.min != null ? `A partir de ${brl(sel.min)}` : `Até ${brl(sel.max)}`) });\n    if (sel.estoque) chips.push({ id: 'estoque|', label: 'Só em estoque' });\n    const removeChip = (id) => {\n      const [g, v] = String(id || '').split('|');\n      const s = JSON.parse(JSON.stringify(sel));\n      if (g === 'preco') { s.range = ''; s.min = null; s.max = null; } else if (g === 'estoque') s.estoque = false; else s[g] = (s[g] || []).filter((x) => x !== v);\n      set({ sel: s });\n    };\n\n    // ——— Cabeçalho (categoria ou busca)\n    const singleCat = sel.categoria.length === 1 ? sel.categoria[0] : '';\n    const head = q\n      ? { eyebrow: 'Busca', title: `Resultados para “${q}”`, description: total ? `${total} ${total === 1 ? 'produto encontrado' : 'produtos encontrados'}.` : '', crumbs: [{ label: 'Início', href: '/' }, { label: 'Busca' }] }\n      : singleCat\n        ? { eyebrow: 'Categoria', title: singleCat, description: descr[singleCat] || '', crumbs: [{ label: 'Início', href: '/' }, { label: singleCat }] }\n        : { eyebrow: 'Loja', title: p.allTitle || 'Todos os produtos', description: p.allDescription || 'Os produtos que aparecem no canal, com a curadoria de quem testa de verdade.', crumbs: [{ label: 'Início', href: '/' }, { label: 'Todos os produtos' }] };\n    const header = R.ph ? d2.render(R.ph, {\n      eyebrow: head.eyebrow, title: head.title, description: head.description, crumbs: head.crumbs, meta: countLabel, showSearch: false, layout, breadcrumb: R.bc\n    }, { key: 'ph-' + ver + '-' + fold(head.title) + '-' + total, style: 'height:auto' }) : '';\n\n    // ——— Card de produto (no tablet a grade tem 3 colunas estreitas: o card usa a versão compacta, com rótulos curtos)\n    const cardLayout = layout === 'desktop' ? 'desktop' : 'mobile';\n    const card = (x, i, prefix) => R.pc ? `<div class=\"cell\" style=\"height:${CARD_H[layout]}px\">${d2.render(R.pc, {\n      name: x.nome, brand: x.subcategoria || x.categoria || '', price: Number(x.preco) || 0, oldPrice: x.precoAntigo ? Number(x.precoAntigo) : undefined,\n      installments: Number(x.parcelas) || 1, href: '/produto/' + (x.slug || ''), sku: x.sku || '', image: x.imagem || '', outOfStock: !(Number(x.estoque) > 0),\n      partner: x.origem === 'parceiro' ? (String(x.marca || '').split(' ')[0] || 'Parceiro') : '', variant: 'outlined', layout: cardLayout,\n      priceComponent: R.price, button: R.btn, badge: R.badge, iconComponent: R.icon\n    }, { key: prefix + (x.sku || i) + '-' + layout, onAdd: (s) => { addToBag(x.sku, 1); emit(d2, 'onAdd', s); }, onNotify: (s) => emit(d2, 'onNotify', s), onOpen: (s) => emit(d2, 'onOpen', s) })}</div>` : '';\n\n    if (loading) return `<div class=\"cat l-${layout}\">${header}<div class=\"in\" style=\"padding:${PAD[layout]}\"></div></div>`;\n\n    // ——— Sem resultado: EmptyState + mais vendidos\n    if (!total) {\n      const empty = R.es ? d2.render(R.es, {\n        query: q, ctaHref: '/lista-de-produtos/q', title: q ? '' : 'Nenhum produto com esses filtros', description: q ? '' : 'Tira um filtro ou dois que a gente acha alguma coisa pra você.',\n        layout, searchBar: R.sb, button: R.btn, iconComponent: R.icon\n      }, {\n        key: 'es-' + ver, style: 'height:auto',\n        onSearch: (v) => set({ q: String(v || ''), sel: blankSel() }), onSuggestion: (v) => set({ q: String(v || ''), sel: blankSel() })\n      }) : '';\n      const best = all.slice().sort(sorters['mais-vendidos']).slice(0, 4);\n      const bestHead = R.sh ? d2.render(R.sh, { eyebrow: 'Enquanto isso', title: 'Os mais vendidos da loja', layout }, { key: 'bh', style: 'height:auto' }) : '';\n      const bestHtml = best.length ? `<section class=\"best\"><div class=\"bin\" style=\"padding:${PAD[layout].replace(/^\\S+/, layout === 'mobile' ? '64px' : layout === 'tablet' ? '88px' : '96px')}\">${bestHead}<div class=\"grid\">${best.map((x, i) => card(x, i, 'b-')).join('')}</div></div></section>` : '';\n      return `<div class=\"cat l-${layout}\">${header}${empty}${bestHtml}</div>`;\n    }\n\n    // ——— Resultados\n    const panel = desk && R.fp ? `<aside class=\"side\" aria-label=\"Filtros\">${d2.render(R.fp, {\n      groups, version: ver + '-' + all.length, layout, filterGroup: R.fg, priceFilter: R.pf, checkbox: R.cb, radio: R.rd, formField: R.ff, iconComponent: R.icon\n    }, { key: 'fp-' + ver + '-' + all.length, style: 'height:auto', onChange: onGroup, onPrice, onRange, onClear: clearAll })}</aside>` : '';\n    const toolbar = R.tb ? d2.render(R.tb, {\n      chips, filterCount: chips.length, countLabel, sortOptions: SORTS, sortValue: sort, layout, filterChip: R.fc, formField: R.ff, iconComponent: R.icon\n    }, {\n      key: 'tb-' + ver + '-' + total, style: 'height:auto',\n      onRemove: removeChip, onClear: clearAll, onSort: (v) => set({ sort: v || 'relevancia' }),\n      onOpenFilters: () => { d2.state.sheet = true; d2.state.ver = (d2.state.ver || 0) + 1; }\n    }) : '';\n    const grid = `<div class=\"grid\">${results.slice(0, shown).map((x, i) => card(x, i, 'r-')).join('')}</div>`;\n    const more = R.lm ? d2.render(R.lm, { countLabel, done: shown >= total, layout, button: R.btn }, { key: 'lm-' + shown + '-' + total, style: 'height:auto', onClick: () => set({ pages: pages + 1 }) }) : '';\n    const closeSheet = () => { d2.state.sheet = false; d2.state.ver = (d2.state.ver || 0) + 1; };\n    const sheet = !desk && d2.state.sheet && R.fs ? d2.render(R.fs, {\n      open: true, groups, sortOptions: SORTS, sortValue: sort, version: ver, layout,\n      filterPanel: R.fp, filterGroup: R.fg, priceFilter: R.pf, checkbox: R.cb, radio: R.rd, formField: R.ff, button: R.btn, iconComponent: R.icon\n    }, {\n      key: 'fs-' + ver, style: 'height:0',\n      onClose: closeSheet, onApply: closeSheet, onClear: clearAll, onChange: onGroup, onPrice, onRange, onSort: (v) => set({ sort: v || 'relevancia' })\n    }) : '';\n\n    return `<div class=\"cat l-${layout}\">${header}\n      <div class=\"in\" style=\"padding:${PAD[layout]}\">${panel}<div class=\"main\">${toolbar}${grid}${more}</div></div>\n      ${sheet}\n    </div>`;\n  }\n};"}},"allDescription":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"allDescription"}}}},"allTitle":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"allTitle"}}}},"badge":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"badge"}}}},"breadcrumb":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"breadcrumb"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"catalogToolbar":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"catalogToolbar"}}}},"category":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"category"}}}},"categoryDescriptions":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"categoryDescriptions"}}}},"checkbox":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkbox"}}}},"dataset":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"dataset"}}}},"emptyState":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"emptyState"}}}},"filterChip":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"filterChip"}}}},"filterGroup":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"filterGroup"}}}},"filterPanel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"filterPanel"}}}},"filterSheet":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"filterSheet"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"loadMore":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"loadMore"}}}},"onAdd":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onAdd"}}}},"onFiltersChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onFiltersChange"}}}},"onNotify":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onNotify"}}}},"onOpen":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onOpen"}}}},"pageHeader":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"pageHeader"}}}},"pageSize":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"pageSize"}}}},"priceComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"priceComponent"}}}},"priceFilter":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"priceFilter"}}}},"productCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"productCard"}}}},"products":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"products"}}}},"query":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"query"}}}},"radio":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"radio"}}}},"searchBar":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"searchBar"}}}},"sectionHeader":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"sectionHeader"}}}},"sort":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"sort"}}}}}}}}}},{"_id":"6abeb166ff933b0688424a3e","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"CartItem","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// CartItem — Loja Lucas Fontana\n// Uma linha da sacola: foto (112/104/84px), categoria em vermelho, nome (link), opção/variação, a quantidade (QuantityStepper\n// pequeno), o total da linha e o botão de lixeira (44px).\n// Desktop: o preço unitário vai na linha da opção (\"· R$ 89,90 cada\"); quantidade e total em colunas próprias.\n// Tablet e mobile: quantidade embaixo do texto e o total à direita, com \"R$ 89,90 cada\" embaixo.\n// `lowStock` mostra o aviso em vermelho (\"Última unidade!\"); `max` limita a quantidade. `partner` adiciona a linha com caminhão\n// (\"Enviado pelo parceiro BPower Motorsport\").\n// `soldOut`: foto apagada com \"Volta já já\", sem quantidade, um traço cinza no lugar do total e o aviso com barra preta\n// \"Esgotou enquanto estava na sua sacola. Esse item não entra no total. **Me avise quando chegar**\". O item continua na lista.\n// Emite `onQuantityChange` (número), `onRemove` e `onNotify`. Usa QuantityStepper, Badge e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.ci { --red-500: #c8102e; --ink: #0b0b0c; --white: #ffffff; --grey-50: #f5f5f3; --grey-100: #ececea; --grey-400: #8e9095; --grey-500: #6b6e73; --grey-700: #45474b; --grey-900: #1c1d1f; --line: #e4e4e2;\n  font-family: ${FF}; -webkit-font-smoothing: antialiased; color: var(--ink);\n  display: grid; grid-template-columns: 112px minmax(0, 1fr) 110px 140px 44px; column-gap: 20px; grid-template-areas: \"img info qty total del\";\n  padding: 24px 0; border-bottom: 1px solid var(--line); align-items: start; }\np { margin: 0; }\n.img { grid-area: img; position: relative; width: 112px; aspect-ratio: 1 / 1; background: var(--grey-100); display: flex; align-items: center; justify-content: center; overflow: hidden; }\n.img img { width: 100%; height: 100%; object-fit: cover; }\n.ph { font-size: 9px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--grey-500); }\n.badge { position: absolute; top: 6px; left: 6px; height: 18px; }\n.so .img > img, .so .img > .ph { opacity: .55; }\n.info { grid-area: info; display: flex; flex-direction: column; align-items: flex-start; gap: 6px; min-width: 0; }\n.cat { font-size: 10px; font-weight: 800; letter-spacing: .2em; text-transform: uppercase; color: var(--red-500); }\n.name { font-size: 16px; font-weight: 700; line-height: 1.3; }\n.name a { color: inherit; text-decoration: none; }\n.name a:hover { color: var(--red-500); }\n.name a:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }\n.meta { font-size: 13px; line-height: 1.4; color: var(--grey-700); }\n.low { font-size: 13px; font-weight: 700; color: var(--red-500); }\n.partner { margin-top: 2px; display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--grey-700); }\n.notice { margin-top: 8px; align-self: stretch; display: flex; flex-direction: column; gap: 4px; padding: 13px 16px 13px 18px; border-left: 4px solid var(--ink); background: var(--grey-50); font-size: 13px; line-height: 1.45; color: var(--grey-900); }\n.notice a { color: var(--ink); font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }\n.notice a:hover { color: var(--red-500); }\n.so .info { grid-column: 2 / 4; }\n.qtyc { grid-area: qty; display: flex; justify-content: center; }\n.qtyc > * { width: 110px; height: 44px; }\n.total { grid-area: total; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; padding-top: 4px; text-align: right; }\n.total b { font-size: 18px; font-weight: 800; font-stretch: 110%; line-height: 1.1; white-space: nowrap; }\n.unit { display: none; font-size: 12px; color: var(--grey-700); white-space: nowrap; }\n.dash { display: block; width: 28px; height: 3px; margin: 10px 0; background: var(--grey-400); }\n.del { grid-area: del; justify-self: end; width: 44px; height: 44px; margin: -4px 0 0; padding: 0; border: 0; background: transparent; color: var(--ink); display: flex; align-items: center; justify-content: center; cursor: pointer; }\n.del:hover { color: var(--red-500); }\n.del:focus-visible { outline: 2px solid var(--red-500); outline-offset: -2px; }\n\n.l-tablet, .l-mobile { grid-template-columns: 104px auto minmax(0, 1fr) 44px; column-gap: 14px; row-gap: 12px; padding: 20px 0;\n  grid-template-areas: \"img info info del\" \"img qty total total\"; }\n.l-tablet .img, .l-mobile .img { width: 104px; grid-row: 1 / 3; align-self: start; }\n.l-tablet .info, .l-mobile .info, .l-tablet.so .info, .l-mobile.so .info { gap: 4px; grid-column: 2 / 5; grid-row: 1; }\n.l-tablet .name, .l-mobile .name { font-size: 14px; }\n.l-tablet .del, .l-mobile .del { grid-column: 4; grid-row: 1; position: relative; z-index: 1; margin: -10px -10px 0 0; }\n.l-tablet .cat, .l-mobile .cat, .l-tablet .name, .l-mobile .name { padding-right: 36px; }\n.l-tablet .unit-inline, .l-mobile .unit-inline { display: none; }\n.l-tablet .unit, .l-mobile .unit { display: block; }\n.l-tablet .notice, .l-mobile .notice { margin-top: 6px; }\n.l-tablet .qtyc, .l-mobile .qtyc { justify-content: flex-start; }\n.l-tablet.so .qtyc, .l-mobile.so .qtyc { display: none; }\n.l-tablet.so .total, .l-mobile.so .total { grid-column: 2 / 5; }\n.l-tablet .total, .l-mobile .total { align-self: end; padding-top: 0; }\n.l-tablet .dash, .l-mobile .dash { margin: 4px 0 8px; width: 20px; }\n.l-mobile { grid-template-columns: 84px auto minmax(0, 1fr) 44px; }\n.l-mobile .img { width: 84px; }\n.l-mobile .badge { top: 4px; left: 4px; height: 16px; }\n.l-mobile .partner { font-size: 12px; align-items: flex-start; }\n.l-mobile .notice { padding: 12px 14px; }\n`,\n\n  mounted(d2) {\n    d2.on('.del', 'click', () => emit(d2, 'onRemove', (d2.params || {}).sku || true));\n    d2.on('.notice a', 'click', (e) => { if (!(d2.params || {}).notifyHref) e.preventDefault(); emit(d2, 'onNotify', (d2.params || {}).sku || true); });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const R = { qs: refOf(d2.param('quantityStepper')), badge: refOf(d2.param('badge')), icon: refOf(d2.param('iconComponent')) };\n    const so = truthy(p.soldOut);\n    const low = p.lowStock === true || p.lowStock === 'true' ? 'Última unidade!' : (p.lowStock || '');\n    const name = esc(p.name || '[Nome do produto]');\n    const unit = p.unitPrice ? esc(p.unitPrice) : '';\n    const img = p.image ? `<img src=\"${esc(p.image)}\" alt=\"\">` : '<span class=\"ph\">Foto</span>';\n    const badge = so && R.badge ? `<span class=\"badge\">${d2.render(R.badge, { label: p.soldOutLabel || 'Volta já já', isStatus: true, tone: 'ink', layout: 'mobile' }, { key: 'b', width: 'auto', height: 18 })}</span>` : '';\n    const truck = R.icon ? d2.render(R.icon, { name: 'truck', size: 15, iconColor: '#45474b' }, { key: 'tr', width: 15, height: 15 }) : '';\n    const trash = R.icon ? d2.render(R.icon, { name: 'trash', size: 20, iconColor: 'currentColor' }, { key: 'del', width: 20, height: 20 }) : '×';\n    const qty = !so && R.qs ? `<div class=\"qtyc\">${d2.render(R.qs, { size: 'sm', value: Number(p.quantity) || 1, min: 1, max: Number(p.max) > 0 ? Number(p.max) : 99, ariaLabel: 'Quantidade de ' + (p.name || 'produto'), iconComponent: R.icon, layout }, {\n      key: 'q-' + (Number(p.quantity) || 1) + '-' + (p.max || ''), onChange: (v) => emit(d2, 'onQuantityChange', v)\n    })}</div>` : '<div class=\"qtyc\"></div>';\n    const meta = p.meta || unit ? `<p class=\"meta\">${esc(p.meta || '')}${unit ? `<span class=\"unit-inline\">${p.meta ? ' · ' : ''}${unit} cada</span>` : ''}</p>` : '';\n    const notice = so ? `<div class=\"notice\" role=\"status\"><b>${esc(p.soldOutTitle || 'Esgotou enquanto estava na sua sacola.')}</b><span>${esc(p.soldOutText || 'Esse item não entra no total.')} <a href=\"${esc(p.notifyHref || '#')}\">${esc(p.notifyLabel || 'Me avise quando chegar')}</a></span></div>` : '';\n    return `<div class=\"ci l-${layout}${so ? ' so' : ''}\">\n      <div class=\"img\">${img}${badge}</div>\n      <div class=\"info\">\n        ${p.category ? `<span class=\"cat\">${esc(p.category)}</span>` : ''}\n        <p class=\"name\">${p.href ? `<a href=\"${esc(p.href)}\">${name}</a>` : name}</p>\n        ${meta}\n        ${low && !so ? `<p class=\"low\">${esc(low)}</p>` : ''}\n        ${p.partner ? `<div class=\"partner\">${truck}<span>${esc(typeof p.partner === 'string' && p.partner !== 'true' ? p.partner : 'Enviado pelo parceiro')}</span></div>` : ''}\n        ${notice}\n      </div>\n      ${qty}\n      <div class=\"total\">${so ? '<span class=\"dash\" role=\"img\" aria-label=\"Fora do total\"></span>' : `<b>${esc(p.total || '')}</b>`}${unit ? `<span class=\"unit\">${unit} cada</span>` : ''}</div>\n      <button type=\"button\" class=\"del\" aria-label=\"Remover ${name} da sacola\">${trash}</button>\n    </div>`;\n  }\n};"}},"badge":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"badge"}}}},"category":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"category"}}}},"href":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"href"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"image":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"image"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"lowStock":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"lowStock"}}}},"max":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"max"}}}},"meta":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"meta"}}}},"name":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"name"}}}},"notifyHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notifyHref"}}}},"notifyLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notifyLabel"}}}},"onNotify":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onNotify"}}}},"onQuantityChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onQuantityChange"}}}},"onRemove":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onRemove"}}}},"partner":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"partner"}}}},"quantity":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"quantity"}}}},"quantityStepper":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"quantityStepper"}}}},"sku":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"sku"}}}},"soldOut":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"soldOut"}}}},"soldOutLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"soldOutLabel"}}}},"soldOutText":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"soldOutText"}}}},"soldOutTitle":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"soldOutTitle"}}}},"total":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"total"}}}},"unitPrice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"unitPrice"}}}}}}}}}},{"_id":"6abeb197a554b79571c1b7b6","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"CartList","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// CartList — Loja Lucas Fontana\n// Os itens da sacola sob uma régua preta de 2px. No desktop, uma linha de cabeçalho (Produto · Quantidade · Total) alinhada\n// com a grade dos itens; abaixo de 1200px o cabeçalho some e cada item empilha.\n// Os itens chegam por `items` (parâmetros do CartItem, com `sku`). `headers: false` esconde o cabeçalho.\n// Emite `onQuantityChange` {sku, quantity}, `onRemove` (sku) e `onNotify` (sku). Usa CartItem (e repassa QuantityStepper, Badge e Icon).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => { if (Array.isArray(v)) return v; if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } } return []; };\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst DEMO = [\n  { sku: 'demo-1', category: 'Lavagem', name: 'Shampoo automotivo neutro', unitPrice: 'R$ 89,90', total: 'R$ 179,80', quantity: 2 },\n  { sku: 'demo-2', category: 'Performance', name: '[Nome do produto BPower]', unitPrice: 'R$ 2.500,00', total: 'R$ 2.500,00', quantity: 1, partner: 'Enviado pelo parceiro BPower Motorsport' },\n  { sku: 'demo-3', category: 'Proteção', name: 'Cera líquida de acabamento', unitPrice: 'R$ 119,90', soldOut: true }\n];\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.cl { border-top: 2px solid #0b0b0c; font-family: ${FF}; -webkit-font-smoothing: antialiased; }\n.cols { display: grid; grid-template-columns: 112px minmax(0, 1fr) 110px 140px 44px; column-gap: 20px; padding: 13px 0 12px; border-bottom: 1px solid #e4e4e2;\n  font-size: 10px; font-weight: 800; letter-spacing: .2em; text-transform: uppercase; color: #0b0b0c; }\n.cols > span:first-child { grid-column: 1 / 3; }\n.cols > span:nth-child(2) { text-align: center; }\n.cols > span:nth-child(3) { text-align: right; }\nul { list-style: none; margin: 0; padding: 0; }\n.l-tablet .cols, .l-mobile .cols { display: none; }\n`,\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const R = { ci: refOf(d2.param('cartItem')), qs: refOf(d2.param('quantityStepper')), badge: refOf(d2.param('badge')), icon: refOf(d2.param('iconComponent')) };\n    const items = list(p.items).length ? list(p.items) : (p.items === '' || p.showDemo === false ? [] : DEMO);\n    const ver = p.version == null ? '' : String(p.version);\n    const rows = items.map((it, i) => R.ci ? `<li>${d2.render(R.ci, Object.assign({}, it, { layout, quantityStepper: R.qs, badge: R.badge, iconComponent: R.icon }), {\n      key: 'i-' + (it.sku || i) + '-' + ver + '-' + (it.quantity || 0) + (it.soldOut ? '-so' : ''), style: 'height:auto',\n      onQuantityChange: (v) => emit(d2, 'onQuantityChange', { sku: it.sku, quantity: v }),\n      onRemove: () => emit(d2, 'onRemove', it.sku), onNotify: () => emit(d2, 'onNotify', it.sku)\n    })}</li>` : '').join('');\n    return `<div class=\"cl l-${layout}\">\n      ${p.headers === false || p.headers === 'false' ? '' : '<div class=\"cols\" aria-hidden=\"true\"><span>Produto</span><span>Quantidade</span><span>Total</span><span></span></div>'}\n      <ul aria-label=\"${esc(p.ariaLabel || 'Itens na sacola')}\">${rows}</ul>\n    </div>`;\n  }\n};"}},"ariaLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"ariaLabel"}}}},"badge":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"badge"}}}},"cartItem":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"cartItem"}}}},"headers":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"headers"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"items":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"items"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onNotify":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onNotify"}}}},"onQuantityChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onQuantityChange"}}}},"onRemove":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onRemove"}}}},"quantityStepper":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"quantityStepper"}}}},"showDemo":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"showDemo"}}}},"version":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"version"}}}}}}}}}},{"_id":"6abeb1ac1b1a6d54b50b3e04","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"ShippingCalculator","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// ShippingCalculator — Loja Lucas Fontana\n// A linha \"Frete\" do resumo da sacola: o valor à direita (\"Informe o CEP\" em cinza antes de calcular), o campo de CEP\n// (máscara 00000-000, 44px) e o botão de contorno \"Calcular\". Embaixo, a nota de 12px em cinza\n// (\"Itens BPower são enviados pelo parceiro, com frete e rastreio próprios.\") ou o erro em vermelho.\n// Emite `onCalculate` com o CEP (8 números). Enquanto o frete não estiver integrado (V2), a sacola mostra\n// \"Calculado no checkout\" como `value` depois de calcular.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst fmt = (v) => { const d = String(v || '').replace(/\\D/g, '').slice(0, 8); return d.length > 5 ? d.slice(0, 5) + '-' + d.slice(5) : d; };\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.sc { display: flex; flex-direction: column; gap: 10px; font-family: ${FF}; -webkit-font-smoothing: antialiased; }\n.row { display: flex; justify-content: space-between; gap: 12px; padding: 4px 0; font-size: 14px; color: #45474b; }\n.row span.v { color: #0b0b0c; font-weight: 700; font-size: 13px; }\n.row span.muted { color: #6b6e73; font-weight: 400; font-size: 14px; }\nform { display: flex; gap: 12px; margin: 0; }\ninput { flex: 1; min-width: 0; height: 44px; padding: 0 16px; border: 1px solid #d9d9d6; border-radius: 2px; background: #ffffff; font: 400 16px ${FF}; color: #0b0b0c; outline: none; }\ninput::placeholder { color: #6b6e73; }\ninput:focus { border-color: #0b0b0c; box-shadow: 0 0 0 1px #0b0b0c; }\ninput.bad { border-color: #c8102e; }\nbutton { flex: none; height: 44px; margin: 0; padding: 0 22px; border: 2px solid #0b0b0c; border-radius: 0; background: transparent; font: 800 12px/1 ${FF}; letter-spacing: .12em; text-transform: uppercase; color: #0b0b0c; cursor: pointer; }\nbutton:hover { background: #0b0b0c; color: #ffffff; }\nbutton:focus-visible { outline: 2px solid #c8102e; outline-offset: 2px; }\np { margin: 0; font-size: 12px; line-height: 1.5; color: #45474b; }\np.err { color: #c8102e; font-weight: 600; }\n.l-mobile form { gap: 8px; }\n.l-mobile input { padding: 0 12px; }\n.l-mobile button { padding: 0 16px; }\n`,\n  mounted(d2) {\n    d2.on('input', 'input', (e, el) => { const v = fmt(el.value); if (v !== el.value) el.value = v; if (d2.root) d2.root.__cep = v; });\n    d2.on('form', 'submit', (e) => { e.preventDefault(); const v = String((d2.root && d2.root.__cep) || (d2.$('input') || {}).value || '').replace(/\\D/g, ''); emit(d2, 'onCalculate', v); });\n  },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const val = p.value ? String(p.value) : '';\n    const zip = fmt((d2.root && d2.root.__cep) || p.defaultZip || '');\n    const note = p.note == null ? 'Itens BPower são enviados pelo parceiro, com frete e rastreio próprios.' : String(p.note);\n    return `<div class=\"sc l-${layout}\">\n      <div class=\"row\"><label for=\"cep\">${esc(p.label || 'Frete')}</label><span class=\"${val ? 'v' : 'muted'}\">${esc(val || p.emptyLabel || 'Informe o CEP')}</span></div>\n      <form novalidate><input id=\"cep\" class=\"${p.error ? 'bad' : ''}\" inputmode=\"numeric\" autocomplete=\"postal-code\" placeholder=\"${esc(p.placeholder || '00000-000')}\" value=\"${esc(zip)}\"${p.error ? ' aria-invalid=\"true\"' : ''}><button type=\"submit\">${esc(p.submitLabel || 'Calcular')}</button></form>\n      ${p.error ? `<p class=\"err\" role=\"alert\">${esc(p.error)}</p>` : ''}\n      ${note ? `<p>${esc(note)}</p>` : ''}\n    </div>`;\n  }\n};"}},"defaultZip":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"defaultZip"}}}},"emptyLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"emptyLabel"}}}},"error":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"error"}}}},"label":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"label"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"note":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"note"}}}},"onCalculate":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCalculate"}}}},"placeholder":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"placeholder"}}}},"submitLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"submitLabel"}}}},"value":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"value"}}}}}}}}}},{"_id":"6abeb1c88f48bcd64453d2b9","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"CartSummary","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// CartSummary — Loja Lucas Fontana\n// O resumo cinza da sacola: \"RESUMO DA SACOLA\", subtotal com a quantidade de itens, a ShippingCalculator, o total (28px, largo)\n// com \"R$ X no Pix · ou em até Nx de R$ Y no cartão\", o vermelho \"Finalizar compra\" (56px, com seta), \"Continuar comprando\"\n// e duas linhas de confiança (Mercado Pago; conta só na próxima etapa, a sacola fica salva).\n// \"Finalizar compra\" é o único botão vermelho da página. `checkoutDisabled` desativa (ex.: sacola só com itens esgotados).\n// `shipping` recebe os parâmetros da ShippingCalculator (ou `false` para esconder); `rows` [[rótulo, valor]] adiciona linhas.\n// Emite `onCheckout` e `onCalculate` (CEP). Usa ShippingCalculator, Button e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst truthy = (v) => v === true || v === 'true' || v === 1 || v === '1';\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => { if (Array.isArray(v)) return v; if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } } return []; };\nconst obj = (v) => { if (v && typeof v === 'object' && !Array.isArray(v)) return v; if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return j && typeof j === 'object' ? j : {}; } catch (e) { return {}; } } return {}; };\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst TRUST = [{ icon: 'lock', text: 'Pagamento seguro pelo Mercado Pago: Pix ou cartão.' }, { icon: 'user', text: 'Você entra ou cria sua conta só na próxima etapa. A sacola fica salva.' }];\nconst itemsLabel = (n) => n + (Number(n) === 1 ? ' item' : ' itens');\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\nsection { display: flex; flex-direction: column; padding: 32px 28px; background: #f5f5f3; font-family: ${FF}; -webkit-font-smoothing: antialiased; color: #0b0b0c; }\nh2 { margin: 0 0 14px; font-size: 12px; font-weight: 800; letter-spacing: .2em; text-transform: uppercase; }\n.row { display: flex; justify-content: space-between; gap: 12px; padding: 4px 0; font-size: 14px; color: #45474b; }\n.row b { color: #0b0b0c; font-weight: 700; font-size: 13px; }\n.ship { margin-top: 8px; }\n.tot { margin: 22px 0; padding-top: 22px; border-top: 1px solid #d9d9d6; display: flex; flex-direction: column; gap: 10px; }\n.tr { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }\n.tr span { font-size: 16px; font-weight: 800; }\n.tr b { font-size: 28px; font-weight: 800; font-stretch: 110%; line-height: 1; white-space: nowrap; }\n.tot p { margin: 0; font-size: 13px; line-height: 1.5; color: #45474b; text-align: right; }\n.cta { height: 56px; }\n.cont { align-self: center; display: inline-flex; align-items: center; min-height: 44px; margin-top: 12px; font-size: 14px; font-weight: 700; color: #0b0b0c; text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1.5px; }\n.cont:hover { color: #c8102e; }\n.cont:focus-visible { outline: 2px solid #c8102e; outline-offset: 2px; }\nul { list-style: none; margin: 12px 0 0; padding: 20px 0 0; border-top: 1px solid #d9d9d6; display: flex; flex-direction: column; gap: 12px; }\nli { display: flex; gap: 12px; align-items: flex-start; font-size: 13px; line-height: 1.5; color: #45474b; }\nli .i { flex: none; display: flex; }\n.l-mobile { padding: 28px 20px; }\n.l-mobile .cta { height: 52px; }\n`,\n  mounted(d2) { d2.on('.cont', 'click', (e, el) => emit(d2, 'onContinue', el.getAttribute('href'))); },\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const R = { sc: refOf(d2.param('shippingCalculator')), btn: refOf(d2.param('button')), icon: refOf(d2.param('iconComponent')) };\n    const trust = p.trust === false || p.trust === 'false' ? [] : (list(p.trust).length ? list(p.trust) : TRUST);\n    const rows = list(p.rows);\n    const count = p.count == null || p.count === '' ? null : Number(p.count);\n    const ship = p.shipping === false || p.shipping === 'false' ? null : obj(p.shipping);\n    const ver = p.version == null ? '' : String(p.version);\n    const shipHtml = ship && R.sc ? `<div class=\"ship\">${d2.render(R.sc, Object.assign({}, ship, { layout }), { key: 'sc-' + (ship.value || '') + (ship.error || '') + ver, style: 'height:auto', onCalculate: (v) => emit(d2, 'onCalculate', v) })}</div>` : '';\n    const cta = R.btn ? `<div class=\"cta\">${d2.render(R.btn, { label: p.checkoutLabel || 'Finalizar compra', variant: 'brand', size: 'lg', fullWidth: 'always', arrow: true, href: p.checkoutHref || '', isDisabled: truthy(p.checkoutDisabled), layout }, {\n      key: 'cta-' + (truthy(p.checkoutDisabled) ? 'd' : 'e'), height: layout === 'mobile' ? 52 : 56, onClick: () => emit(d2, 'onCheckout', true)\n    })}</div>` : '';\n    const pix = p.pixTotal ? esc(p.pixTotal) + ' no Pix' : '';\n    const inst = p.installments ? 'ou em até ' + esc(p.installments) + ' no cartão' : '';\n    return `<section class=\"l-${layout}\" aria-label=\"${esc(p.title || 'Resumo da sacola')}\">\n      <h2>${esc(p.title || 'Resumo da sacola')}</h2>\n      <div class=\"row\"><span>Subtotal${count != null ? ' (' + itemsLabel(count) + ')' : ''}</span><b>${esc(p.subtotal || 'R$ 0,00')}</b></div>\n      ${rows.map((r) => `<div class=\"row\"><span>${esc(r[0])}</span><span>${esc(r[1])}</span></div>`).join('')}\n      ${shipHtml}\n      <div class=\"tot\"><div class=\"tr\"><span>Total</span><b>${esc(p.total || 'R$ 0,00')}</b></div>${pix || inst ? `<p>${pix}${pix && inst ? ' · ' : ''}${inst}</p>` : ''}</div>\n      ${cta}\n      ${p.continueHref === false || p.continueHref === 'false' ? '' : `<a class=\"cont\" href=\"${esc(p.continueHref || '/produtos')}\">${esc(p.continueLabel || 'Continuar comprando')}</a>`}\n      ${trust.length ? `<ul>${trust.map((t, i) => `<li><span class=\"i\">${R.icon ? d2.render(R.icon, { name: t.icon || 'check', size: 18, iconColor: '#0b0b0c' }, { key: 't' + i, width: 18, height: 18 }) : ''}</span><span>${esc(t.text)}</span></li>`).join('')}</ul>` : ''}\n    </section>`;\n  }\n};"}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"checkoutDisabled":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkoutDisabled"}}}},"checkoutHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkoutHref"}}}},"checkoutLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkoutLabel"}}}},"continueHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"continueHref"}}}},"continueLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"continueLabel"}}}},"count":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"count"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"installments":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"installments"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onCalculate":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCalculate"}}}},"onCheckout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCheckout"}}}},"onContinue":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onContinue"}}}},"pixTotal":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"pixTotal"}}}},"rows":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"rows"}}}},"shipping":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"shipping"}}}},"shippingCalculator":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"shippingCalculator"}}}},"subtotal":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"subtotal"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}},"total":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"total"}}}},"trust":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"trust"}}}},"version":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"version"}}}}}}}}}},{"_id":"6ac3c2582677f59ea4da65a1","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"CartLayout","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// CartLayout — Loja Lucas Fontana\n// O corpo da página da SACOLA: breadcrumb, o título \"SUA SACOLA\" (44/36/30px) com a contagem de itens em cinza ao lado,\n// a lista (CartList) e, no desktop, o resumo (CartSummary) numa coluna fixa de 400px presa na rolagem. Abaixo de 1200px\n// o resumo desce para baixo da lista, na largura toda. Depois, a faixa cinza \"+ Aproveita e leva / Leva junto que combina\"\n// com 4 ProductCards com contorno. Sacola vazia: o EmptyState (\"Sua sacola está vazia\") no lugar da lista e do resumo.\n// Onde a sacola fica: no navegador da pessoa (localStorage `lf-sacola`, uma lista de {sku, qty}), sem precisar de login.\n// Qualquer página adiciona itens gravando nessa mesma chave (e avisando com o evento `lf-sacola` no window).\n// Os dados de cada item (nome, foto, preço, estoque, parceiro) vêm SEMPRE da tabela Produtos (`dataset`): a sacola nunca mostra\n// preço velho, limita a quantidade ao estoque, mostra \"Última unidade!\" e trata o item que esgotou (fica na lista, fora do total).\n// Frete (V2): \"Calcular\" emite `onCalculate` com o CEP e a linha passa a \"Calculado no checkout\".\n// `demoItems` [{sku, qty}] preenche a sacola só quando ela está vazia — use apenas para revisar o layout; tire antes de publicar.\n// Usa Breadcrumb, CartList, CartItem, CartSummary, ShippingCalculator, QuantityStepper, EmptyState, SearchBar, SectionHeader,\n// ProductCard, Price, Badge, Button e Icon por parâmetro.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => { if (Array.isArray(v)) return v; if (typeof v === 'string' && v.trim()) { try { const j = JSON.parse(v); return Array.isArray(j) ? j : []; } catch (e) { return []; } } return []; };\nconst emit = (d2, evt, v) => { try { d2.emit(evt, v); } catch (err) { /* sem handler */ } };\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst brl = (n) => 'R$ ' + Number(n || 0).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 });\nconst PAD = { desktop: '32px 96px 104px', tablet: '28px 40px 72px', mobile: '20px 20px 48px' };\nconst REL_PAD = { desktop: '96px 96px', tablet: '72px 40px', mobile: '56px 20px' };\nconst CARD_H = { desktop: 500, tablet: 470, mobile: 384 };\nconst KEY = 'lf-sacola';\nconst readBag = (k) => { try { const v = JSON.parse(localStorage.getItem(k) || '[]'); return Array.isArray(v) ? v.filter((x) => x && x.sku) : []; } catch (e) { return []; } };\nconst writeBag = (k, bag) => {\n  try { localStorage.setItem(k, JSON.stringify(bag)); } catch (e) { /* sem storage */ }\n  try { window.dispatchEvent(new CustomEvent('lf-sacola', { detail: { count: bag.reduce((s, x) => s + (Number(x.qty) || 0), 0) } })); } catch (e) { /* sem window */ }\n};\nconst itemsLabel = (n) => n + (Number(n) === 1 ? ' item' : ' itens');\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.cart { width: 100%; background: #ffffff; color: #0b0b0c; font-family: ${FF}; -webkit-font-smoothing: antialiased; }\n.in { display: flex; flex-direction: column; gap: 16px; }\n.crumb { height: 24px; }\n.head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 16px; margin-bottom: 24px; }\nh1 { margin: 0; font-size: 44px; font-weight: 800; font-stretch: 115%; line-height: 1; letter-spacing: -.01em; text-transform: uppercase; }\n.count { font-size: 15px; color: #6b6e73; }\n.grid { display: grid; grid-template-columns: minmax(0, 1fr) 400px; gap: 48px; align-items: start; }\n.aside { position: sticky; top: 24px; }\n.rel { background: #f5f5f3; }\n.rel .rin { display: flex; flex-direction: column; gap: 40px; }\n.rel .cards { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 20px; }\n.l-tablet .in { gap: 14px; } .l-tablet .head { margin-bottom: 20px; } .l-tablet h1 { font-size: 36px; }\n.l-tablet .grid, .l-mobile .grid { grid-template-columns: minmax(0, 1fr); gap: 24px; }\n.l-tablet .aside, .l-mobile .aside { position: static; }\n.l-tablet .rel .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }\n.l-mobile .in { gap: 12px; } .l-mobile .head { margin-bottom: 16px; gap: 4px 12px; }\n.l-mobile h1 { font-size: 30px; font-stretch: 112%; letter-spacing: 0; } .l-mobile .count { font-size: 14px; }\n.l-mobile .crumb { height: 30px; }\n.l-mobile .rel .rin { gap: 24px; }\n.l-mobile .rel .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }\n`,\n\n  mounted(d2) {\n    try { const dh = d2.param('dataset') && d2.data ? d2.data('dataset') : null; if (dh && typeof dh.loadAll === 'function') dh.loadAll(); } catch (e) { /* sem DataSet */ }\n    const p = d2.params || {};\n    const k = p.storageKey || KEY;\n    let bag = readBag(k);\n    if (!bag.length && list(p.demoItems).length) { bag = list(p.demoItems).map((x) => ({ sku: x.sku, qty: Number(x.qty) || 1 })); writeBag(k, bag); }\n    d2.state.bag = bag;\n    try { d2.state.cep = localStorage.getItem('lf-cep') || ''; } catch (e) { /* sem storage */ }\n    // Outra aba ou página mexeu na sacola\n    const onStorage = (e) => { if (!e || e.key === k) { d2.state.ver = (d2.state.ver || 0) + 1; d2.state.bag = readBag(k); } };\n    const onBag = () => { const b = readBag(k); if (JSON.stringify(b) !== JSON.stringify(d2.state.bag || [])) { d2.state.ver = (d2.state.ver || 0) + 1; d2.state.bag = b; } };\n    window.addEventListener('storage', onStorage); window.addEventListener('lf-sacola', onBag);\n    d2.onUnmount(() => { window.removeEventListener('storage', onStorage); window.removeEventListener('lf-sacola', onBag); });\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const r = (n) => refOf(d2.param(n));\n    const R = { bc: r('breadcrumb'), cl: r('cartList'), ci: r('cartItem'), cs: r('cartSummary'), sc: r('shippingCalculator'), qs: r('quantityStepper'),\n      es: r('emptyState'), sb: r('searchBar'), sh: r('sectionHeader'), pc: r('productCard'), price: r('priceComponent'), badge: r('badge'), btn: r('button'), icon: r('iconComponent') };\n    const k = p.storageKey || KEY;\n    const bag = d2.state.bag || [];\n    const save = (next) => { d2.state.ver = (d2.state.ver || 0) + 1; d2.state.bag = next; writeBag(k, next); emit(d2, 'onChange', next); };\n\n    // ——— Dados atuais dos produtos\n    const dh = d2.param('dataset') && d2.data ? d2.data('dataset') : null;\n    const rows = dh && typeof dh.records === 'function' ? dh.records() : [];\n    const loading = dh && dh.loading && !rows.length && bag.length;\n    const bySku = {}; rows.forEach((x) => { if (x && x.sku) bySku[x.sku] = x; });\n\n    const items = bag.map((b) => {\n      const x = bySku[b.sku];\n      if (!x) return null;\n      const stock = Number(x.estoque) || 0;\n      const soldOut = stock <= 0 || x.ativo === false || x.ativo === 'false';\n      const qty = soldOut ? Number(b.qty) || 1 : Math.max(1, Math.min(Number(b.qty) || 1, stock));\n      const unit = Number(x.preco) || 0;\n      return {\n        sku: x.sku, category: x.subcategoria || x.categoria || '', name: x.nome, href: '/p/' + (x.slug || ''), image: x.imagem || '',\n        unitPrice: brl(unit), total: brl(unit * qty), quantity: qty, max: stock || 1, soldOut,\n        lowStock: soldOut ? '' : (stock === 1 ? 'Última unidade!' : (stock <= 3 ? `Restam só ${stock} unidades` : '')),\n        partner: x.origem === 'parceiro' ? 'Enviado pelo parceiro ' + (x.marca || '') : '', _unit: unit, _parc: Number(x.parcelas) || 1\n      };\n    }).filter(Boolean);\n    const live = items.filter((i) => !i.soldOut);\n    const count = live.reduce((s, i) => s + i.quantity, 0);\n    const subtotal = live.reduce((s, i) => s + i._unit * i.quantity, 0);\n    const pixPct = Number(p.pixDiscount) >= 0 && p.pixDiscount !== '' && p.pixDiscount != null ? Number(p.pixDiscount) : 10;\n    const parc = live.reduce((m, i) => Math.max(m, i._parc), 1);\n    const ver = String(d2.state.ver || 0);\n\n    const crumbs = R.bc ? `<div class=\"crumb\">${d2.render(R.bc, { items: [{ label: 'Início', href: '/' }, { label: 'Sacola' }], layout, scroll: layout === 'mobile' }, { key: 'bc' })}</div>` : '';\n    const head = `<div class=\"head\"><h1>${esc(p.title || 'Sua sacola')}</h1>${items.length ? `<span class=\"count\">${itemsLabel(count)}</span>` : ''}</div>`;\n\n    // ——— Faixa \"Leva junto que combina\"\n    const card = (x, i) => R.pc ? `<div style=\"height:${CARD_H[layout]}px\">${d2.render(R.pc, {\n      name: x.nome, brand: x.subcategoria || x.categoria || '', price: Number(x.preco) || 0, oldPrice: x.precoAntigo ? Number(x.precoAntigo) : undefined,\n      installments: Number(x.parcelas) || 1, href: '/p/' + (x.slug || ''), sku: x.sku, image: x.imagem || '', outOfStock: !(Number(x.estoque) > 0),\n      partner: x.origem === 'parceiro' ? (String(x.marca || '').split(' ')[0] || 'Parceiro') : '', variant: 'outlined', layout: layout === 'desktop' ? 'desktop' : 'mobile',\n      priceComponent: R.price, button: R.btn, badge: R.badge, iconComponent: R.icon\n    }, {\n      key: 'rel-' + x.sku + '-' + layout,\n      onAdd: () => { const b = (d2.state.bag || []).slice(); const f = b.find((y) => y.sku === x.sku); if (f) f.qty = (Number(f.qty) || 0) + 1; else b.push({ sku: x.sku, qty: 1 }); save(b); emit(d2, 'onAdd', x.sku); },\n      onNotify: () => emit(d2, 'onNotify', x.sku)\n    })}</div>` : '';\n    const inBag = {}; bag.forEach((b) => { inBag[b.sku] = 1; });\n    const related = rows.filter((x) => x && x.ativo !== false && x.ativo !== 'false' && !inBag[x.sku] && Number(x.estoque) > 0)\n      .sort((a, b) => (b.vendas || 0) - (a.vendas || 0)).slice(0, 4);\n    const relHead = R.sh ? d2.render(R.sh, { number: '+', eyebrow: p.relatedEyebrow || 'Aproveita e leva', title: p.relatedTitle || 'Leva junto que combina', layout }, { key: 'rh', style: 'height:auto' }) : '';\n    const relHtml = related.length && p.showRelated !== false && p.showRelated !== 'false'\n      ? `<section class=\"rel\"><div class=\"rin\" style=\"padding:${REL_PAD[layout]}\">${relHead}<div class=\"cards\">${related.map(card).join('')}</div></div></section>` : '';\n\n    if (loading) return `<div class=\"cart l-${layout}\"><div class=\"in\" style=\"padding:${PAD[layout]}\">${crumbs}${head}</div></div>`;\n\n    // ——— Sacola vazia\n    if (!items.length) {\n      const empty = R.es ? d2.render(R.es, {\n        iconName: 'bag', eyebrow: 'Sacola', title: 'Sua sacola está vazia', description: p.emptyDescription || 'Bora encher? Os produtos que aparecem no canal estão a um clique.',\n        suggestionsLabel: 'Procurando algo?', ctaLabel: 'Ver todos os produtos', ctaHref: p.continueHref || '/produtos', layout, searchBar: R.sb, button: R.btn, iconComponent: R.icon\n      }, {\n        key: 'empty', style: 'height:auto',\n        onSearch: (q) => { emit(d2, 'onSearch', q); try { location.href = (p.searchHref || '/busca') + '?q=' + encodeURIComponent(q || ''); } catch (e) { /* sem navegação */ } },\n        onSuggestion: (q) => { emit(d2, 'onSearch', q); try { location.href = (p.searchHref || '/busca') + '?q=' + encodeURIComponent(q || ''); } catch (e) { /* sem navegação */ } }\n      }) : '';\n      return `<div class=\"cart l-${layout}\"><div class=\"in\" style=\"padding:${PAD[layout].replace(/\\S+$/, '0')}\">${crumbs}</div>${empty}${relHtml}</div>`;\n    }\n\n    // ——— Lista + resumo\n    const listHtml = R.cl ? d2.render(R.cl, { items: items.map((i) => { const o = Object.assign({}, i); delete o._unit; delete o._parc; return o; }), layout, version: ver, cartItem: R.ci, quantityStepper: R.qs, badge: R.badge, iconComponent: R.icon }, {\n      key: 'list-' + ver, style: 'height:auto',\n      onQuantityChange: (v) => { if (!v) return; const b = (d2.state.bag || []).map((y) => (y.sku === v.sku ? { sku: y.sku, qty: Number(v.quantity) || 1 } : y)); d2.state.ver = (d2.state.ver || 0) + 1; save(b); },\n      onRemove: (sku) => { const b = (d2.state.bag || []).filter((y) => y.sku !== sku); d2.state.ver = (d2.state.ver || 0) + 1; save(b); emit(d2, 'onRemove', sku); },\n      onNotify: (sku) => emit(d2, 'onNotify', sku)\n    }) : '';\n    const pixTotal = subtotal * (1 - pixPct / 100);\n    const summary = R.cs ? d2.render(R.cs, {\n      count, subtotal: brl(subtotal), total: brl(subtotal), pixTotal: pixPct > 0 ? brl(pixTotal) : '',\n      installments: parc > 1 ? `${parc}x de ${brl(subtotal / parc)}` : '',\n      shipping: { value: d2.state.shipped ? (p.shippingPendingLabel || 'Calculado no checkout') : '', defaultZip: d2.state.cep || '' },\n      checkoutHref: p.checkoutHref || '/checkout', checkoutDisabled: count === 0, continueHref: p.continueHref || '/produtos',\n      layout, version: ver, shippingCalculator: R.sc, button: R.btn, iconComponent: R.icon\n    }, {\n      key: 'sum-' + ver + '-' + (d2.state.shipped ? 's' : 'n'), style: 'height:auto',\n      onCalculate: (cep) => { try { localStorage.setItem('lf-cep', cep || ''); } catch (e) { /* sem storage */ } d2.state.cep = cep; d2.state.shipped = true; emit(d2, 'onCalculate', cep); },\n      onCheckout: () => emit(d2, 'onCheckout', { items: live.map((i) => ({ sku: i.sku, qty: i.quantity, unitPrice: i._unit })), subtotal, cep: d2.state.cep || '' })\n    }) : '';\n\n    return `<div class=\"cart l-${layout}\">\n      <div class=\"in\" style=\"padding:${PAD[layout]}\">${crumbs}${head}\n        <div class=\"grid\"><div class=\"main\">${listHtml}</div><aside class=\"aside\" aria-label=\"Resumo da sacola\">${summary}</aside></div>\n      </div>\n      ${relHtml}\n    </div>`;\n  }\n};"}},"badge":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"badge"}}}},"breadcrumb":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"breadcrumb"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"cartItem":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"cartItem"}}}},"cartList":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"cartList"}}}},"cartSummary":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"cartSummary"}}}},"checkoutHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkoutHref"}}}},"continueHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"continueHref"}}}},"dataset":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"dataset"}}}},"demoItems":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"demoItems"}}}},"emptyDescription":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"emptyDescription"}}}},"emptyState":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"emptyState"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"onAdd":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onAdd"}}}},"onCalculate":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCalculate"}}}},"onChange":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onChange"}}}},"onCheckout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onCheckout"}}}},"onNotify":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onNotify"}}}},"onRemove":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onRemove"}}}},"onSearch":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"onSearch"}}}},"pixDiscount":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"pixDiscount"}}}},"priceComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"priceComponent"}}}},"productCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"productCard"}}}},"quantityStepper":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"quantityStepper"}}}},"relatedEyebrow":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"relatedEyebrow"}}}},"relatedTitle":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"relatedTitle"}}}},"searchBar":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"searchBar"}}}},"searchHref":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"searchHref"}}}},"sectionHeader":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"sectionHeader"}}}},"shippingCalculator":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"shippingCalculator"}}}},"shippingPendingLabel":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"shippingPendingLabel"}}}},"showRelated":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"showRelated"}}}},"storageKey":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"storageKey"}}}},"title":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"title"}}}}}}}}}},{"_id":"6ac427c86bb5213aca5fdfea","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"GestaoCategorias","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Gestão — Categorias (backoffice, só desktop)\n// Uma tela para listar e outra (a mesma) para criar/editar. A navegação lista <-> formulário é interna.\n// Reaproveita Logo, Button, Notice, EmptyState e BackLink do sistema; o resto é HTML simples com os mesmos tokens.\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst slugify = (s) => String(s || '').normalize('NFD').replace(/[\\u0300-\\u036f]/g, '')\n  .toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');\nconst idOf = (v) => (v && typeof v === 'object' ? (v._id || '') : (v || ''));\nconst norm = (s) => String(s || '').normalize('NFD').replace(/[\\u0300-\\u036f]/g, '').toLowerCase();\n\nconst EMPTY_FORM = { nome: '', slug: '', ativa: true, slugTouched: false, legenda: '', imagem: '' };\n\nexport default {\n  css: `\n:host { display: block; height: 100%; overflow-y: auto; }\n* { box-sizing: border-box; }\n.root { --red: #c8102e; --ink: #0b0b0c; --white: #fff; --g100: #ececea; --g50: #f5f5f3; --g500: #6b6c70; --g800: #2a2b2e;\n  position: relative; min-height: 100%; background: var(--g50); color: var(--ink);\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased; }\n.notice.below { margin: 20px 0 0; }\n.page { max-width: 1120px; margin: 0 auto; padding: 40px 48px 64px; }\n.head { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: 24px; }\n.eyebrow { font-size: 12px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--red); margin: 0 0 8px; }\nh1 { margin: 0; font-size: 34px; font-weight: 800; letter-spacing: -.01em; line-height: 1.1; }\n.sub { margin: 8px 0 0; color: var(--g500); font-size: 15px; }\n.notice { margin-bottom: 16px; }\n.tools { display: flex; align-items: center; gap: 16px; margin-bottom: 16px; flex-wrap: wrap; }\n.search { flex: 1; min-width: 260px; max-width: 420px; height: 44px; border: 1.5px solid var(--g100); background: var(--white); border-radius: 2px; padding: 0 14px; font: inherit; font-size: 14px; color: var(--ink); }\n.search:focus, .inp:focus { outline: 2px solid var(--red); outline-offset: 1px; border-color: var(--ink); }\n.chips { display: flex; gap: 8px; }\n.chip { height: 36px; padding: 0 16px; border: 1.5px solid var(--ink); background: var(--white); color: var(--ink); border-radius: 999px; font: inherit; font-size: 12px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; cursor: pointer; }\n.chip[aria-pressed=\"true\"] { background: var(--ink); color: var(--white); }\n.card { background: var(--white); border: 1px solid var(--g100); border-radius: 2px; }\ntable { width: 100%; border-collapse: collapse; }\nth { text-align: left; font-size: 11px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--g500); padding: 14px 20px; border-bottom: 1px solid var(--g100); }\ntd { padding: 16px 20px; border-bottom: 1px solid var(--g100); font-size: 15px; vertical-align: middle; }\ntr:last-child td { border-bottom: 0; }\ntd.nome { font-weight: 700; }\ntd.slug { color: var(--g500); font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 13px; }\n.pill { display: inline-flex; align-items: center; gap: 8px; height: 26px; padding: 0 12px; border-radius: 999px; font-size: 11px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; }\n.pill::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }\n.pill.on { background: var(--g100); color: var(--ink); }\n.pill.off { background: #fbe9ec; color: var(--red); }\n.yes { font-weight: 700; } .no { color: var(--g500); }\n.acts { display: flex; gap: 16px; justify-content: flex-end; }\n.lk { background: none; border: 0; padding: 0; font: inherit; font-size: 12px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--ink); cursor: pointer; border-bottom: 1.5px solid var(--ink); }\n.lk:hover { color: var(--red); border-color: var(--red); }\n.lk.danger { color: var(--red); border-color: var(--red); }\n.count { margin: 12px 2px 0; color: var(--g500); font-size: 13px; }\n.form { max-width: 640px; padding: 32px; }\n.back { margin-bottom: 20px; }\n.field { margin-bottom: 22px; }\n.lbl { display: block; font-size: 12px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; margin-bottom: 8px; }\n.inp { width: 100%; height: 48px; border: 1.5px solid var(--g100); background: var(--white); border-radius: 2px; padding: 0 14px; font: inherit; font-size: 15px; color: var(--ink); }\n.inp[readonly] { background: var(--g50); color: var(--g500); }\n.inp.bad { border-color: var(--red); }\n.hint { margin: 6px 0 0; font-size: 13px; color: var(--g500); }\n.err { margin: 6px 0 0; font-size: 13px; font-weight: 700; color: var(--red); }\n.checks { display: grid; gap: 14px; margin: 8px 0 24px; }\n.ck { display: flex; align-items: flex-start; gap: 12px; cursor: pointer; font-size: 15px; }\n.ck input { width: 20px; height: 20px; margin: 1px 0 0; accent-color: var(--ink); flex: none; }\n.ck small { display: block; color: var(--g500); font-size: 13px; margin-top: 2px; }\n.warn { margin-bottom: 24px; }\n.btns { display: flex; align-items: center; gap: 12px; padding-top: 8px; }\n.btns .sp { flex: 1; }\n.empty { padding: 24px; }\n.imgbox { display: flex; flex-direction: column; gap: 12px; }\n.pv { display: flex; gap: 14px; align-items: flex-end; }\n.pv figure { margin: 0; }\n.pv .fr { position: relative; overflow: hidden; background-size: cover; background-position: center; background-color: var(--g100); }\n.pv .fr::after { content: ''; position: absolute; inset: 0; background: linear-gradient(0deg, rgba(11,11,12,.92) 0%, rgba(11,11,12,.45) 55%, rgba(11,11,12,.25) 100%); }\n.pv figcaption { margin-top: 4px; font-size: 11px; color: var(--g500); letter-spacing: .06em; text-transform: uppercase; }\n.noimg { width: 160px; height: 120px; display: flex; align-items: center; justify-content: center; background: var(--g50); border: 1.5px dashed var(--g100); color: var(--g500); font-size: 13px; }\n.imgbtns { display: flex; gap: 20px; align-items: center; }\nlabel.lk { display: inline-block; }\n.ovl { position: fixed; inset: 0; background: rgba(11,11,12,.55); display: flex; align-items: flex-start; justify-content: center; padding-top: 200px; z-index: 10; }\n.dlg { width: 480px; max-width: calc(100% - 32px); background: var(--white); border-radius: 2px; padding: 32px; box-shadow: 0 24px 64px rgba(0,0,0,.35); }\n.dlg h2 { margin: 0 0 12px; font-size: 22px; font-weight: 800; }\n.dlg p { margin: 0 0 24px; color: var(--g800); font-size: 15px; line-height: 1.5; }\n.dlg .row { display: flex; gap: 12px; justify-content: flex-end; }\n`,\n\n  mounted(d2) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font'; l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    const cat = d2.data('categorias');\n    const prod = d2.data('produtos');\n\n    const S = d2.state;\n    const records = () => S.items || [];\n    const countProducts = (id) => { const r = records().find((x) => String(x._id) === String(id)); return r ? Number(r.produtos) || 0 : 0; };\n    const say = (tone, body) => { S.notice = { tone, body }; };\n    const reload = async () => {\n      try {\n        const res = await d2.rush('gestaoCategoriasListar').invoke({});\n        const out = res && res.data !== undefined ? res.data : res;\n        S.items = Array.isArray(out) ? out : [];\n      } catch (e) { say('error', 'Não foi possível carregar as categorias.'); }\n      S.loaded = true;\n    };\n\n    const openNew = () => { S.editingId = null; S.form = { ...EMPTY_FORM }; S.errors = {}; S.notice = null; S.view = 'form'; };\n    const openEdit = (id) => {\n      const r = records().find((x) => String(x._id) === String(id));\n      if (!r) return;\n      S.editingId = r._id;\n      S.form = { nome: r.nome || '', slug: r.slug || '', ativa: r.ativa !== false, legenda: r.legenda || '', imagem: r.imagem || '', slugTouched: true };\n      S.original = { ativa: r.ativa !== false };\n      S.errors = {}; S.notice = null; S.view = 'form';\n    };\n    const backToList = () => { S.view = 'lista'; S.errors = {}; };\n\n    const askConfirm = (kind, rec, fromForm) => {\n      S.confirm = { kind, id: rec._id, nome: rec.nome || S.form.nome, n: countProducts(rec._id), fromForm: !!fromForm };\n    };\n\n    const validate = () => {\n      const f = S.form || EMPTY_FORM; const errs = {};\n      if (!String(f.nome).trim()) errs.nome = 'Informe o nome da categoria.';\n      \n      const sl = slugify(f.slug);\n      if (!sl) errs.slug = 'Informe o slug da categoria.';\n      else if (records().some((r) => String(r._id) !== String(S.editingId) && String(r.slug).toLowerCase() === sl)) errs.slug = 'Já existe uma categoria com esse slug.';\n      S.errors = errs;\n      return Object.keys(errs).length === 0;\n    };\n\n    const persist = async () => {\n      const f = S.form; const payload = { nome: String(f.nome).trim(), slug: slugify(f.slug), ativa: !!f.ativa, legenda: String(f.legenda || '').trim(), imagem: String(f.imagem || '') };\n      S.busy = true;\n      try {\n        const res = await d2.rush('gestaoCategoriaSalvar').invoke({ id: S.editingId || undefined, ...payload });\n        const out = res && res.data !== undefined ? res.data : res;\n        if (out && out.ok === false) { const err = new Error(out.error || 'erro'); err.userMessage = out.error; throw err; }\n      } finally { S.busy = false; }\n      return payload;\n    };\n\n    const save = async () => {\n      if (S.busy || !validate()) return;\n      const f = S.form;\n      if (S.editingId && S.original && S.original.ativa && !f.ativa) {\n        askConfirm('desativar', { _id: S.editingId, nome: f.nome }, true);\n        return;\n      }\n      try {\n        await persist(); await reload();\n        say('success', S.editingId ? 'Categoria atualizada.' : 'Categoria criada.');\n        backToList();\n      } catch (e) { say('error', (e && e.userMessage) || 'Não foi possível salvar a categoria. Tente de novo.'); }\n    };\n\n    const confirmGo = async () => {\n      if (!S.confirm || S.busy) return;\n      const c = { ...S.confirm, n: countProducts(S.confirm.id) };\n      S.busy = true;\n      try {\n        if (c.kind === 'desativar') {\n          if (c.fromForm) { S.busy = false; await persist(); S.busy = true; }\n          await d2.rush('gestaoCategoriaDesativar').invoke({ id: c.id });\n          say('success', 'Categoria desativada. ' + c.n + (c.n === 1 ? ' produto foi desativado.' : ' produtos foram desativados.'));\n        } else {\n          await d2.rush('gestaoCategoriaExcluir').invoke({ id: c.id });\n          say('success', 'Categoria excluída. ' + c.n + (c.n === 1 ? ' produto foi desativado.' : ' produtos foram desativados.'));\n        }\n        S.confirm = null; S.busy = false; await reload(); backToList();\n      } catch (e) { S.busy = false; S.confirm = null; say('error', (e && e.userMessage) || 'Não foi possível concluir a ação. Nada foi alterado.'); }\n    };\n\n    const toggleAtiva = async (id) => {\n      const r = records().find((x) => String(x._id) === String(id)); if (!r) return;\n      if (r.ativa !== false) { askConfirm('desativar', r, false); return; }\n      try { const res = await d2.rush('gestaoCategoriaSalvar').invoke({ id: r._id, nome: r.nome, slug: r.slug, ativa: true, legenda: r.legenda || '', imagem: r.imagem || '' }); const out = res && res.data !== undefined ? res.data : res; if (out && out.ok === false) { say('error', out.error || 'Não foi possível reativar a categoria.'); return; } await reload(); say('success', 'Categoria reativada. Os produtos continuam como estavam.'); }\n      catch (e) { say('error', 'Não foi possível reativar a categoria.'); }\n    };\n\n    d2.on('[data-act]', 'click', (e, el) => {\n      const act = el.getAttribute('data-act'); const id = el.getAttribute('data-id');\n      if (act === 'new') openNew(); else if (act === 'save') save(); else if (act === 'back') backToList(); else if (act === 'confirm-go') confirmGo(); else if (act === 'edit') openEdit(id);\n      else if (act === 'toggle') toggleAtiva(id);\n      else if (act === 'delete') { const r = records().find((x) => String(x._id) === String(id)); if (r) askConfirm('excluir', r, false); }\n      else if (act === 'filter') S.filter = el.getAttribute('data-v');\n      else if (act === 'delete-form') askConfirm('excluir', { _id: S.editingId, nome: S.form.nome }, true);\n      else if (act === 'cancel-confirm') S.confirm = null;\n      else if (act === 'img-clear') { S.form = { ...(S.form || EMPTY_FORM), imagem: '' }; S.imgErr = ''; }\n    });\n    d2.on('[data-f]', 'input', (e, el) => {\n      const k = el.getAttribute('data-f'); const f = { ...(S.form || EMPTY_FORM) };\n      f[k] = el.value;\n      if (k === 'nome' && !S.editingId && !f.slugTouched) f.slug = slugify(el.value);\n      if (k === 'slug') f.slugTouched = true;\n      S.form = f;\n    });\n    d2.on('[data-c]', 'change', (e, el) => { S.form = { ...(S.form || EMPTY_FORM), [el.getAttribute('data-c')]: !!el.checked }; });\n    d2.on('[data-q]', 'input', (e, el) => { S.q = el.value; });\n    d2.on('[data-up]', 'change', async (e, el) => {\n      const file = el.files && el.files[0]; el.value = '';\n      if (!file) return;\n      S.imgErr = '';\n      if (!/^image\\/(jpeg|png|webp)$/.test(file.type)) { S.imgErr = 'Use uma imagem JPG, PNG ou WebP.'; return; }\n      if (file.size > 5 * 1024 * 1024) { S.imgErr = 'A imagem passa de 5 MB. Escolha uma menor.'; return; }\n      S.imgBusy = true;\n      try {\n        const bmp = await createImageBitmap(file);\n        const w = bmp.width; const h = bmp.height;\n        if (Math.min(w, h) < 900) { S.imgErr = 'A imagem precisa ter pelo menos 900×900 px (esta tem ' + w + '×' + h + ').'; S.imgBusy = false; return; }\n        const side = Math.min(w, h);\n        const cv = document.createElement('canvas'); cv.width = 1200; cv.height = 1200;\n        const cx = cv.getContext('2d'); cx.fillStyle = '#ffffff'; cx.fillRect(0, 0, 1200, 1200);\n        cx.drawImage(bmp, (w - side) / 2, (h - side) / 2, side, side, 0, 0, 1200, 1200);\n        const blob = await new Promise((r) => cv.toBlob(r, 'image/jpeg', 0.86));\n        if (!blob) throw new Error('crop');\n        const b64 = await new Promise((r, j) => { const fr = new FileReader(); fr.onload = () => r(String(fr.result).split(',')[1]); fr.onerror = j; fr.readAsDataURL(blob); });\n        const res = await d2.rush('gestaoCategoriaImagem').invoke({ base64: b64, slug: (S.form && S.form.slug) || 'nova' });\n        const out = res && res.data !== undefined ? res.data : res;\n        const url = out && out.ok ? out.url : '';\n        if (!url) throw new Error('upload');\n        S.form = { ...(S.form || EMPTY_FORM), imagem: url };\n      } catch (err) { try { console.error('GESTAO_IMG', err && err.message, JSON.stringify((err && (err.response || err.data || err.code)) || null)); } catch (x) { /* log */ } S.imgErr = 'Não foi possível enviar a imagem. Tente de novo.'; }\n      S.imgBusy = false;\n    });\n\n    // callbacks que os Buttons reaproveitados disparam\n    S.__fn = { openNew, save, backToList, confirmGo, cancelConfirm: () => { S.confirm = null; }, toggle: toggleAtiva };\n    reload();\n  },\n\n  render(d2) {\n    const S = d2.state;\n    const P = d2.params || {};\n    const cat = d2.data('categorias');\n    const prod = d2.data('produtos');\n    if (S.view === undefined) {\n      S.view = P.view === 'form' ? 'form' : 'lista';\n      S.filter = 'todas'; S.q = ''; S.form = { ...EMPTY_FORM }; S.errors = {}; S.editingId = null; S.confirm = null; S.notice = null; S.busy = false;\n    }\n    const lazy = (name) => () => { const f = d2.state.__fn; if (f && f[name]) return f[name](); };\n    const fn = { openNew: lazy('openNew'), save: lazy('save'), backToList: lazy('backToList'), confirmGo: lazy('confirmGo'), cancelConfirm: lazy('cancelConfirm') };\n    const btn = (label, variant, act, key, w) => `<span data-act=\"${act}\" style=\"display:inline-block\">${d2.render(P.button, { label, variant, size: 'sm' }, { key, width: w, height: 44 })}</span>`;\n    const rows = (S.items || []).slice().sort((a, b) => String(a.nome).localeCompare(String(b.nome), 'pt-BR'));\n    const nProd = (id) => { const r = rows.find((x) => String(x._id) === String(id)); return r ? Number(r.produtos) || 0 : 0; };\n\n    // variante de design: mostra o overlay de confirmação sem precisar clicar\n    let confirm = S.confirm;\n    if (!confirm && P.demoConfirm && rows.length) {\n      const r = rows.find((x) => x.ativa !== false) || rows[0];\n      confirm = { kind: 'desativar', id: r._id, nome: r.nome, n: nProd(r._id), fromForm: false };\n    }\n\n    if (confirm) confirm = Object.assign({}, confirm, { n: nProd(confirm.id) });\n\n    const header = ''; // o menu fica no componente GestaoMenu (bloco no topo de cada tela)\n    const notice = S.notice ? `<div class=\"notice\">${d2.render(P.notice, { tone: S.notice.tone === 'error' ? 'error' : 'success', body: S.notice.body, live: true }, { key: 'notice', height: 64 })}</div>` : '';\n\n    const noticeBelow = notice ? notice.replace('class=\"notice\"', 'class=\"notice below\"') : '';\n    let main = '';\n    if (S.view === 'form') {\n      const f = S.form || EMPTY_FORM; const e = S.errors || {}; const edit = !!S.editingId;\n      const willCascade = edit && S.original && S.original.ativa;\n      main = `\n<div class=\"page\">\n  <div class=\"back\"><span data-act=\"back\" style=\"display:inline-block\">${d2.render(P.backLink, { label: 'Voltar para categorias' }, { key: 'back', width: 260, height: 32 })}</span></div>\n  <div class=\"head\"><div><p class=\"eyebrow\">Categorias</p><h1>${edit ? 'Editar categoria' : 'Nova categoria'}</h1>\n    <p class=\"sub\">${edit ? 'Altere os dados e salve.' : 'Cadastre uma categoria para organizar os produtos da loja.'}</p></div></div>\n  <div class=\"card form\">\n    <div class=\"field\"><label class=\"lbl\" for=\"f-nome\">Nome</label>\n      <input id=\"f-nome\" class=\"inp ${e.nome ? 'bad' : ''}\" data-f=\"nome\" value=\"${esc(f.nome)}\" placeholder=\"Ex.: Cuidado automotivo\" maxlength=\"80\" autocomplete=\"off\">\n      ${e.nome ? `<p class=\"err\">${esc(e.nome)}</p>` : ''}</div>\n    <div class=\"field\"><label class=\"lbl\" for=\"f-slug\">Slug</label>\n      <input id=\"f-slug\" class=\"inp ${e.slug ? 'bad' : ''}\" data-f=\"slug\" value=\"${esc(f.slug)}\" placeholder=\"nome-da-categoria\" maxlength=\"80\" autocomplete=\"off\" ${edit ? 'readonly' : ''}>\n      ${e.slug ? `<p class=\"err\">${esc(e.slug)}</p>` : `<p class=\"hint\">${edit ? 'O slug não muda depois de criado.' : 'Gerado a partir do nome. Pode editar antes de salvar.'}</p>`}</div>\n    \n    <div class=\"field\"><span class=\"lbl\">Imagem do card</span>\n      <div class=\"imgbox\">${f.imagem ? `<div class=\"pv\">\n        <figure><div class=\"fr\" style=\"width:90px;height:120px;background-image:url('${esc(f.imagem)}')\"></div><figcaption>Desktop</figcaption></figure>\n        <figure><div class=\"fr\" style=\"width:120px;height:100px;background-image:url('${esc(f.imagem)}')\"></div><figcaption>Tablet</figcaption></figure>\n        <figure><div class=\"fr\" style=\"width:80px;height:95px;background-image:url('${esc(f.imagem)}')\"></div><figcaption>Mobile</figcaption></figure></div>` : '<div class=\"noimg\">Sem imagem</div>'}\n        <div class=\"imgbtns\"><label class=\"lk\">${S.imgBusy ? 'Enviando...' : (f.imagem ? 'Trocar imagem' : 'Escolher imagem')}<input type=\"file\" data-up accept=\"image/jpeg,image/png,image/webp\" hidden></label>${f.imagem ? '<button class=\"lk danger\" data-act=\"img-clear\">Remover imagem</button>' : ''}</div></div>\n      ${S.imgErr ? `<p class=\"err\">${esc(S.imgErr)}</p>` : ''}\n      <p class=\"hint\">Imagem quadrada, de 1200×1200 px (mínimo 900×900), JPG, PNG ou WebP, até 5 MB. A tela recorta o centro e converte sozinha. O card corta as bordas conforme a tela (retrato no desktop, paisagem no tablet): deixe o assunto no centro. Evite detalhes no canto superior esquerdo (número) e na parte de baixo (nome e legenda), que ficam sobre um degradê escuro. Obrigatória para a categoria entrar na home.</p></div>\n    <div class=\"field\"><label class=\"lbl\" for=\"f-legenda\">Legenda do card da home</label>\n      <input id=\"f-legenda\" class=\"inp\" data-f=\"legenda\" value=\"${esc(f.legenda)}\" placeholder=\"Ex.: Shampoo, pretinho, cera e cia.\" maxlength=\"60\" autocomplete=\"off\">\n      <p class=\"hint\">Texto curto que aparece embaixo do nome no card da home.</p></div>\n    <div class=\"checks\">\n      <label class=\"ck\"><input type=\"checkbox\" data-c=\"ativa\" ${f.ativa ? 'checked' : ''}><span>Ativa<small>Categoria inativa some da loja e libera as vagas de destaque.</small></span></label>\n      \n    </div>\n    <div class=\"warn\">${d2.render(P.notice, { tone: 'info', body: 'Ao desativar ou excluir uma categoria, todos os produtos dela também são desativados.' + (willCascade ? ' Hoje são ' + nProd(S.editingId) + ' produto(s).' : ''), live: false }, { key: 'warn', height: 72 })}</div>\n    <div class=\"btns\">${btn(edit ? 'Salvar alterações' : 'Criar categoria', 'primary', 'save', 'save', 210)}${btn('Cancelar', 'outline', 'back', 'cancel', 130)}<span class=\"sp\"></span>${edit ? '<button class=\"lk danger\" data-act=\"delete-form\">Excluir categoria</button>' : ''}</div>\n    ${noticeBelow}\n  </div>\n</div>`;\n    } else {\n      const q = norm(S.q);\n      const shown = rows.filter((r) => (S.filter === 'ativas' ? r.ativa !== false : S.filter === 'inativas' ? r.ativa === false : true)\n        && (!q || norm(r.nome).includes(q) || norm(r.slug).includes(q)));\n      const chip = (v, l) => `<button class=\"chip\" data-act=\"filter\" data-v=\"${v}\" aria-pressed=\"${S.filter === v}\">${l}</button>`;\n      const body = shown.length ? `\n<div class=\"card\"><table>\n  <thead><tr><th>Nome</th><th>Slug</th><th>Status</th><th>Home</th><th>Menu</th><th></th></tr></thead>\n  <tbody>${shown.map((r) => `\n    <tr data-key=\"${esc(r._id || 'pending-' + r.slug)}\">\n      <td class=\"nome\">${esc(r.nome)}</td><td class=\"slug\">${esc(r.slug)}</td>\n      <td><span class=\"pill ${r.ativa === false ? 'off' : 'on'}\">${r.ativa === false ? 'Inativa' : 'Ativa'}</span></td>\n      <td class=\"${Number(r.posicao_home) > 0 ? 'yes' : 'no'}\">${Number(r.posicao_home) > 0 ? 'Vaga ' + r.posicao_home : '—'}</td>\n      <td class=\"${Number(r.posicao_menu) > 0 ? 'yes' : 'no'}\">${Number(r.posicao_menu) > 0 ? 'Vaga ' + r.posicao_menu : '—'}</td>\n      <td><div class=\"acts\"><button class=\"lk\" data-act=\"edit\" data-id=\"${esc(r._id)}\">Editar</button>\n        <button class=\"lk\" data-act=\"toggle\" data-id=\"${esc(r._id)}\">${r.ativa === false ? 'Ativar' : 'Desativar'}</button>\n        <button class=\"lk danger\" data-act=\"delete\" data-id=\"${esc(r._id)}\">Excluir</button></div></td>\n    </tr>`).join('')}</tbody></table></div>\n<p class=\"count\">${shown.length} de ${rows.length} ${rows.length === 1 ? 'categoria' : 'categorias'}</p>`\n        : !S.loaded ? '<div class=\"card empty\"><p class=\"sub\">Carregando categorias…</p></div>' : `<div class=\"card empty\">${d2.render(P.emptyState, { eyebrow: 'Categorias', title: rows.length ? 'Nenhuma categoria encontrada' : 'Nenhuma categoria cadastrada', description: rows.length ? 'Tente outro nome ou mude o filtro.' : 'Crie a primeira categoria para organizar os produtos da loja.', iconName: 'search' }, { key: 'empty', height: 260 })}</div>`;\n      main = `\n<div class=\"page\">\n  <div class=\"head\"><div><p class=\"eyebrow\">Gestão</p><h1>Categorias</h1><p class=\"sub\">Organize as categorias da loja e escolha quais aparecem na home e no menu.</p></div>\n    ${btn('Nova categoria', 'primary', 'new', 'new', 200)}</div>\n  ${notice}\n  <div class=\"tools\"><input class=\"search\" data-q placeholder=\"Buscar por nome ou slug\" value=\"${esc(S.q)}\" aria-label=\"Buscar categoria\">\n    <div class=\"chips\">${chip('todas', 'Todas')}${chip('ativas', 'Ativas')}${chip('inativas', 'Inativas')}</div></div>\n  ${body}\n</div>`;\n    }\n\n    const overlay = confirm ? `\n<div class=\"ovl\"><div class=\"dlg\" role=\"alertdialog\" aria-modal=\"true\">\n  <h2>${confirm.kind === 'excluir' ? 'Excluir' : 'Desativar'} “${esc(confirm.nome)}”?</h2>\n  <p>${confirm.kind === 'excluir' ? 'A categoria será apagada e não dá para desfazer. ' : 'A categoria sai da loja (home, menu e filtros). '}${confirm.n} ${confirm.n === 1 ? 'produto dessa categoria também será desativado' : 'produtos dessa categoria também serão desativados'}.</p>\n  <div class=\"row\">${btn('Cancelar', 'outline', 'cancel-confirm', 'c-cancel', 130)}${btn(confirm.kind === 'excluir' ? 'Excluir categoria' : 'Desativar categoria', confirm.kind === 'excluir' ? 'brand' : 'primary', 'confirm-go', 'c-ok', 230)}</div>\n</div></div>` : '';\n\n    return `<div class=\"root\">${header}${main}${overlay}</div>`;\n  }\n};"}},"backLink":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"backLink"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"categorias":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"categorias"}}}},"demoConfirm":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"demoConfirm"}}}},"emptyState":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"emptyState"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"logo":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"logo"}}}},"notice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notice"}}}},"produtos":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"produtos"}}}},"view":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"view"}}}}}}}}}},{"_id":"6ac429e6b4eec9d29421e98e","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"HomeCategorias","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// HomeCategorias — grade de categorias da Home, lida da tabela Categorias\n// Mostra só categorias ativas com destaque na home (a busca vem do serviço `categoriasLoja`).\n// Reaproveita o CategoryCard pelo parâmetro `categoryCard`.\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst COLS = { desktop: 4, tablet: 2, mobile: 2 };\nconst GAP = { desktop: 20, tablet: 16, mobile: 12 };\nconst ROW_H = { desktop: 400, tablet: 280, mobile: 200 };\nconst CAPTIONS = {\n  'cuidado-automotivo': 'Shampoo, pretinho, cera e cia.',\n  'performance': 'Linha BPower Motorsport',\n  'vestuario': 'Camisetas e moletons do canal',\n  'acessorios': 'Bonés, chaveiros e adesivos'\n};\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nlet LOADED = null; let LOADING = null;\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.grid { display: grid; width: 100%; }\n`,\n  mounted(d2) {\n    if (!LOADED) {\n      if (!LOADING) {\n        LOADING = d2.rush('categoriasLoja').invoke({}).then((res) => {\n          const rows = (res && res.data !== undefined ? res.data : res) || [];\n          LOADED = rows.filter((c) => c && c.ativa !== false && Number(c.posicao_home) > 0).sort((a, b) => Number(a.posicao_home) - Number(b.posicao_home));\n        }).catch(() => { LOADING = null; });\n      }\n      const pr = LOADING;\n      if (pr) pr.then(() => { d2.state.tick = Date.now(); });\n    }\n  },\n  render(d2) {\n    void d2.state.tick;\n    const p = d2.params || {};\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const card = refOf(d2.param('categoryCard'));\n    const rows = (LOADED || []).slice(0, 4);\n    if (!card || !rows.length) return '<div class=\"grid\"></div>';\n    const h = ROW_H[layout];\n    const cells = rows.map((c, i) => `<div>${d2.render(card, {\n      iconComponent: refOf(d2.param('iconComponent')) || 'babi-lf@Icon',\n      layout, number: i + 1, label: c.nome, caption: c.legenda || '',\n      href: '/lista-de-produtos/q?categoria=' + c.slug, image: c.imagem || '', tone: i % 2 === 0 ? 'graphite' : 'ink'\n    }, { key: 'cat-' + (c._id || c.slug), height: h })}</div>`).join('');\n    return `<div class=\"grid\" style=\"grid-template-columns:repeat(${COLS[layout]},1fr);gap:${GAP[layout]}px\">${cells}</div>`;\n  }\n};"}},"categoryCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"categoryCard"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}}}}}}}},{"_id":"6ac42eb0005d4042c2e33937","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"GestaoLogin","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Gestão — Login (backoffice, só desktop)\n// Reaproveita o LoginForm, Logo, FormField, Button, Notice e Icon da loja; só liga o envio ao login da Gestão.\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\n\nexport default {\n  css: `\n:host { display: block; }\n* { box-sizing: border-box; }\n.root { --ink: #0b0b0c; --white: #fff; --g100: #ececea; --g50: #f5f5f3;\n  min-height: 100%; background: var(--g50); color: var(--ink);\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased; }\n.bar { height: 72px; background: var(--white); border-bottom: 1px solid var(--g100); display: flex; align-items: center; padding: 0 48px; gap: 20px; }\n.bar .tag { font-size: 11px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; background: var(--ink); color: var(--white); padding: 6px 10px; border-radius: 2px; }\n.stage { display: flex; justify-content: center; padding: 72px 24px; }\n.card { width: 520px; max-width: 100%; }\n`,\n  mounted(d2) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font'; l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n  },\n  render(d2) {\n    const S = d2.state;\n    const P = d2.params || {};\n    const onSubmit = async (v) => {\n      if (S.busy || !v) return;\n      S.busy = true; S.err = '';\n      try {\n        await d2.auth('auth').login({ credentials: { email: v.email, senha: v.password } });\n        S.ok = true;\n        try { d2.router('router').goTo('/categorias'); } catch (e) { /* segue para o reload */ }\n        if (typeof window !== 'undefined') setTimeout(() => window.location.reload(), 300);\n      } catch (e) {\n        S.err = 'E-mail ou senha incorretos.';\n      }\n      S.busy = false;\n    };\n    const header = `<div class=\"bar\">${d2.render(P.logo, { layout: 'desktop', noLink: true }, { key: 'logo', width: 380, height: 40 })}<span class=\"tag\">Gestão</span></div>`;\n    const form = d2.render(P.loginForm, {\n      layout: 'desktop', eyebrow: 'Gestão', title: 'Entrar',\n      description: 'Acesso restrito à equipe de gestão da loja.',\n      autoAdvance: false, submitLabel: S.busy ? 'Entrando...' : 'Entrar',\n      passwordError: S.err || '',\n      forgotLabel: 'Esqueci minha senha', forgotHref: 'mailto:babi.vallim@gmail.com?subject=Gest%C3%A3o%20-%20redefinir%20senha',\n      note: 'A sessão fica ativa neste aparelho. Em computador compartilhado, saia ao terminar.',\n      formField: P.formField, button: P.button, notice: P.notice, iconComponent: P.iconComponent,\n      codeField: P.codeField, resendCode: P.resendCode\n    }, { key: 'form', height: 560, onSubmit });\n    return `<div class=\"root\">${header}<div class=\"stage\"><div class=\"card\">${form}</div></div></div>`;\n  }\n};"}},"auth":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"auth"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"codeField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"codeField"}}}},"formField":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"formField"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"loginForm":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"loginForm"}}}},"logo":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"logo"}}}},"notice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notice"}}}},"resendCode":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"resendCode"}}}},"router":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"router"}}}}}}}}}},{"_id":"6ac436822f4d9a7641b7a788","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"GestaoDestaques","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Gestão — Destaques (backoffice, só desktop)\n// A home tem 4 vagas e o menu tem 6. Cada vaga recebe no máximo uma categoria, e cada categoria ocupa no máximo uma vaga por lugar.\n// Reaproveita Logo, Button e Notice da loja; o resto é HTML simples com os mesmos tokens.\nconst esc = (s) => String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst HOME = 4;\nconst MENU = 6;\nconst PROD = 12;\nconst slotsOf = (items, key, n) => { const a = Array(n).fill(''); (items || []).forEach((c) => { const p = Number(c[key]); if (c.ativa !== false && p >= 1 && p <= n) a[p - 1] = String(c._id); }); return a; };\n\nexport default {\n  css: `\n:host { display: block; height: 100%; overflow-y: auto; }\n* { box-sizing: border-box; }\n.root { --red: #c8102e; --ink: #0b0b0c; --white: #fff; --g100: #ececea; --g50: #f5f5f3; --g500: #6b6c70;\n  min-height: 100%; background: var(--g50); color: var(--ink);\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased; }\n.notice.below { margin: 20px 0 0; }\n.page { max-width: 1120px; margin: 0 auto; padding: 40px 48px 64px; }\n.head { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: 24px; }\n.eyebrow { font-size: 12px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--red); margin: 0 0 8px; }\nh1 { margin: 0; font-size: 34px; font-weight: 800; letter-spacing: -.01em; line-height: 1.1; }\n.sub { margin: 8px 0 0; color: var(--g500); font-size: 15px; }\n.notice { margin-bottom: 16px; }\n.cols { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: start; }\n.card { background: var(--white); border: 1px solid var(--g100); border-radius: 2px; padding: 28px; }\n.card h2 { margin: 0 0 4px; font-size: 20px; font-weight: 800; }\n.card .cnt { margin: 0 0 20px; color: var(--g500); font-size: 14px; }\n.card .cnt.warn { color: var(--red); font-weight: 700; }\n.slot { display: grid; grid-template-columns: 72px 1fr; align-items: center; gap: 12px; margin-bottom: 12px; }\n.slot .n { font-size: 12px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--g500); }\n.sel { width: 100%; height: 46px; border: 1.5px solid var(--g100); background: var(--white); border-radius: 2px; padding: 0 12px; font: inherit; font-size: 15px; color: var(--ink); }\n.sel:focus { outline: 2px solid var(--red); outline-offset: 1px; border-color: var(--ink); }\n.wide { margin-top: 24px; }\n.slots2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 24px; }\n.foot { display: flex; align-items: center; gap: 16px; margin-top: 24px; }\n.foot .hint { color: var(--g500); font-size: 13px; }\n`,\n  mounted(d2) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font'; l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    const S = d2.state;\n    const load = async () => {\n      try {\n        const res = await d2.rush('gestaoCategoriasListar').invoke({});\n        const out = res && res.data !== undefined ? res.data : res;\n        S.items = Array.isArray(out) ? out : [];\n        S.home = slotsOf(S.items, 'posicao_home', HOME);\n        S.menu = slotsOf(S.items, 'posicao_menu', MENU);\n        const pres = await d2.rush('gestaoProdutosListar').invoke({});\n        const pout = pres && pres.data !== undefined ? pres.data : pres;\n        S.prods = Array.isArray(pout && pout.produtos) ? pout.produtos : [];\n        S.pslots = Array(PROD).fill('');\n        S.prods.forEach((x) => { const p = Number(x.posicaoDestaque); if (x.ativo !== false && p >= 1 && p <= PROD) S.pslots[p - 1] = String(x._id); });\n        S.dirty = false;\n      } catch (e) { S.notice = { tone: 'error', body: 'Não foi possível carregar as categorias.' }; }\n      S.loaded = true;\n    };\n    const save = async () => {\n      if (S.busy) return;\n      S.busy = true;\n      try {\n        const items = (S.items || []).filter((c) => c.ativa !== false).map((c) => ({\n          id: String(c._id),\n          home: (S.home || []).indexOf(String(c._id)) + 1,\n          menu: (S.menu || []).indexOf(String(c._id)) + 1\n        }));\n        const res = await d2.rush('gestaoDestaquesSalvar').invoke({ items });\n        const out = res && res.data !== undefined ? res.data : res;\n        if (out && out.ok === false) { S.notice = { tone: 'error', body: out.error || 'Não foi possível salvar os destaques.' }; }\n        else {\n          const pitems = (S.pslots || []).map((id, i) => (id ? { id: String(id), pos: i + 1 } : null)).filter(Boolean);\n          const res2 = await d2.rush('gestaoDestaquesProdutosSalvar').invoke({ items: pitems });\n          const out2 = res2 && res2.data !== undefined ? res2.data : res2;\n          if (out2 && out2.ok === false) { S.notice = { tone: 'error', body: out2.error || 'Não foi possível salvar os produtos em destaque.' }; }\n          else { await load(); S.notice = { tone: 'success', body: 'Destaques salvos.' }; }\n        }\n      } catch (e) { S.notice = { tone: 'error', body: 'Não foi possível salvar os destaques.' }; }\n      S.busy = false;\n    };\n    d2.on('[data-slot]', 'change', (e, el) => {\n      const [list, idx] = String(el.getAttribute('data-slot')).split(':');\n      const arr = (list === 'home' ? S.home : list === 'prod' ? S.pslots : S.menu).slice();\n      const v = el.value;\n      const k = Number(idx); const prev = arr[k]; const j = v ? arr.indexOf(v) : -1; if (j >= 0 && j !== k) arr[j] = prev; arr[k] = v;\n      if (list === 'home') S.home = arr; else if (list === 'prod') S.pslots = arr; else S.menu = arr;\n      S.dirty = true; S.notice = null;\n    });\n    d2.on('[data-act]', 'click', (e, el) => { if (el.getAttribute('data-act') === 'save-dest') save(); });\n    load();\n  },\n  render(d2) {\n    const S = d2.state;\n    const P = d2.params || {};\n    const actives = (S.items || []).filter((c) => c.ativa !== false).sort((a, b) => String(a.nome).localeCompare(String(b.nome), 'pt-BR'));\n    const header = ''; // o menu fica no componente GestaoMenu (bloco no topo de cada tela)\n    const notice = S.notice ? `<div class=\"notice\">${d2.render(P.notice, { tone: S.notice.tone === 'error' ? 'error' : 'success', body: S.notice.body, live: true }, { key: 'notice-' + S.notice.tone, height: 64 })}</div>` : '';\n    const block = (title, list, arr, n) => {\n      const filled = arr.filter(Boolean).length;\n      const rows = arr.map((cur, i) => `<div class=\"slot\"><span class=\"n\">Vaga ${i + 1}</span><select class=\"sel\" data-slot=\"${list}:${i}\" aria-label=\"${esc(title)} vaga ${i + 1}\">\n        <option value=\"\">— vazia —</option>${actives.map((c) => `<option value=\"${esc(c._id)}\"${String(c._id) === cur ? ' selected' : ''}${list === 'home' && !c.imagem && !(Number(c.posicao_home) > 0) ? ' disabled' : ''}>${esc(c.nome)}${list === 'home' && !c.imagem && !(Number(c.posicao_home) > 0) ? ' (sem imagem)' : ''}</option>`).join('')}</select></div>`).join('');\n      return `<div class=\"card\"><h2>${title}</h2><p class=\"cnt${filled < n ? ' warn' : ''}\">${title.split(' ')[0]} com ${filled} de ${n} vagas preenchidas${filled < n ? '' : ''}</p>${rows}</div>`;\n    };\n    const pact = (S.prods || []).filter((x) => x.ativo !== false).sort((a, b) => String(a.nome).localeCompare(String(b.nome), 'pt-BR'));\n    const prodBlock = () => {\n      const arr = S.pslots || []; const filled = arr.filter(Boolean).length;\n      const rows = arr.map((cur, i) => `<div class=\"slot\"><span class=\"n\">Vaga ${i + 1}</span><select class=\"sel\" data-slot=\"prod:${i}\" aria-label=\"Produtos em destaque vaga ${i + 1}\">\n        <option value=\"\">— vazia —</option>${pact.map((x) => `<option value=\"${esc(x._id)}\"${String(x._id) === cur ? ' selected' : ''}>${esc(x.nome)}${x.imagem ? '' : ' (sem foto)'}</option>`).join('')}</select></div>`).join('');\n      return `<div class=\"card wide\"><h2>Produtos em destaque (carrossel da Home)</h2><p class=\"cnt\">${filled} de ${PROD} vagas preenchidas. A ordem das vagas é a ordem do carrossel.</p><div class=\"slots2\">${rows}</div></div>`;\n    };\n    const body = !S.loaded ? '<div class=\"card\"><p class=\"sub\">Carregando categorias…</p></div>'\n      : `<div class=\"cols\">${block('Home (cards de categorias)', 'home', S.home || [], HOME)}${block('Menu (topo da loja)', 'menu', S.menu || [], MENU)}</div>${prodBlock()}\n        <div class=\"foot\"><span data-act=\"save-dest\" style=\"display:inline-block\">${d2.render(P.button, { label: S.busy ? 'Salvando...' : 'Salvar destaques', variant: 'primary', size: 'sm' }, { key: 'save', width: 230, height: 44 })}</span>\n        <span class=\"hint\">Escolher um item que já está em outra vaga troca as duas de lugar. Só itens ativos aparecem.</span></div>`;\n    return `<div class=\"root\">${header}<div class=\"page\"><div class=\"head\"><div><p class=\"eyebrow\">Gestão</p><h1>Destaques</h1><p class=\"sub\">Escolha quais categorias aparecem na home (até 4) e no menu do topo (até 6), e os produtos do carrossel “Produtos em destaque” da home (até 12), sempre na ordem das vagas.</p></div></div>${body}${notice ? notice.replace('class=\"notice\"', 'class=\"notice below\"') : ''}</div></div>`;\n  }\n};"}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"logo":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"logo"}}}},"notice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notice"}}}}}}}}}},{"_id":"6ac5286078f3730f24cd3aef","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"GestaoProdutos","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// Gestão — Produtos (backoffice, só desktop)\n// Lista + formulário (criar/editar) na mesma tela; navegação interna. Reaproveita Logo, Button, Notice, EmptyState e BackLink.\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst norm = (s) => String(s || '').normalize('NFD').replace(/[\\u0300-\\u036f]/g, '').toLowerCase();\nconst slugify = (s) => norm(s).replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');\nconst num = (v) => { if (v === '' || v == null) return undefined; return Number(String(v).trim().replace(',', '.')); };\nconst brl = (v) => (v == null || v === '' || isNaN(Number(v)) ? '—' : Number(v).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }));\nconst s2 = (v) => (v == null ? '' : String(v));\nconst MB = 1024 * 1024;\n\nconst EMPTY_FORM = { nome: '', slug: '', slugTouched: false, marcaTouched: false, sku: '', categoria: '', subcategoria: '', marca: 'Lucas Fontana', origem: 'proprio', parceiro: '',\n  preco: '', precoAntigo: '', parcelas: '', desconto_pix: '', descricao: '', beneficios: '', ficha_tecnica: '', instrucoes_uso: '', social_video: '', ativo: true, destaque: false };\n\nexport default {\n  css: `\n:host { display: block; height: 100%; overflow-y: auto; }\n* { box-sizing: border-box; }\n.root { --red: #c8102e; --ink: #0b0b0c; --white: #fff; --g100: #ececea; --g50: #f5f5f3; --g500: #6b6c70; --g800: #2a2b2e;\n  position: relative; min-height: 100%; background: var(--g50); color: var(--ink);\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased; }\n.notice.below { margin: 20px 0 0; }\n.bar a.nav.on { border-bottom-color: var(--red); }\n.page { max-width: 1240px; margin: 0 auto; padding: 40px 48px 64px; }\n.head { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: 24px; }\n.eyebrow { font-size: 12px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--red); margin: 0 0 8px; }\nh1 { margin: 0; font-size: 34px; font-weight: 800; letter-spacing: -.01em; line-height: 1.1; }\nh3 { margin: 0 0 16px; font-size: 14px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; }\n.sub { margin: 8px 0 0; color: var(--g500); font-size: 15px; }\n.notice { margin-bottom: 16px; }\n.tools { display: flex; align-items: center; gap: 16px; margin-bottom: 16px; flex-wrap: wrap; }\n.search { flex: 1; min-width: 240px; max-width: 360px; height: 44px; border: 1.5px solid var(--g100); background: var(--white); border-radius: 2px; padding: 0 14px; font: inherit; font-size: 14px; color: var(--ink); }\n.search:focus, .inp:focus { outline: 2px solid var(--red); outline-offset: 1px; border-color: var(--ink); }\n.chips { display: flex; gap: 8px; }\n.chip { height: 36px; padding: 0 16px; border: 1.5px solid var(--ink); background: var(--white); color: var(--ink); border-radius: 999px; font: inherit; font-size: 12px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; cursor: pointer; }\n.chip[aria-pressed=\"true\"] { background: var(--ink); color: var(--white); }\n.card { background: var(--white); border: 1px solid var(--g100); border-radius: 2px; }\ntable { width: 100%; border-collapse: collapse; }\nth { text-align: left; font-size: 11px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--g500); padding: 14px 16px; border-bottom: 1px solid var(--g100); }\ntd { padding: 14px 16px; border-bottom: 1px solid var(--g100); font-size: 14px; vertical-align: middle; }\ntr:last-child td { border-bottom: 0; }\ntd.nome { font-weight: 700; } td.nome small { display: block; margin-top: 3px; font-weight: 400; color: var(--g500); font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12px; }\ntd.num { white-space: nowrap; }\n.pill { display: inline-flex; align-items: center; gap: 8px; height: 26px; padding: 0 12px; border-radius: 999px; font-size: 11px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; }\n.pill::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }\n.pill.on { background: var(--g100); color: var(--ink); } .pill.off { background: #fbe9ec; color: var(--red); }\n.yes { font-weight: 700; } .no { color: var(--g500); font-size: 12px; }\n.acts { display: flex; gap: 14px; justify-content: flex-end; flex-wrap: wrap; }\n.lk { background: none; border: 0; padding: 0; font: inherit; font-size: 12px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--ink); cursor: pointer; border-bottom: 1.5px solid var(--ink); }\n.lk:hover { color: var(--red); border-color: var(--red); } .lk.danger { color: var(--red); border-color: var(--red); }\nlabel.lk { display: inline-block; }\n.count { margin: 12px 2px 0; color: var(--g500); font-size: 13px; }\n.form { padding: 32px; margin-bottom: 20px; }\n.back { margin-bottom: 20px; }\n.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 24px; } .grid3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 0 24px; } .grid4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0 24px; }\n.field { margin-bottom: 22px; }\n.lbl { display: block; font-size: 12px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; margin-bottom: 8px; }\n.inp { width: 100%; height: 48px; border: 1.5px solid var(--g100); background: var(--white); border-radius: 2px; padding: 0 14px; font: inherit; font-size: 15px; color: var(--ink); }\ntextarea.inp { height: auto; min-height: 110px; padding: 12px 14px; line-height: 1.45; resize: vertical; }\n.inp[readonly] { background: var(--g50); color: var(--g500); } .inp.bad { border-color: var(--red); }\n.hint { margin: 6px 0 0; font-size: 13px; color: var(--g500); } .err { margin: 6px 0 0; font-size: 13px; font-weight: 700; color: var(--red); }\n.checks { display: grid; gap: 14px; margin: 4px 0 8px; } .radios { display: flex; gap: 28px; padding: 12px 0; }\n.ck { display: flex; align-items: flex-start; gap: 12px; cursor: pointer; font-size: 15px; }\n.ck input { width: 20px; height: 20px; margin: 1px 0 0; accent-color: var(--ink); flex: none; }\n.ck small { display: block; color: var(--g500); font-size: 13px; margin-top: 2px; }\n.warn { margin: 16px 0 24px; }\n.btns { display: flex; align-items: center; gap: 12px; padding-top: 8px; } .btns .sp { flex: 1; }\n.empty { padding: 24px; }\n.gal { display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px; }\n.slot { border: 1.5px dashed var(--g100); background: var(--g50); padding: 10px; display: flex; flex-direction: column; gap: 10px; min-height: 190px; }\n.slot.full { border-style: solid; background: var(--white); }\n.slot .pos { font-size: 11px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--g500); }\n.slot .med { width: 100%; aspect-ratio: 1 / 1; background: var(--g100) center / cover no-repeat; display: flex; align-items: center; justify-content: center; color: var(--g500); font-size: 12px; overflow: hidden; }\n.slot .med video { width: 100%; height: 100%; object-fit: cover; }\n.rels { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }\n.rchip { display: inline-flex; align-items: center; gap: 10px; background: var(--g100); border-radius: 999px; padding: 6px 8px 6px 14px; font-size: 13px; font-weight: 700; }\n.rchip button { border: 0; background: var(--ink); color: var(--white); width: 20px; height: 20px; border-radius: 50%; cursor: pointer; font-size: 12px; line-height: 1; }\n.cands { border: 1px solid var(--g100); margin-top: 8px; } .cand { display: flex; justify-content: space-between; align-items: center; padding: 10px 14px; border-bottom: 1px solid var(--g100); font-size: 14px; } .cand:last-child { border-bottom: 0; }\n.ovl { position: fixed; inset: 0; background: rgba(11,11,12,.55); display: flex; align-items: flex-start; justify-content: center; padding-top: 200px; z-index: 10; }\n.dlg { width: 480px; max-width: calc(100% - 32px); background: var(--white); border-radius: 2px; padding: 32px; box-shadow: 0 24px 64px rgba(0,0,0,.35); }\n.dlg h2 { margin: 0 0 12px; font-size: 22px; font-weight: 800; }\n.dlg p { margin: 0 0 24px; color: var(--g800); font-size: 15px; line-height: 1.5; }\n.dlg .row { display: flex; gap: 12px; justify-content: flex-end; }\n`,\n\n  mounted(d2) {\n    if (typeof document !== 'undefined' && document.head && !document.getElementById('lf-archivo-font')) {\n      const l = document.createElement('link');\n      l.id = 'lf-archivo-font'; l.rel = 'stylesheet';\n      l.href = 'https://fonts.googleapis.com/css2?family=Archivo:ital,wdth,wght@0,62..125,100..900;1,62..125,100..900&display=swap';\n      document.head.appendChild(l);\n    }\n    const S = d2.state;\n    const unwrap = (res) => (res && res.data !== undefined ? res.data : res);\n    const call = async (name, body) => unwrap(await d2.rush(name).invoke(body || {}));\n    const say = (tone, body) => { S.notice = { tone, body }; };\n    const items = () => S.items || [];\n\n    const reload = async () => {\n      try {\n        const out = await call('gestaoProdutosListar');\n        S.items = Array.isArray(out && out.produtos) ? out.produtos : [];\n        S.cats = Array.isArray(out && out.categorias) ? out.categorias : [];\n        S.parceiros = Array.isArray(out && out.parceiros) ? out.parceiros : [];\n      } catch (e) { say('error', 'Não foi possível carregar os produtos.'); }\n      S.loaded = true;\n    };\n\n    const fillFromServer = (out) => {\n      const p = out.produto;\n      S.editingId = p._id;\n      S.form = { nome: s2(p.nome), slug: s2(p.slug), slugTouched: true, marcaTouched: true, sku: s2(p.sku), categoria: s2(p.categoria), subcategoria: s2(p.subcategoria),\n        marca: s2(p.marca), origem: p.origem === 'parceiro' ? 'parceiro' : 'proprio', parceiro: s2(p.parceiro), preco: s2(p.preco), precoAntigo: s2(p.precoAntigo),\n        parcelas: s2(p.parcelas), desconto_pix: s2(p.desconto_pix), descricao: s2(p.descricao), beneficios: s2(p.beneficios), ficha_tecnica: s2(p.ficha_tecnica),\n        instrucoes_uso: s2(p.instrucoes_uso), social_video: s2(p.social_video), ativo: p.ativo !== false, destaque: p.destaque === true };\n      S.galeria = out.galeria || [];\n      S.rels = out.relacionados || [];\n      S.original = { ativo: p.ativo !== false, vendas: Number(p.vendas) || 0 };\n      S.errors = {}; S.notice = null; S.upErr = ''; S.relQ = '';\n    };\n\n    const openNew = () => { S.editingId = null; S.form = { ...EMPTY_FORM }; S.galeria = []; S.rels = []; S.original = null; S.errors = {}; S.notice = null; S.upErr = ''; S.relQ = ''; S.view = 'form'; };\n    const openEdit = async (id) => {\n      if (S.busy) return;\n      S.busy = true;\n      try {\n        const out = await call('gestaoProdutoObter', { id });\n        if (!out || out.ok === false) { say('error', (out && out.error) || 'Não foi possível abrir o produto.'); }\n        else { fillFromServer(out); S.view = 'form'; }\n      } catch (e) { say('error', 'Não foi possível abrir o produto.'); }\n      S.busy = false;\n    };\n    const backToList = () => { S.view = 'lista'; S.errors = {}; };\n    const askConfirm = (kind, rec, fromForm) => { S.confirm = { kind, id: rec._id, nome: rec.nome || (S.form && S.form.nome) || '', ordem: rec.ordem, fromForm: !!fromForm }; };\n\n    const validate = () => {\n      const f = S.form || EMPTY_FORM; const e = {};\n      const empty = (v) => !String(v == null ? '' : v).trim();\n      if (empty(f.nome)) e.nome = 'Informe o nome do produto.';\n      const sl = slugify(f.slug);\n      if (!sl) e.slug = 'Informe o endereço (slug) da página.';\n      else if (items().some((r) => String(r._id) !== String(S.editingId) && String(r.slug || '').toLowerCase() === sl)) e.slug = 'Já existe um produto com esse slug.';\n      if (empty(f.categoria)) e.categoria = 'Escolha uma categoria.';\n      if (empty(f.marca)) e.marca = 'Informe a marca.';\n      if (f.origem === 'parceiro' && empty(f.parceiro)) e.parceiro = 'Escolha o parceiro deste produto.';\n      const preco = num(f.preco);\n      if (preco === undefined || isNaN(preco) || preco <= 0) e.preco = 'Informe um preço maior que zero.';\n      const antigo = num(f.precoAntigo);\n      if (antigo !== undefined && (isNaN(antigo) || antigo <= 0)) e.precoAntigo = 'Preço inválido.';\n      const parc = num(f.parcelas);\n      if (parc !== undefined && (isNaN(parc) || parc < 1 || parc % 1 !== 0)) e.parcelas = 'Use um número inteiro a partir de 1.';\n      const pix = num(f.desconto_pix);\n      if (pix !== undefined && (isNaN(pix) || pix < 0 || pix > 100)) e.desconto_pix = 'O desconto Pix deve ficar entre 0 e 100%.';\n      if (empty(f.descricao)) e.descricao = 'Informe a descrição.';\n      S.errors = e;\n      return Object.keys(e).length === 0;\n    };\n\n    const doSave = async () => {\n      const f = S.form;\n      const payload = { id: S.editingId || undefined, nome: String(f.nome).trim(), slug: slugify(f.slug), sku: String(f.sku || '').trim(), categoria: f.categoria,\n        subcategoria: String(f.subcategoria || '').trim(), marca: String(f.marca).trim(), origem: f.origem, parceiro: f.origem === 'parceiro' ? f.parceiro : undefined,\n        preco: num(f.preco), precoAntigo: num(f.precoAntigo), parcelas: num(f.parcelas), desconto_pix: num(f.desconto_pix), descricao: String(f.descricao).trim(),\n        beneficios: String(f.beneficios || '').trim(), ficha_tecnica: String(f.ficha_tecnica || '').trim(), instrucoes_uso: String(f.instrucoes_uso || '').trim(),\n        social_video: String(f.social_video || '').trim(), ativo: !!f.ativo, relacionados: S.rels || [] };\n      S.busy = true;\n      try {\n        const out = await call('gestaoProdutoSalvar', payload);\n        if (out && out.ok === false) { say('error', out.error || 'Não foi possível salvar o produto.'); S.busy = false; return; }\n        const wasNew = !S.editingId;\n        await reload();\n        if (wasNew && out && out.id) {\n          const o = await call('gestaoProdutoObter', { id: out.id });\n          if (o && o.ok !== false) fillFromServer(o);\n          say('success', 'Produto criado. Agora você pode enviar fotos e vídeos para a galeria.');\n        } else { say('success', 'Produto atualizado.'); backToList(); }\n      } catch (e) { say('error', 'Não foi possível salvar o produto. Tente de novo.'); }\n      S.busy = false;\n    };\n\n    const save = async () => {\n      if (S.busy || !validate()) return;\n      if (S.editingId && S.original && S.original.ativo && !S.form.ativo) { askConfirm('desativar', { _id: S.editingId, nome: S.form.nome }, true); return; }\n      await doSave();\n    };\n\n    const refreshGaleria = async () => {\n      const o = await call('gestaoProdutoObter', { id: S.editingId });\n      if (o && o.ok !== false) S.galeria = o.galeria || [];\n      await reload();\n    };\n\n    const confirmGo = async () => {\n      if (!S.confirm || S.busy) return;\n      const c = S.confirm;\n      if (c.kind === 'desativar' && c.fromForm) { S.confirm = null; await doSave(); return; }\n      S.busy = true;\n      try {\n        if (c.kind === 'desativar') {\n          const out = await call('gestaoProdutoAtivar', { id: c.id, ativo: false });\n          if (out && out.ok === false) say('error', out.error || 'Não foi possível desativar.'); else say('success', 'Produto desativado. Ele não aparece mais na loja.');\n        } else if (c.kind === 'excluir') {\n          const out = await call('gestaoProdutoExcluir', { id: c.id });\n          if (out && out.ok === false) say('error', out.error || 'Não foi possível excluir.'); else { say('success', 'Produto excluído.'); }\n          if (S.view === 'form') backToList();\n        } else if (c.kind === 'arquivo') {\n          const out = await call('gestaoGaleriaRemover', { id: c.id });\n          if (out && out.ok === false) S.upErr = out.error || 'Não foi possível remover o arquivo.'; else { S.upErr = ''; await refreshGaleria(); }\n        }\n        S.confirm = null; S.busy = false; await reload();\n      } catch (e) { S.busy = false; S.confirm = null; say('error', 'Não foi possível concluir a ação. Nada foi alterado.'); }\n    };\n\n    const toggleAtivo = async (id) => {\n      const r = items().find((x) => String(x._id) === String(id)); if (!r) return;\n      if (r.ativo !== false) { askConfirm('desativar', r, false); return; }\n      try {\n        const out = await call('gestaoProdutoAtivar', { id: r._id, ativo: true });\n        if (out && out.ok === false) { say('error', out.error || 'Não foi possível reativar.'); return; }\n        await reload(); say('success', 'Produto reativado.');\n      } catch (e) { say('error', 'Não foi possível reativar o produto.'); }\n    };\n\n    const createParc = async () => {\n      const np = S.np || {}; if (S.busy) return;\n      const nome = String(np.nome || '').trim();\n      if (!nome) { S.np = { ...np, err: 'Informe o nome do parceiro.' }; return; }\n      S.busy = true;\n      try {\n        const out = await call('gestaoParceiroSalvar', { nome, site: String(np.site || '').trim() });\n        if (!out || out.ok === false) { S.np = { ...np, err: (out && out.error) || 'Não foi possível cadastrar o parceiro.' }; }\n        else {\n          await reload();\n          const f = { ...(S.form || EMPTY_FORM), parceiro: out.id }; if (!f.marcaTouched) f.marca = nome;\n          S.form = f; S.np = { open: false };\n        }\n      } catch (e) { S.np = { ...np, err: 'Não foi possível cadastrar o parceiro. Tente de novo.' }; }\n      S.busy = false;\n    };\n\n    const readB64 = (file) => new Promise((r, j) => { const fr = new FileReader(); fr.onload = () => r(String(fr.result).split(',')[1]); fr.onerror = j; fr.readAsDataURL(file); });\n\n    d2.on('[data-act]', 'click', (e, el) => {\n      const act = el.getAttribute('data-act'); const id = el.getAttribute('data-id');\n      if (act === 'new') openNew(); else if (act === 'save') save(); else if (act === 'back') backToList(); else if (act === 'confirm-go') confirmGo();\n      else if (act === 'edit') openEdit(id); else if (act === 'toggle') toggleAtivo(id);\n      else if (act === 'delete') { const r = items().find((x) => String(x._id) === String(id)); if (r) askConfirm('excluir', r, false); }\n      else if (act === 'delete-form') askConfirm('excluir', { _id: S.editingId, nome: S.form.nome }, true);\n      else if (act === 'toggle-form') { if (S.form.ativo) { if (S.editingId) askConfirm('desativar', { _id: S.editingId, nome: S.form.nome }, true); } else { S.form = { ...S.form, ativo: true }; } }\n      else if (act === 'cancel-confirm') S.confirm = null;\n      else if (act === 'filter') S.fStatus = el.getAttribute('data-v');\n      else if (act === 'gal-rm') askConfirm('arquivo', { _id: id, nome: 'arquivo', ordem: el.getAttribute('data-o') }, true);\n      else if (act === 'rel-add') { if (!(S.rels || []).includes(id)) S.rels = (S.rels || []).concat([id]); S.relQ = ''; }\n      else if (act === 'rel-rm') S.rels = (S.rels || []).filter((x) => x !== id);\n      else if (act === 'parc-toggle') S.np = (S.np && S.np.open) ? { open: false } : { open: true, nome: '', site: '', err: '' };\n      else if (act === 'parc-save') createParc();\n    });\n    d2.on('[data-f]', 'input', (e, el) => {\n      const k = el.getAttribute('data-f'); const f = { ...(S.form || EMPTY_FORM) };\n      f[k] = el.value;\n      if (k === 'nome' && !S.editingId && !f.slugTouched) f.slug = slugify(el.value);\n      if (k === 'slug') f.slugTouched = true;\n      if (k === 'marca') f.marcaTouched = true;\n      S.form = f;\n    });\n    d2.on('[data-s]', 'change', (e, el) => {\n      const k = el.getAttribute('data-s'); const f = { ...(S.form || EMPTY_FORM) };\n      f[k] = el.value;\n      const pNome = (id) => { const p = (S.parceiros || []).find((x) => String(x._id) === String(id)); return p ? p.nome : ''; };\n      if (k === 'origem' && !f.marcaTouched) f.marca = el.value === 'proprio' ? 'Lucas Fontana' : pNome(f.parceiro);\n      if (k === 'parceiro' && !f.marcaTouched) f.marca = pNome(el.value);\n      S.form = f;\n    });\n    d2.on('[data-c]', 'change', (e, el) => { S.form = { ...(S.form || EMPTY_FORM), [el.getAttribute('data-c')]: !!el.checked }; });\n    d2.on('[data-q]', 'input', (e, el) => { S.q = el.value; });\n    d2.on('[data-np]', 'input', (e, el) => { S.np = { ...(S.np || {}), [el.getAttribute('data-np')]: el.value }; });\n    d2.on('[data-fc]', 'change', (e, el) => { S.fCat = el.value; });\n    d2.on('[data-fo]', 'change', (e, el) => { S.fOrg = el.value; });\n    d2.on('[data-rq]', 'input', (e, el) => { S.relQ = el.value; });\n    d2.on('[data-up]', 'change', async (e, el) => {\n      const file = el.files && el.files[0]; const slot = Number(el.getAttribute('data-up')); el.value = '';\n      if (!file || !S.editingId) return;\n      S.upErr = '';\n      const isImg = /^image\\/(jpeg|png|webp)$/.test(file.type); const isVid = /^video\\/(mp4|webm)$/.test(file.type);\n      if (!isImg && !isVid) { S.upErr = 'Formato não aceito. Use JPG, PNG ou WebP para fotos e MP4 ou WebM para vídeos.'; return; }\n      if (isImg && file.size > 5 * MB) { S.upErr = 'A foto passa de 5 MB. Escolha uma menor.'; return; }\n      if (isVid && file.size > 20 * MB) { S.upErr = 'O vídeo passa de 20 MB. Escolha um menor.'; return; }\n      if ((S.galeria || []).some((g) => Number(g.ordem) === slot)) { S.upErr = 'A posição ' + slot + ' da galeria já está ocupada.'; return; }\n      S.upBusy = slot;\n      try {\n        const b64 = await readB64(file);\n        const out = await call('gestaoGaleriaEnviar', { produtoId: S.editingId, ordem: slot, base64: b64, contentType: file.type });\n        if (!out || out.ok === false) S.upErr = (out && out.error) || 'Não foi possível enviar o arquivo.';\n        else await refreshGaleria();\n      } catch (err) { S.upErr = 'Não foi possível enviar o arquivo. Tente de novo.'; }\n      S.upBusy = 0;\n    });\n\n    reload();\n  },\n\n  render(d2) {\n    const S = d2.state;\n    const P = d2.params || {};\n    if (S.view === undefined) {\n      S.view = P.view === 'form' ? 'form' : 'lista';\n      S.fStatus = 'todos'; S.fCat = ''; S.fOrg = ''; S.q = ''; S.form = { ...EMPTY_FORM }; S.errors = {}; S.editingId = null; S.confirm = null; S.notice = null; S.busy = false; S.galeria = []; S.rels = []; S.upBusy = 0; S.upErr = ''; S.relQ = '';\n    }\n    const btn = (label, variant, act, key, w) => `<span data-act=\"${act}\" style=\"display:inline-block\">${d2.render(P.button, { label, variant, size: 'sm' }, { key, width: w, height: 44 })}</span>`;\n    const rows = (S.items || []).slice().sort((a, b) => String(a.nome).localeCompare(String(b.nome), 'pt-BR'));\n    const catName = (id) => { const c = (S.cats || []).find((x) => String(x._id) === String(id)); return c ? c.nome : '—'; };\n    const parcName = (id) => { const p = (S.parceiros || []).find((x) => String(x._id) === String(id)); return p ? p.nome : ''; };\n\n    let confirm = S.confirm;\n    if (!confirm && P.demoConfirm && rows.length) confirm = { kind: 'desativar', id: rows[0]._id, nome: rows[0].nome, fromForm: false };\n\n    const header = ''; // o menu fica no componente GestaoMenu (bloco no topo de cada tela)\n    const notice = S.notice ? `<div class=\"notice\">${d2.render(P.notice, { tone: S.notice.tone === 'error' ? 'error' : 'success', body: S.notice.body, live: true }, { key: 'notice', height: 64 })}</div>` : '';\n\n    const noticeBelow = notice ? notice.replace('class=\"notice\"', 'class=\"notice below\"') : '';\n    let main = '';\n    if (S.view === 'form') {\n      const f = S.form || EMPTY_FORM; const e = S.errors || {}; const edit = !!S.editingId;\n      const err = (k) => (e[k] ? `<p class=\"err\">${esc(e[k])}</p>` : '');\n      const inp = (k, label, ph, opts) => { const o = opts || {}; return `<div class=\"field\"><label class=\"lbl\" for=\"f-${k}\">${label}</label><input id=\"f-${k}\" class=\"inp ${e[k] ? 'bad' : ''}\" data-f=\"${k}\" value=\"${esc(f[k])}\" placeholder=\"${esc(ph || '')}\" ${o.ro ? 'readonly' : ''} autocomplete=\"off\">${e[k] ? err(k) : (o.hint ? `<p class=\"hint\">${o.hint}</p>` : '')}</div>`; };\n      const ta = (k, label, ph, hint) => `<div class=\"field\"><label class=\"lbl\" for=\"f-${k}\">${label}</label><textarea id=\"f-${k}\" class=\"inp ${e[k] ? 'bad' : ''}\" data-f=\"${k}\" placeholder=\"${esc(ph || '')}\">${esc(f[k])}</textarea>${e[k] ? err(k) : (hint ? `<p class=\"hint\">${hint}</p>` : '')}</div>`;\n      const catOpts = (S.cats || []).filter((c) => c.ativa !== false || String(c._id) === String(f.categoria)).map((c) => `<option value=\"${esc(c._id)}\" ${String(c._id) === String(f.categoria) ? 'selected' : ''}>${esc(c.nome)}${c.ativa === false ? ' (inativa)' : ''}</option>`).join('');\n      const parcOpts = (S.parceiros || []).map((p) => `<option value=\"${esc(p._id)}\" ${String(p._id) === String(f.parceiro) ? 'selected' : ''}>${esc(p.nome)}</option>`).join('');\n      const vendas = S.original ? S.original.vendas : 0;\n\n      const slots = [1, 2, 3, 4, 5].map((n) => {\n        const g = (S.galeria || []).find((x) => Number(x.ordem) === n);\n        const isVid = g && /^video\\//.test(String(g.tipo || ''));\n        const media = g ? (isVid ? `<div class=\"med\"><video src=\"${esc(g.url)}\" muted preload=\"metadata\"></video></div>` : `<div class=\"med\" style=\"background-image:url('${esc(g.url)}')\"></div>`) : `<div class=\"med\">${S.upBusy === n ? 'Enviando…' : 'Vazio'}</div>`;\n        const act = g ? `<button class=\"lk danger\" data-act=\"gal-rm\" data-id=\"${esc(g._id)}\" data-o=\"${n}\">Remover</button>` : `<label class=\"lk\">${S.upBusy === n ? 'Enviando…' : 'Enviar'}<input type=\"file\" data-up=\"${n}\" accept=\"image/jpeg,image/png,image/webp,video/mp4,video/webm\" hidden></label>`;\n        return `<div class=\"slot ${g ? 'full' : ''}\" data-key=\"slot-${n}\"><span class=\"pos\">Posição ${n}${g ? (isVid ? ' · vídeo' : ' · foto') : ''}</span>${media}${act}</div>`;\n      }).join('');\n      const galeria = edit\n        ? `<div class=\"gal\">${slots}</div>${S.upErr ? `<p class=\"err\">${esc(S.upErr)}</p>` : ''}<p class=\"hint\">Cada posição (1 a 5) aceita um único arquivo. Fotos JPG, PNG ou WebP até 5 MB; vídeos MP4 ou WebM até 20 MB. A foto da posição 1 vira a foto principal do produto.</p>`\n        : `<p class=\"hint\">Salve o produto para liberar o envio de fotos e vídeos.</p>`;\n\n      const relSel = (S.rels || []).map((id) => { const r = rows.find((x) => String(x._id) === String(id)); return `<span class=\"rchip\" data-key=\"rc-${esc(id)}\">${esc(r ? r.nome : id)}<button data-act=\"rel-rm\" data-id=\"${esc(id)}\" aria-label=\"Remover\">×</button></span>`; }).join('');\n      const rq = norm(S.relQ);\n      const cands = rq ? rows.filter((r) => String(r._id) !== String(S.editingId) && !(S.rels || []).includes(r._id) && r.ativo !== false && (norm(r.nome).includes(rq) || norm(r.sku).includes(rq))).slice(0, 6) : [];\n      const relBox = `<div class=\"rels\">${relSel || '<span class=\"hint\" style=\"margin:0\">Nenhum produto relacionado.</span>'}</div>\n        <input class=\"search\" style=\"max-width:100%\" data-rq placeholder=\"Buscar produto pelo nome ou SKU para relacionar\" value=\"${esc(S.relQ)}\" aria-label=\"Buscar produto relacionado\">\n        ${rq ? `<div class=\"cands\">${cands.length ? cands.map((r) => `<div class=\"cand\" data-key=\"cd-${esc(r._id)}\"><span>${esc(r.nome)}</span><button class=\"lk\" data-act=\"rel-add\" data-id=\"${esc(r._id)}\">Adicionar</button></div>`).join('') : '<div class=\"cand\"><span class=\"no\">Nenhum produto ativo encontrado.</span></div>'}</div>` : ''}`;\n\n      const delBtn = !edit ? '' : '<button class=\"lk danger\" data-act=\"delete-form\">Excluir produto</button>';\n      const togBtn = edit ? `<button class=\"lk\" data-act=\"toggle-form\">${f.ativo ? 'Desativar produto' : 'Marcar como ativo'}</button>` : '';\n\n      main = `\n<div class=\"page\">\n  <div class=\"back\"><span data-act=\"back\" style=\"display:inline-block\">${d2.render(P.backLink, { label: 'Voltar para produtos' }, { key: 'back', width: 260, height: 32 })}</span></div>\n  <div class=\"head\"><div><p class=\"eyebrow\">Produtos</p><h1>${edit ? 'Editar produto' : 'Novo produto'}</h1>\n    <p class=\"sub\">${edit ? 'Altere os dados e salve.' : 'Cadastre um produto próprio ou de uma marca parceira.'}</p></div></div>\n  <div class=\"card form\"><h3>Dados do produto</h3>\n    <div class=\"grid2\">${inp('nome', 'Nome', 'Ex.: Shampoo automotivo neutro')}${inp('slug', 'Slug (endereço da página)', 'shampoo-automotivo-neutro', { ro: edit, hint: edit ? 'O slug não muda depois de criado.' : 'Gerado a partir do nome. Pode editar antes de salvar.' })}</div>\n    <div class=\"grid3\">${inp('sku', 'SKU', 'LF-LAV-001')}\n      <div class=\"field\"><label class=\"lbl\" for=\"f-categoria\">Categoria</label><select id=\"f-categoria\" class=\"inp ${e.categoria ? 'bad' : ''}\" data-s=\"categoria\"><option value=\"\">Escolha…</option>${catOpts}</select>${err('categoria')}</div>\n      ${inp('subcategoria', 'Subcategoria', 'Ex.: Lavagem')}</div>\n    <div class=\"grid2\"><div class=\"field\"><span class=\"lbl\">Origem</span><div class=\"radios\">\n        <label class=\"ck\"><input type=\"radio\" name=\"origem\" data-s=\"origem\" value=\"proprio\" ${f.origem === 'proprio' ? 'checked' : ''}><span>Próprio</span></label>\n        <label class=\"ck\"><input type=\"radio\" name=\"origem\" data-s=\"origem\" value=\"parceiro\" ${f.origem === 'parceiro' ? 'checked' : ''}><span>Parceiro</span></label></div></div>\n      ${f.origem === 'parceiro' ? `<div class=\"field\"><label class=\"lbl\" for=\"f-parceiro\">Parceiro</label><select id=\"f-parceiro\" class=\"inp ${e.parceiro ? 'bad' : ''}\" data-s=\"parceiro\"><option value=\"\">Escolha…</option>${parcOpts}</select>${err('parceiro')}${(S.parceiros || []).length ? '' : '<p class=\"hint\">Nenhum parceiro cadastrado ainda.</p>'}<button class=\"lk\" data-act=\"parc-toggle\" style=\"margin-top:10px\">${S.np && S.np.open ? 'Cancelar novo parceiro' : '+ Novo parceiro'}</button>${S.np && S.np.open ? `<div class=\"grid2\" style=\"margin-top:12px\"><div><input class=\"inp\" data-np=\"nome\" placeholder=\"Nome do parceiro\" value=\"${esc(S.np.nome)}\"></div><div><input class=\"inp\" data-np=\"site\" placeholder=\"Site (opcional)\" value=\"${esc(S.np.site)}\"></div></div>${S.np.err ? `<p class=\"err\">${esc(S.np.err)}</p>` : ''}<div style=\"margin-top:12px\"><button class=\"lk\" data-act=\"parc-save\">Cadastrar parceiro</button></div>` : ''}</div>` : '<div></div>'}</div>\n    ${inp('marca', 'Marca', 'Ex.: Lucas Fontana')}\n    <h3 style=\"margin-top:12px\">Preço</h3>\n    <div class=\"grid4\">${inp('preco', 'Preço (R$)', '129,90')}${inp('precoAntigo', 'Preço \"de\" (riscado)', 'Opcional')}${inp('parcelas', 'Parcelas sem juros', 'Ex.: 3')}${inp('desconto_pix', 'Desconto Pix (%)', 'Ex.: 5')}</div>\n    <h3 style=\"margin-top:12px\">Conteúdo</h3>\n    ${ta('descricao', 'Descrição', 'Conte o que é o produto e para que serve.')}\n    <div class=\"grid2\">${ta('beneficios', 'Benefícios', 'Um benefício por linha.')}${ta('ficha_tecnica', 'Ficha técnica', 'Ex.: Volume: 500 ml')}</div>\n    <div class=\"grid2\">${ta('instrucoes_uso', 'Instruções de uso', 'Como aplicar, em passos curtos.')}${inp('social_video', 'Vídeo (YouTube ou Instagram)', 'https://', { hint: 'Link do vídeo que mostra o produto em uso.' })}</div>\n    <h3 style=\"margin-top:12px\">Visibilidade</h3>\n    <div class=\"checks\">\n      <label class=\"ck\"><input type=\"checkbox\" data-c=\"ativo\" ${f.ativo ? 'checked' : ''}><span>Ativo<small>Produto inativo some da loja, da busca e dos filtros, mesmo que esteja em destaque na home.</small></span></label>\n      <p class=\"hint\" style=\"margin:0\">Para colocar este produto no carrossel “Produtos em destaque” da Home, use a tela <a href=\"/destaques\">Destaques</a>.</p></div>\n    ${edit && S.original && S.original.ativo && !f.ativo ? `<div class=\"warn\">${d2.render(P.notice, { tone: 'info', body: 'Ao salvar, este produto deixa de aparecer na loja. Vamos pedir uma confirmação.', live: false }, { key: 'warn', height: 64 })}</div>` : ''}\n  </div>\n  <div class=\"card form\"><h3>Galeria (fotos e vídeos)</h3>${galeria}</div>\n  <div class=\"card form\"><h3>Produtos relacionados</h3>${relBox}<p class=\"hint\">Aparecem na página do produto, em \"combina com\". Produtos inativos não aparecem na loja.</p></div>\n  <div class=\"btns\">${btn(edit ? 'Salvar alterações' : 'Criar produto', 'primary', 'save', 'save', 210)}${btn('Cancelar', 'outline', 'back', 'cancel', 130)}<span class=\"sp\"></span>${togBtn}${delBtn}</div>\n  ${noticeBelow}\n</div>`;\n    } else {\n      const q = norm(S.q);\n      const shown = rows.filter((r) => (S.fStatus === 'ativos' ? r.ativo !== false : S.fStatus === 'inativos' ? r.ativo === false : true)\n        && (!S.fCat || String(r.categoria) === String(S.fCat)) && (!S.fOrg || r.origem === S.fOrg)\n        && (!q || norm(r.nome).includes(q) || norm(r.sku).includes(q) || norm(r.slug).includes(q) || norm(r.marca).includes(q)));\n      const chip = (v, l) => `<button class=\"chip\" data-act=\"filter\" data-v=\"${v}\" aria-pressed=\"${S.fStatus === v}\">${l}</button>`;\n      const catSel = `<select class=\"search\" style=\"flex:none;min-width:200px\" data-fc aria-label=\"Filtrar por categoria\"><option value=\"\">Todas as categorias</option>${(S.cats || []).map((c) => `<option value=\"${esc(c._id)}\" ${String(c._id) === String(S.fCat) ? 'selected' : ''}>${esc(c.nome)}</option>`).join('')}</select>`;\n      const orgSel = `<select class=\"search\" style=\"flex:none;min-width:160px\" data-fo aria-label=\"Filtrar por origem\"><option value=\"\">Toda origem</option><option value=\"proprio\" ${S.fOrg === 'proprio' ? 'selected' : ''}>Próprio</option><option value=\"parceiro\" ${S.fOrg === 'parceiro' ? 'selected' : ''}>Parceiro</option></select>`;\n      const body = shown.length ? `\n<div class=\"card\"><table>\n  <thead><tr><th>Produto</th><th>Categoria</th><th>Origem</th><th>Preço</th><th>Galeria</th><th>Status</th><th>Home</th><th></th></tr></thead>\n  <tbody>${shown.map((r) => `\n    <tr data-key=\"${esc(r._id)}\">\n      <td class=\"nome\">${esc(r.nome)}<small>${esc(r.sku || r.slug)}</small></td><td>${esc(catName(r.categoria))}</td>\n      <td>${r.origem === 'parceiro' ? 'Parceiro' + (parcName(r.parceiro) ? ' · ' + esc(parcName(r.parceiro)) : '') : 'Próprio'}</td>\n      <td class=\"num\">${brl(r.preco)}</td><td class=\"${Number(r.fotos) > 0 ? 'yes' : 'no'}\">${Number(r.fotos) || 0}/5</td>\n      <td><span class=\"pill ${r.ativo === false ? 'off' : 'on'}\">${r.ativo === false ? 'Inativo' : 'Ativo'}</span></td>\n      <td class=\"${Number(r.posicaoDestaque) > 0 ? 'yes' : 'no'}\">${Number(r.posicaoDestaque) > 0 ? 'Vaga ' + r.posicaoDestaque : '—'}</td>\n      <td><div class=\"acts\"><button class=\"lk\" data-act=\"edit\" data-id=\"${esc(r._id)}\">Editar</button>\n        <button class=\"lk\" data-act=\"toggle\" data-id=\"${esc(r._id)}\">${r.ativo === false ? 'Ativar' : 'Desativar'}</button>\n        <button class=\"lk danger\" data-act=\"delete\" data-id=\"${esc(r._id)}\">Excluir</button></div></td>\n    </tr>`).join('')}</tbody></table></div>\n<p class=\"count\">${shown.length} de ${rows.length} ${rows.length === 1 ? 'produto' : 'produtos'}</p>`\n        : !S.loaded ? '<div class=\"card empty\"><p class=\"sub\">Carregando produtos…</p></div>' : `<div class=\"card empty\">${d2.render(P.emptyState, { eyebrow: 'Produtos', title: rows.length ? 'Nenhum produto encontrado' : 'Nenhum produto cadastrado', description: rows.length ? 'Tente outro termo ou mude os filtros.' : 'Cadastre o primeiro produto da loja.', iconName: 'search' }, { key: 'empty', height: 260 })}</div>`;\n      main = `\n<div class=\"page\">\n  <div class=\"head\"><div><p class=\"eyebrow\">Gestão</p><h1>Produtos</h1><p class=\"sub\">Cadastre e organize os produtos da loja. Produto inativo não aparece na loja.</p></div>\n    ${btn('Novo produto', 'primary', 'new', 'new', 190)}</div>\n  ${notice}\n  <div class=\"tools\"><input class=\"search\" data-q placeholder=\"Buscar por nome, SKU ou marca\" value=\"${esc(S.q)}\" aria-label=\"Buscar produto\">${catSel}${orgSel}\n    <div class=\"chips\">${chip('todos', 'Todos')}${chip('ativos', 'Ativos')}${chip('inativos', 'Inativos')}</div></div>\n  ${body}\n</div>`;\n    }\n\n    let overlay = '';\n    if (confirm) {\n      const k = confirm.kind;\n      const title = k === 'excluir' ? 'Excluir “' + esc(confirm.nome) + '”?' : k === 'arquivo' ? 'Remover o arquivo da posição ' + esc(confirm.ordem) + '?' : 'Desativar “' + esc(confirm.nome) + '”?';\n      const text = k === 'excluir' ? 'O produto será apagado junto com a galeria e os vínculos de produtos relacionados. Não dá para desfazer.'\n        : k === 'arquivo' ? 'O arquivo sai da galeria e a posição fica livre para outro envio.'\n        : 'O produto deixa de aparecer na loja, na busca e nos filtros, mesmo que esteja marcado como destaque na home. Você pode ativar de novo quando quiser.';\n      const okLabel = k === 'excluir' ? 'Excluir produto' : k === 'arquivo' ? 'Remover arquivo' : 'Desativar produto';\n      overlay = `<div class=\"ovl\"><div class=\"dlg\" role=\"alertdialog\" aria-modal=\"true\"><h2>${title}</h2><p>${text}</p>\n  <div class=\"row\">${btn('Cancelar', 'outline', 'cancel-confirm', 'c-cancel', 130)}${btn(okLabel, k === 'desativar' ? 'primary' : 'brand', 'confirm-go', 'c-ok', 230)}</div></div></div>`;\n    }\n\n    return `<div class=\"root\">${header}${main}${overlay}</div>`;\n  }\n};"}},"backLink":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"backLink"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"demoConfirm":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"demoConfirm"}}}},"emptyState":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"emptyState"}}}},"logo":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"logo"}}}},"notice":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"notice"}}}},"view":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"view"}}}}}}}}}},{"_id":"6ac52dcf80918a4cab959827","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"HomeDestaques","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// HomeDestaques — Loja Lucas Fontana\n// Carrossel \"Produtos em destaque\" da Home: até 12 produtos ativos, na ordem definida na Gestão (tela Destaques).\n// Rolagem lateral (arrastar/deslizar) com encaixe por card.\n// Desktop: setas nas laterais, FORA da área dos cards (o bloco tem uma margem de 72px de cada lado para elas).\n// Tablet e mobile: tracinhos embaixo (o mesmo padrão da ProductGallery no mobile): um tracinho por \"página\" de 2 cards; o tracinho vermelho é a página atual.\n// Lê o serviço público produtosLoja (só produtos ativos) e as categorias ativas (categoriasLoja). Desenha com ProductCard.\nconst esc = (s) => String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst LAYOUT = { desktop: { w: 297, gap: 20, h: 500, vis: 4, arrows: true, pad: 72 }, tablet: { w: 336, gap: 16, h: 495, vis: 2, arrows: false, pad: 0 }, mobile: { w: 169, gap: 12, h: 384, vis: 2, arrows: false, pad: 0 } };\nconst MAX = 12;\nconst DOTS_H = 44;\nlet PRODS = null; let PRODS_LOADING = null; let CATS = null; let CATS_LOADING = null;\n\nexport default {\n  css: `\n:host { display: block; width: 100%; height: 100%; }\n* { box-sizing: border-box; }\n.car { position: relative; width: 100%; }\n.track { display: flex; overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch; scrollbar-width: none; overscroll-behavior-x: contain; }\n.track::-webkit-scrollbar { display: none; }\n.cell { flex: 0 0 auto; scroll-snap-align: start; }\n.nav { position: absolute; top: 146px; width: 48px; height: 48px; margin: 0; padding: 0; border-radius: 50%; border: 0; background: #0b0b0c; color: #ffffff; display: flex; align-items: center; justify-content: center; cursor: pointer; z-index: 2; }\n.nav:hover { background: #c8102e; }\n.nav:focus-visible { outline: 2px solid #c8102e; outline-offset: 2px; }\n.nav.prev { left: 12px; } .nav.next { right: 12px; }\n.nav svg { width: 20px; height: 20px; }\n.dots { display: flex; justify-content: center; gap: 4px; height: 32px; margin-top: 12px; }\n.dots button { width: 38px; height: 32px; margin: 0; padding: 0 4px; border: 0; background: transparent; display: flex; align-items: center; cursor: pointer; }\n.dots button:focus-visible { outline: 2px solid #c8102e; outline-offset: 2px; }\n.dots span { display: block; width: 100%; height: 3px; background: #d9d9d6; }\n.dots [aria-current=\"true\"] span { background: #c8102e; }\n.empty { padding: 24px 0; color: #6b6c70; font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; font-size: 15px; }\n`,\n\n  mounted(d2, root) {\n    const tick = () => { d2.state.tick = Date.now(); };\n    if (!PRODS) {\n      if (!PRODS_LOADING) {\n        PRODS_LOADING = d2.rush('produtosLoja').invoke({ destaque: true }).then((res) => { PRODS = (res && res.data !== undefined ? res.data : res) || []; }).catch(() => { PRODS_LOADING = null; });\n      }\n      if (PRODS_LOADING) PRODS_LOADING.then(tick);\n    }\n    if (!CATS) {\n      if (!CATS_LOADING) {\n        CATS_LOADING = d2.rush('categoriasLoja').invoke({}).then((res) => { CATS = (res && res.data !== undefined ? res.data : res) || []; }).catch(() => { CATS_LOADING = null; });\n      }\n      if (CATS_LOADING) CATS_LOADING.then(tick);\n    }\n    const layoutOf = () => LAYOUT[(d2.params || {}).layout] || LAYOUT.desktop;\n    const trackEl = () => (root && root.querySelector ? root.querySelector('.track') : null);\n    // Setas (desktop): rolam 2 cards por clique\n    d2.on('[data-nav]', 'click', (e, el) => {\n      const tr = trackEl(); if (!tr) return;\n      const L = layoutOf(); const dir = Number(el.getAttribute('data-nav')) || 1;\n      tr.scrollBy({ left: dir * (L.w + L.gap) * 2, behavior: 'smooth' });\n    });\n    // Tracinhos (tablet e mobile): levam à página escolhida\n    d2.on('[data-page]', 'click', (e, el) => {\n      const tr = trackEl(); if (!tr) return;\n      const L = layoutOf(); const pg = Number(el.getAttribute('data-page')) || 0;\n      tr.scrollTo({ left: pg * (L.w + L.gap) * L.vis, behavior: 'smooth' });\n    });\n    // Rolagem: atualiza o tracinho vermelho direto no DOM (scroll não borbulha, por isso captura)\n    if (root && root.addEventListener) {\n      root.addEventListener('scroll', (e) => {\n        const tr = trackEl(); if (!tr || e.target !== tr) return;\n        const dots = root.querySelectorAll ? root.querySelectorAll('.dots button') : [];\n        if (!dots.length) return;\n        const L = layoutOf(); const step = (L.w + L.gap) * L.vis; const max = tr.scrollWidth - tr.clientWidth;\n        const page = tr.scrollLeft >= max - 2 ? dots.length - 1 : Math.min(dots.length - 1, Math.round(tr.scrollLeft / step));\n        dots.forEach((b, i) => b.setAttribute('aria-current', i === page ? 'true' : 'false'));\n      }, true);\n    }\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    void d2.state.tick;\n    const layout = LAYOUT[p.layout] ? p.layout : 'desktop';\n    const L = LAYOUT[layout];\n    const limit = Math.min(MAX, Number(p.limit) > 0 ? Number(p.limit) : MAX);\n    const cats = {}; (CATS || []).forEach((c) => { cats[String(c._id)] = c.nome; });\n    const rows = (PRODS || []).filter((x) => x && x.ativo !== false && Number(x.posicaoDestaque) > 0)\n      .sort((a, b) => Number(a.posicaoDestaque) - Number(b.posicaoDestaque)).slice(0, limit);\n    if (!rows.length) return PRODS ? '<div class=\"empty\">Nenhum produto em destaque no momento.</div>' : '';\n    const card = (x) => d2.render(p.productCard, {\n      layout, priceComponent: p.priceComponent, button: p.button, badge: p.badge, iconComponent: p.iconComponent,\n      brand: cats[String(x.categoria)] || '', name: x.nome, price: x.preco, oldPrice: x.precoAntigo, installments: x.parcelas,\n      pixDiscount: x.desconto_pix, outOfStock: !(Number(x.estoque) > 0), sku: x.sku, href: '/produto/' + x.slug, image: x.imagem || '', partner: x.parceiroNome || ''\n    }, { key: 'c-' + x._id, style: 'width:100%;height:' + L.h + 'px' });\n    const cells = rows.map((x) => `<div class=\"cell\" data-key=\"${esc(x._id)}\" style=\"width:${L.w}px;height:${L.h}px\">${card(x)}</div>`).join('');\n    const overflow = rows.length > L.vis;\n    const arrows = L.arrows && overflow\n      ? `<button class=\"nav prev\" data-nav=\"-1\" aria-label=\"Produtos anteriores\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M15 5l-7 7 7 7\"/></svg></button><button class=\"nav next\" data-nav=\"1\" aria-label=\"Próximos produtos\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 5l7 7-7 7\"/></svg></button>`\n      : '';\n    const pages = Math.ceil(rows.length / L.vis);\n    const showDots = !L.arrows && pages > 1;\n    const dots = showDots\n      ? `<div class=\"dots\" role=\"tablist\" aria-label=\"Páginas do carrossel\">${Array.from({ length: pages }).map((_, i) => `<button data-page=\"${i}\" role=\"tab\" aria-label=\"Página ${i + 1} de ${pages}\" aria-current=\"${i === 0 ? 'true' : 'false'}\"><span></span></button>`).join('')}</div>`\n      : '';\n    const total = L.h + (showDots ? DOTS_H : 0);\n    return `<div class=\"car\" style=\"height:${total}px;padding:0 ${L.pad}px\"><div class=\"track\" style=\"height:${L.h}px;gap:${L.gap}px\">${cells}</div>${arrows}${dots}</div>`;\n  }\n};"}},"badge":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"badge"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"limit":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"limit"}}}},"priceComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"priceComponent"}}}},"productCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"productCard"}}}}}}}}}},{"_id":"6ac575cfa8fc5b5f763cb506","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"ProdutoConteudo","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// ProdutoConteudo — Loja Lucas Fontana\n// O miolo da página /produto/:slug: lê o slug da rota, busca o produto no serviço público produtoLoja e desenha\n// ProductLayout (breadcrumb + galeria + BuyBox), Tabs (Descrição / Como usar / Ficha técnica) e a faixa \"Combina com\".\n// Não desenha nada disso: reaproveita ProductLayout, Tabs, ProductCard, SectionHeader e EmptyState por parâmetro.\n// Estados: carregando (bloco cinza), produto não encontrado ou inativo (EmptyState), erro de rede (EmptyState).\n// O serviço NÃO devolve estoque nem vendas: só `disponivel` (true/false).\n// Abas sem conteúdo não aparecem; sem relacionados cadastrados, a faixa \"Combina com\" some.\n// SEO/GEO: ao carregar, ajusta o título da aba, a meta description, as tags Open Graph, o canonical e o JSON-LD (schema.org Product).\n// `slugFixo` só serve para pré-visualizar no builder (na rota o slug vem da URL).\nconst LAYOUTS = ['desktop', 'tablet', 'mobile'];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst list = (v) => Array.isArray(v) ? v : [];\nconst FF = \"'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif\";\nconst TTL = 60000;\nconst CACHE = {};\nconst LOADING = {};\nconst ERR = {};\nlet SEO_SLUG = '';\nconst MAX_REL = 4;\nconst REL = {\n  desktop: { pad: '96px 96px 96px', hh: 80, gap: 40, cols: 4, cellH: 500, colGap: 20, rowGap: 20 },\n  tablet: { pad: '80px 40px 80px', hh: 90, gap: 32, cols: 2, cellH: 495, colGap: 16, rowGap: 16 },\n  mobile: { pad: '64px 20px 64px', hh: 100, gap: 24, cols: 2, cellH: 384, colGap: 12, rowGap: 12 }\n};\nconst SK_H = { desktop: 760, tablet: 900, mobile: 700 };\n\n// Sacola no navegador (mesma chave da página Sacola): [{sku, qty}]\nconst addToBag = (sku, qty) => {\n  if (!sku) return;\n  try {\n    const bag = JSON.parse(localStorage.getItem('lf-sacola') || '[]');\n    const l = Array.isArray(bag) ? bag : [];\n    const f = l.find((y) => y && y.sku === sku);\n    if (f) f.qty = (Number(f.qty) || 0) + (Number(qty) || 1); else l.push({ sku, qty: Number(qty) || 1 });\n    localStorage.setItem('lf-sacola', JSON.stringify(l));\n    window.dispatchEvent(new CustomEvent('lf-sacola', { detail: { count: l.reduce((s, y) => s + (Number(y.qty) || 0), 0) } }));\n  } catch (e) { /* sem storage */ }\n};\n\nconst routerOf = (d2) => {\n  try { const r = d2.router('appRouter'); if (r && typeof r.goTo === 'function') return r; } catch (e) { /* tenta o padrão */ }\n  try { const r = d2.router(); if (r && typeof r.goTo === 'function') return r; } catch (e) { /* sem router */ }\n  return null;\n};\nconst go = (d2, path) => {\n  const r = routerOf(d2);\n  if (r) { try { r.goTo(path); return; } catch (e) { /* cai para o navegador */ } }\n  if (typeof window !== 'undefined') window.location.assign(path);\n};\nconst slugOf = (d2) => {\n  let s = '';\n  const r = routerOf(d2);\n  try { s = (r && r.params && r.params.slug) || ''; } catch (e) { s = ''; }\n  if (!s && typeof window !== 'undefined' && window.location) {\n    const m = String(window.location.pathname || '').match(/\\/produto\\/([^\\/?#]+)/);\n    if (m) s = m[1];\n  }\n  if (!s) s = String(d2.param('slugFixo', '') || '');\n  try { s = decodeURIComponent(s); } catch (e) { /* mantém */ }\n  return String(s).trim().toLowerCase();\n};\n\nconst ensure = (d2, slug) => {\n  if (!slug || LOADING[slug] || ERR[slug]) return;\n  const c = CACHE[slug];\n  if (c && Date.now() - c.t < TTL) return;\n  LOADING[slug] = d2.rush('produtoService').invoke({ slug }).then((res) => {\n    const out = (res && res.data !== undefined ? res.data : res) || {};\n    CACHE[slug] = { t: Date.now(), out: out && out.ok ? out : { ok: false } };\n  }).catch(() => { ERR[slug] = true; }).then(() => { delete LOADING[slug]; d2.state.tick = Date.now(); });\n};\n\nconst slugify = (s) => String(s || '').normalize('NFD').replace(/[\\u0300-\\u036f]/g, '').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');\nconst LISTA = '/lista-de-produtos/q';\nconst lines = (t) => String(t == null ? '' : t).split(/\\n/).map((s) => s.trim()).filter(Boolean);\nconst asSpecs = (t) => {\n  const ls = lines(t);\n  const pairs = ls.map((l) => { const m = l.match(/^([^:]{1,40}):\\s*(.+)$/); return m ? [m[1].trim(), m[2].trim()] : null; });\n  return ls.length >= 2 && pairs.every(Boolean) ? pairs : null;\n};\nconst buildTabs = (pr) => {\n  const items = [];\n  const benefits = lines(pr.beneficios);\n  if (String(pr.descricao || '').trim() || benefits.length) items.push({ label: 'Descrição', body: pr.descricao || '', benefits });\n  const uso = String(pr.instrucoes_uso || '').trim();\n  const video = String(pr.social_video || '').trim();\n  if (uso || video) items.push(Object.assign({ label: 'Como usar', body: uso }, video ? { videoHref: video, videoLabel: 'Ver o vídeo de aplicação' } : {}));\n  const ft = String(pr.ficha_tecnica || '').trim();\n  if (ft) { const specs = asSpecs(ft); items.push(specs ? { label: 'Ficha técnica', specs } : { label: 'Ficha técnica', body: ft }); }\n  return items;\n};\nconst buildImages = (pr, gal) => {\n  const g = list(gal).slice().sort((a, b) => (Number(a.ordem) || 0) - (Number(b.ordem) || 0)).filter((x) => x && x.url);\n  const isVid = (x) => String(x.tipo || '').indexOf('video') === 0;\n  const imgs = g.filter((x) => !isVid(x)).map((x, k) => ({ image: x.url, alt: pr.nome + ' — foto ' + (k + 1) }));\n  const vids = g.filter(isVid).map((x) => ({ video: true, href: x.url, label: 'Vídeo' }));\n  const all = imgs.concat(vids);\n  if (all.length) return all;\n  if (pr.imagem) return [{ image: pr.imagem, alt: pr.nome }];\n  return [{ label: 'Sem foto' }];\n};\n\n// ---- SEO / GEO ----\nconst setMeta = (attr, key, content) => {\n  if (typeof document === 'undefined' || !document.head) return;\n  let el = document.head.querySelector(`meta[${attr}=\"${key}\"]`);\n  if (!el) { el = document.createElement('meta'); el.setAttribute(attr, key); document.head.appendChild(el); }\n  el.setAttribute('content', content || '');\n};\nconst setLd = (obj) => {\n  if (typeof document === 'undefined' || !document.head) return;\n  let el = document.getElementById('lf-jsonld-product');\n  if (!obj) { if (el && el.parentNode) el.parentNode.removeChild(el); return; }\n  if (!el) { el = document.createElement('script'); el.id = 'lf-jsonld-product'; el.type = 'application/ld+json'; document.head.appendChild(el); }\n  el.textContent = JSON.stringify(obj);\n};\nconst setCanonical = (href) => {\n  if (typeof document === 'undefined' || !document.head) return;\n  let el = document.head.querySelector('link[rel=\"canonical\"]');\n  if (!el) { el = document.createElement('link'); el.setAttribute('rel', 'canonical'); document.head.appendChild(el); }\n  el.setAttribute('href', href);\n};\nconst applySeo = (slug, out) => {\n  if (typeof document === 'undefined') return;\n  if (!out || !out.ok) { document.title = 'Produto não encontrado | Lucas Fontana'; setLd(null); SEO_SLUG = slug; return; }\n  const pr = out.produto;\n  const imgs = buildImages(pr, out.galeria).map((x) => x.image).filter(Boolean);\n  const url = (typeof window !== 'undefined' && window.location ? window.location.origin : '') + '/produto/' + pr.slug;\n  const desc = String(pr.descricao || '').replace(/\\s+/g, ' ').trim().slice(0, 155);\n  const title = pr.nome + ' | Lucas Fontana';\n  document.title = title;\n  setMeta('name', 'description', desc);\n  setMeta('property', 'og:title', title);\n  setMeta('property', 'og:description', desc);\n  setMeta('property', 'og:type', 'product');\n  setMeta('property', 'og:url', url);\n  if (imgs[0]) setMeta('property', 'og:image', imgs[0]);\n  setCanonical(url);\n  const ld = {\n    '@context': 'https://schema.org', '@type': 'Product', name: pr.nome, sku: pr.sku || undefined, description: desc || undefined,\n    image: imgs.length ? imgs : undefined, category: pr.categoriaNome || undefined, url,\n    brand: { '@type': 'Brand', name: pr.marca || pr.parceiroNome || 'Lucas Fontana' },\n    offers: { '@type': 'Offer', url, priceCurrency: 'BRL', price: Number(pr.preco || 0).toFixed(2), itemCondition: 'https://schema.org/NewCondition', availability: pr.disponivel ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock' }\n  };\n  setLd(ld);\n  SEO_SLUG = slug;\n};\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.pc { width: 100%; background: #ffffff; font-family: ${FF}; -webkit-font-smoothing: antialiased; }\n.sk { width: 100%; background: #f5f5f3; }\n.note { padding: 24px; font-family: ${FF}; font-size: 14px; color: #6b6c70; }\n.rel { width: 100%; background: #f5f5f3; }\n.rel .grid { display: grid; width: 100%; }\n.rel .cell { min-width: 0; }\n`,\n\n  mounted(d2) {\n    ensure(d2, slugOf(d2));\n  },\n\n  updated(d2) {\n    const slug = slugOf(d2);\n    ensure(d2, slug);\n    const c = CACHE[slug];\n    if (c && SEO_SLUG !== slug) applySeo(slug, c.out);\n  },\n\n  render(d2) {\n    const p = d2.params || {};\n    void d2.state.tick;\n    const layout = LAYOUTS.indexOf(p.layout) >= 0 ? p.layout : 'desktop';\n    const R = {\n      pl: refOf(d2.param('productLayout')), tabs: refOf(d2.param('tabs')), card: refOf(d2.param('productCard')),\n      sh: refOf(d2.param('sectionHeader')), empty: refOf(d2.param('emptyState')), bc: refOf(d2.param('breadcrumb')),\n      gal: refOf(d2.param('productGallery')), buy: refOf(d2.param('buyBox')), badge: refOf(d2.param('badge')),\n      benefits: refOf(d2.param('benefitList')), button: refOf(d2.param('button')), icon: refOf(d2.param('iconComponent')),\n      price: refOf(d2.param('priceComponent')), qty: refOf(d2.param('quantityStepper')), pd: refOf(d2.param('productDetails')),\n      cl: refOf(d2.param('checkList')), qc: refOf(d2.param('quoteCard')), search: refOf(d2.param('searchBar'))\n    };\n    const slug = slugOf(d2);\n\n    const emptyView = (variant, eyebrow, title, description) => R.empty\n      ? `<div class=\"pc\">${d2.render(R.empty, {\n          layout, eyebrow, title, description, ctaLabel: 'Ver todos os produtos', ctaHref: '/lista-de-produtos/q',\n          searchBar: R.search, button: R.button, iconComponent: R.icon\n        }, {\n          key: 'empty-' + variant + '-' + layout, style: 'height:auto',\n          onSearch: (v) => go(d2, '/lista-de-produtos/q?q=' + encodeURIComponent(v || '')),\n          onSuggestion: (v) => go(d2, '/lista-de-produtos/q?q=' + encodeURIComponent(v || ''))\n        })}</div>`\n      : '';\n    const notFound = () => emptyView('nf', 'Produto não encontrado', 'Esse produto não está mais na garagem',\n      'O link pode estar errado ou o produto saiu do ar. Que tal dar uma olhada nos outros produtos do Lucas?');\n\n    if (!slug) {\n      return d2.context && d2.context.isBuilder\n        ? `<div class=\"note\">ProdutoConteudo — na página publicada o slug vem da URL (/produto/:slug). Para pré-visualizar aqui, preencha o parâmetro slugFixo.</div>`\n        : notFound();\n    }\n    if (ERR[slug]) return emptyView('err', 'Algo deu errado', 'Não foi possível carregar o produto', 'Confira sua conexão e atualize a página em instantes.');\n    const entry = CACHE[slug];\n    if (!entry) return `<div class=\"sk\" role=\"status\" aria-busy=\"true\" aria-label=\"Carregando produto\" style=\"min-height:${SK_H[layout]}px\"></div>`;\n    if (!entry.out.ok) return notFound();\n\n    const out = entry.out;\n    const pr = out.produto;\n\n    const crumbs = [{ label: 'Início', href: '/' }];\n    if (pr.categoriaNome) crumbs.push(pr.categoriaSlug ? { label: pr.categoriaNome, href: LISTA + '?categoria=' + pr.categoriaSlug } : { label: pr.categoriaNome });\n    if (pr.subcategoria) crumbs.push(pr.categoriaSlug ? { label: pr.subcategoria, href: LISTA + '?categoria=' + pr.categoriaSlug + '&subcategoria=' + slugify(pr.subcategoria) } : { label: pr.subcategoria });\n    crumbs.push({ label: pr.nome });\n\n    const nParc = Number(pr.parcelas) || 0;\n    const benefits = [\n      pr.parceiroNome\n        ? { icon: 'truck', title: 'Enviado pela ' + pr.parceiroNome, text: 'O parceiro envia direto para você e informa o código de rastreio.' }\n        : { icon: 'truck', title: 'Enviamos para todo o Brasil', text: 'O frete é calculado no fechamento do pedido.' },\n      { icon: 'card', title: nParc > 1 ? 'Pix ou cartão em até ' + nParc + 'x' : 'Pix ou cartão', text: 'Pagamento seguro, com antifraude em todas as compras.' },\n      { icon: 'swap', title: 'Troca e devolução', link: { label: 'Ver política de trocas', href: '/politicas/trocas-e-devolucoes' } }\n    ];\n    const product = {\n      name: pr.nome, category: pr.categoriaNome || '', sku: pr.sku || '', price: pr.preco, oldPrice: pr.precoAntigo,\n      installments: pr.parcelas, pixDiscount: pr.desconto_pix, available: !!pr.disponivel, partner: pr.parceiroNome || '', benefits\n    };\n\n    const top = R.pl ? d2.render(R.pl, {\n      layout, product, images: buildImages(pr, out.galeria), crumbs,\n      breadcrumb: R.bc, productGallery: R.gal, buyBox: R.buy, badge: R.badge, priceComponent: R.price,\n      quantityStepper: R.qty, button: R.button, benefitList: R.benefits, iconComponent: R.icon\n    }, {\n      key: 'pl-' + pr._id + '-' + layout, style: 'height:auto',\n      onBuyNow: () => go(d2, '/sacola'),\n      onNavigate: (h) => { if (h) go(d2, h); }\n    }) : '';\n\n    const tabItems = buildTabs(pr);\n    const tabs = R.tabs && tabItems.length ? d2.render(R.tabs, {\n      layout, items: tabItems, productDetails: R.pd, checkList: R.cl, quoteCard: R.qc, iconComponent: R.icon\n    }, { key: 'tabs-' + pr._id + '-' + layout, style: 'height:auto' }) : '';\n\n    const L = REL[layout];\n    const rels = list(out.relacionados).slice(0, MAX_REL);\n    const card = (x) => d2.render(R.card, {\n      layout, priceComponent: R.price, button: R.button, badge: R.badge, iconComponent: R.icon,\n      brand: x.categoriaNome || '', name: x.nome, price: x.preco, oldPrice: x.precoAntigo, installments: x.parcelas,\n      pixDiscount: x.desconto_pix, outOfStock: !x.disponivel, sku: x.sku, href: '/produto/' + x.slug,\n      image: x.imagem || '', partner: x.parceiroNome || ''\n    }, {\n      key: 'rc-' + x._id + '-' + layout, style: 'width:100%;height:' + L.cellH + 'px',\n      onAdd: (sku) => addToBag(sku || x.sku, 1)\n    });\n    const related = R.card && R.sh && rels.length\n      ? `<section class=\"rel\" aria-label=\"Combina com\" style=\"padding:${L.pad}\">\n          <div style=\"height:${L.hh}px;margin-bottom:${L.gap}px\">${d2.render(R.sh, { eyebrow: 'Combina com', title: 'Leva junto que combina', number: '+', layout }, { key: 'sh-' + layout, height: L.hh })}</div>\n          <div class=\"grid\" style=\"grid-template-columns:repeat(${L.cols},minmax(0,1fr));column-gap:${L.colGap}px;row-gap:${L.rowGap}px\">\n            ${rels.map((x) => `<div class=\"cell\" data-key=\"${esc(x._id)}\" style=\"height:${L.cellH}px\">${card(x)}</div>`).join('')}\n          </div>\n        </section>`\n      : '';\n\n    return `<div class=\"pc\">${top}${tabs}${related}</div>`;\n  }\n};\n"}},"appRouter":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"appRouter"}}}},"badge":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"badge"}}}},"benefitList":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"benefitList"}}}},"breadcrumb":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"breadcrumb"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"buyBox":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"buyBox"}}}},"checkList":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"checkList"}}}},"emptyState":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"emptyState"}}}},"iconComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"iconComponent"}}}},"layout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"layout"}}}},"priceComponent":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"priceComponent"}}}},"productCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"productCard"}}}},"productDetails":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"productDetails"}}}},"productGallery":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"productGallery"}}}},"productLayout":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"productLayout"}}}},"produtoService":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"produtoService"}}}},"quantityStepper":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"quantityStepper"}}}},"quoteCard":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"quoteCard"}}}},"searchBar":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"searchBar"}}}},"sectionHeader":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"sectionHeader"}}}},"slugFixo":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"slugFixo"}}}},"tabs":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"tabs"}}}}}}}}}},{"_id":"6ac58b647a27742c85817866","component":"data2-core-types@Component","system":"6ab58b1260cbe7aa719c6d7b","params":{"extends":"data2-core-primitives@Block","component":"GestaoMenu","package":"babi-lf","definition":{"preventEvaluation":true,"component":"data2-core-types@Definition","params":{"def":{"component":"data2-code-components@CodeHost","params":{"code":{"component":"data2-core-primitives@String","params":{"content":"// GestaoMenu — Gestão (backoffice, só desktop)\n// A barra do topo de TODAS as telas da Gestão: logo, selo \"Gestão\", links das áreas e o botão \"Sair\".\n// Para incluir uma área nova no menu, basta acrescentar um item em ITEMS (as telas não têm mais menu próprio).\n// O item ativo vem do parâmetro `active` (\"categorias\", \"destaques\" ou \"produtos\"); sem ele, vale o endereço da página.\n// Reaproveita Logo e Button da loja; o logout usa a estratégia de login recebida em `auth`.\nconst ITEMS = [\n  { key: 'categorias', label: 'Categorias', href: '/categorias' },\n  { key: 'destaques', label: 'Destaques', href: '/destaques' },\n  { key: 'produtos', label: 'Produtos', href: '/produtos' }\n];\nconst esc = (s) => String(s == null ? '' : s)\n  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\nconst refOf = (v) => { const r = (v && typeof v === 'object' ? (typeof v.getReference === 'function' ? v.getReference() : v.reference) : v) || ''; return r && r.indexOf('@') < 0 ? 'babi-lf@' + r : r; };\nconst activeOf = (d2) => {\n  const a = String(d2.param('active', '') || '');\n  if (ITEMS.some((it) => it.key === a)) return a;\n  let path = '';\n  try { path = (typeof window !== 'undefined' && window.location && window.location.pathname) || ''; } catch (e) { path = ''; }\n  const hit = ITEMS.find((it) => path === it.href || path.indexOf(it.href + '/') === 0);\n  if (hit) return hit.key;\n  return path === '' || path === '/' ? 'categorias' : '';\n};\n\nexport default {\n  css: `\n:host { display: block; width: 100%; }\n* { box-sizing: border-box; }\n.bar { --red: #c8102e; --ink: #0b0b0c; --white: #fff; --g100: #ececea;\n  width: 100%; height: 72px; background: var(--white); border-bottom: 1px solid var(--g100); display: flex; align-items: center; padding: 0 48px; gap: 20px; color: var(--ink);\n  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; -webkit-font-smoothing: antialiased; }\n.tag { font-size: 11px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; background: var(--ink); color: var(--white); padding: 6px 10px; border-radius: 2px; }\n.links { display: flex; align-items: center; }\n.nav { margin-left: 24px; font-size: 13px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--ink); border-bottom: 2px solid var(--red); padding: 6px 0; text-decoration: none; }\n.nav:not(.on) { border-bottom-color: transparent; }\n.nav:hover { border-bottom-color: var(--red); }\n.nav:focus-visible { outline: 2px solid var(--red); outline-offset: 4px; }\n.sp { flex: 1; }\n.out { display: inline-block; }\n`,\n\n  mounted(d2) {\n    d2.on('[data-act=\"sair\"]', 'click', async () => {\n      try { await d2.auth('auth').logout(); } catch (e) { /* segue para recarregar */ }\n      if (typeof window !== 'undefined') window.location.assign('/');\n    });\n  },\n\n  render(d2) {\n    const logoRef = refOf(d2.param('logo'));\n    const btnRef = refOf(d2.param('button'));\n    const active = activeOf(d2);\n    const logo = logoRef ? d2.render(logoRef, { layout: 'desktop', noLink: true }, { key: 'logo', width: 380, height: 40 }) : '';\n    const links = ITEMS.map((it) => `<a class=\"nav${it.key === active ? ' on' : ''}\" href=\"${esc(it.href)}\" data-key=\"${esc(it.key)}\"${it.key === active ? ' aria-current=\"page\"' : ''}>${esc(it.label)}</a>`).join('');\n    const sair = btnRef ? `<span class=\"out\" data-act=\"sair\">${d2.render(btnRef, { label: 'Sair', variant: 'outline', size: 'sm' }, { key: 'sair', width: 110, height: 44 })}</span>` : '';\n    return `<div class=\"bar\">${logo}<span class=\"tag\">Gestão</span><nav class=\"links\" aria-label=\"Gestão\">${links}</nav><span class=\"sp\"></span>${sair}</div>`;\n  }\n};\n"}},"active":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"active"}}}},"auth":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"auth"}}}},"button":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"button"}}}},"logo":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"logo"}}}}}}}}}},{"_id":"5ed9bed7b9e0891ce913e884","component":"data2-core-types@Component","params":{"package":"data2-core","component":"DataSource","renderable":{"dimensions":{"disabled":false,"component":"data2-core-types@Dimensions","params":{"width":1366,"exactWidth":false,"exactHeight":false,"height":768}}}}},{"_id":"5f472ae463c680de4ff296e9","component":"data2-core-types@Component","params":{"package":"data2-core","component":"Data2TableDataSource","extends":"data2-core@DataSource","renderable":{"dimensions":{"disabled":false,"component":"data2-core-types@Dimensions","params":{"width":1366,"exactWidth":false,"exactHeight":false,"height":768}}}}}]}},{"reference":"ExternalComponentInstancesTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[]}},{"_id":"5f060d9b1ca96def42f3c40a","displayName":"Builder AuthStrategy","component":"data2-core@AuthenticationStrategy","system":"5e3b796d6228227ca637d0f4","params":{"credentials":[{"component":"data2-core-types@DataSetColumnReference","params":{"column":"email"}},{"component":"data2-core-types@DataSetColumnReference","params":{"column":"password"}},{"component":"data2-core-types@DataSetColumnReference","params":{"column":"status"}}],"verifier":{"component":"data2-core-types@DataSetReference","params":{"reference":"UsersDataSet"}},"sessionShared":{"component":"data2-core-primitives@Boolean","params":{"content":false}},"password":{"disabled":false,"component":"data2-core-types@DataSetColumnReference","params":{"column":"password"}},"email":{"disabled":false,"component":"data2-core-types@DataSetColumnReference","params":{"column":"email"}},"resetPassword":{"resetEmail":{"artboard":{"params":{"preventEvaluation":true,"reference":"nR6Q9d7qdaPtZhJ28Q8Dy"},"component":"data2-core-types@ArtboardReference"}},"resetSuccessEmail":{"artboard":{"params":{"preventEvaluation":true,"reference":"yPCJBTKo8q1Mw0B_3Kpwl"},"component":"data2-core-types@ArtboardReference"}}},"session":[{"component":"data2-core-types@DataSetColumnReference","params":{"column":"name"}},{"component":"data2-core-types@DataSetColumnReference","params":{"column":"email"}},{"component":"data2-core-types@DataSetColumnReference","params":{"column":"password"}},{"component":"data2-core-types@DataSetColumnReference","params":{"column":"status"}}],"sessionMetadata":{"params":{"actions":[{"params":{"compare":{"params":{"subject":{"params":{"components":[{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$user._id"}}}},{"params":{"comparisonSubject":{"component":"data2-core-primitives@String","params":{"content":"active"}},"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$user.status"}}}}},"component":"data2-core-comparison-operators@Equal","displayName":"is active user"}]},"component":"data2-core-logical-operators@And","displayName":"is active and has _id"}},"component":"data2-core-logical-operators@Not"},"then":{"params":{"message":{"component":"data2-core-primitives@String","params":{"content":"Invalid Credentials"}},"code":{"component":"data2-core-primitives@String","params":{"content":"401"}}},"component":"data2-core-types@Error"}},"component":"data2-core-flow@If","displayName":"check $user"},{"params":{"action":{"params":{"pattern":{"component":"data2-core-primitives@String","params":{"content":"@data2.app"}},"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$user.email"}}}}},"component":"data2-core-functions@Includes","displayName":"isData2User"},"resultName":{"component":"data2-core-primitives@String","params":{"content":"is_data2_user"}}},"component":"data2-core-flow@Step"},{"params":{"action":{"params":{"pattern":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$metadata.d2_app"}}}},"subject":[{"component":"data2-core-primitives@String","params":{"content":"management"}}]},"component":"data2-core-functions@Includes","displayName":"isData2App Exception"},"resultName":{"component":"data2-core-primitives@String","params":{"content":"is_data2_app_exception"}}},"component":"data2-core-flow@Step"},{"params":{"resultName":{"component":"data2-core-primitives@String","params":{"content":"has_access"}},"action":{"params":{"compare":{"params":{"components":[{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"is_data2_user"}}}},{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"is_data2_app_exception"}}}}]},"component":"data2-core-logical-operators@Or"},"else":{"params":{"actions":[{"params":{"actions":[{"params":{"compare":{"params":{"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$metadata.system"}}}}},"component":"data2-core-logical-operators@Not"},"then":{"params":{"message":{"component":"data2-core-primitives@String","params":{"content":"Invalid Credentials"}},"code":{"component":"data2-core-primitives@String","params":{"content":"401"}}},"component":"data2-core-types@Error"}},"component":"data2-core-flow@If","displayName":"check $metadata.system"},{"params":{"module":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"WuUa-VKHhW9uYU0E3-mJ8"}},"prop":"filter","args":[{"_id":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$metadata.system"}}}}}]},"component":"data2-core-types@Interaction"},{"params":{"compare":{"params":{"subject":{"component":"data2-core-types@Getter","params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"WuUa-VKHhW9uYU0E3-mJ8"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"data.records.length"}}}}},"component":"data2-core-logical-operators@Not","displayName":"systems not found"},"then":{"params":{"message":{"component":"data2-core-primitives@String","params":{"content":"Invalid Credentials"}},"code":{"component":"data2-core-primitives@String","params":{"content":"401"}}},"component":"data2-core-types@Error"}},"component":"data2-core-flow@If","displayName":"check system found"},{"params":{"actions":[{"params":{"module":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Ok6Tsu5XkS7r8PyW_7TyW"}},"prop":"filter","args":[{"user":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$user._id"}}}},"organization":{"component":"data2-core-types@Getter","params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"WuUa-VKHhW9uYU0E3-mJ8"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"cursor.current.organization._id"}}}}}]},"component":"data2-core-types@Interaction"},{"params":{"module":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"NqKAY34n2ffFL64zamp7t"}},"prop":"filter","args":[{"user":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$user._id"}}}},"system":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$metadata.system"}}}}}]},"component":"data2-core-types@Interaction"}]},"component":"data2-core-flow@Parallel"}]},"component":"data2-core-flow@Series","displayName":"common setup"},{"params":{"then":{"params":{"content":true},"component":"data2-core-primitives@Boolean"},"else":{"params":{"content":false},"component":"data2-core-primitives@Boolean"},"compare":{"params":{"components":{"params":{"array":{"params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"WuUa-VKHhW9uYU0E3-mJ8"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"data.records"}}},"component":"data2-core-types@Getter"},"mapper":{"disabled":false,"component":"data2-core-functions@Function","params":{"parameters":[{"component":"data2-core-primitives@String","params":{"content":"system"}}],"body":{"params":{"expression":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"system.visibility"}}}},"defaultCase":{"params":{"content":false},"component":"data2-core-primitives@Boolean"},"cases":[{"component":"data2-core-flow@Case","params":{"expression":{"component":"data2-core-primitives@String","params":{"content":"public"}},"value":{"params":{"components":[{"params":{"array":{"params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Ok6Tsu5XkS7r8PyW_7TyW"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"data.records"}}},"component":"data2-core-types@Getter"},"filter":{"disabled":false,"component":"data2-core-functions@Function","params":{"parameters":[{"component":"data2-core-primitives@String","params":{"content":"member"}}],"body":{"params":{"components":[{"params":{"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"member.organization._id"}}}},"comparisonSubject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"system.organization._id"}}}}},"component":"data2-core-comparison-operators@Equal","displayName":"is org member"},{"params":{"pattern":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"member.role"}}}},"subject":[{"component":"data2-core-primitives@String","params":{"content":"owner"}},{"component":"data2-core-primitives@String","params":{"content":"billing-owner"}},{"component":"data2-core-primitives@String","params":{"content":"admin"}},{"component":"data2-core-primitives@String","params":{"content":"member"}}]},"component":"data2-core-functions@Includes","displayName":"has role with access"}]},"component":"data2-core-logical-operators@And","displayName":"has org member role with access"}}}},"component":"data2-core-functions@ArrayFind","displayName":"is org member"},{"params":{"components":[{"params":{"array":{"params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Ok6Tsu5XkS7r8PyW_7TyW"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"data.records"}}},"component":"data2-core-types@Getter"},"filter":{"disabled":false,"component":"data2-core-functions@Function","params":{"parameters":[{"component":"data2-core-primitives@String","params":{"content":"member"}}],"body":{"params":{"components":[{"params":{"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"member.organization._id"}}}},"comparisonSubject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"system.organization._id"}}}}},"component":"data2-core-comparison-operators@Equal","displayName":"is org member"},{"params":{"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"member.role"}}}},"comparisonSubject":{"component":"data2-core-primitives@String","params":{"content":"collaborator"}}},"component":"data2-core-comparison-operators@Equal","displayName":"is collaborator"}]},"component":"data2-core-logical-operators@And","displayName":"is org member and collaborator"}}}},"component":"data2-core-functions@ArrayFind","displayName":"is collaborator"},{"params":{"array":{"params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"NqKAY34n2ffFL64zamp7t"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"data.records"}}},"component":"data2-core-types@Getter"},"filter":{"disabled":false,"component":"data2-core-functions@Function","params":{"parameters":[{"component":"data2-core-primitives@String","params":{"content":"access"}}],"body":{"params":{"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"access.system._id"}}}},"comparisonSubject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"system._id"}}}}},"component":"data2-core-comparison-operators@Equal"}}}},"component":"data2-core-functions@ArrayFind","displayName":"has system access"}]},"component":"data2-core-logical-operators@And","displayName":"is collaborator and has system access"}]},"component":"data2-core-logical-operators@Or"}}},{"component":"data2-core-flow@Case","params":{"expression":{"component":"data2-core-primitives@String","params":{"content":"private"}},"value":{"params":{"components":[{"params":{"array":{"params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Ok6Tsu5XkS7r8PyW_7TyW"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"data.records"}}},"component":"data2-core-types@Getter"},"filter":{"disabled":false,"component":"data2-core-functions@Function","params":{"parameters":[{"component":"data2-core-primitives@String","params":{"content":"member"}}],"body":{"params":{"components":[{"params":{"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"member.organization._id"}}}},"comparisonSubject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"system.organization._id"}}}}},"component":"data2-core-comparison-operators@Equal","displayName":"is org member"},{"params":{"pattern":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"member.role"}}}},"subject":[{"component":"data2-core-primitives@String","params":{"content":"owner"}},{"component":"data2-core-primitives@String","params":{"content":"admin"}}]},"component":"data2-core-functions@Includes","displayName":"is owner/admin"}]},"component":"data2-core-logical-operators@And","displayName":"has org member role with access"}}}},"component":"data2-core-functions@ArrayFind","displayName":"is owner/admin"},{"params":{"components":[{"params":{"array":{"params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Ok6Tsu5XkS7r8PyW_7TyW"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"data.records"}}},"component":"data2-core-types@Getter"},"filter":{"disabled":false,"component":"data2-core-functions@Function","params":{"parameters":[{"component":"data2-core-primitives@String","params":{"content":"member"}}],"body":{"params":{"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"member.organization._id"}}}},"comparisonSubject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"system.organization._id"}}}}},"component":"data2-core-comparison-operators@Equal"}}}},"component":"data2-core-functions@ArrayFind","displayName":"is org member"},{"params":{"array":{"params":{"module":{"disabled":false,"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"NqKAY34n2ffFL64zamp7t"}},"prop":{"component":"data2-core-primitives@String","params":{"content":"data.records"}}},"component":"data2-core-types@Getter"},"filter":{"disabled":false,"component":"data2-core-functions@Function","params":{"parameters":[{"component":"data2-core-primitives@String","params":{"content":"access"}}],"body":{"params":{"subject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"access.system._id"}}}},"comparisonSubject":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"system._id"}}}}},"component":"data2-core-comparison-operators@Equal"}}}},"component":"data2-core-functions@ArrayFind","displayName":"has system access"}]},"component":"data2-core-logical-operators@And","displayName":"is member and has system access"}]},"component":"data2-core-logical-operators@Or","displayName":"is owner/admin or has system access"}}}]},"component":"data2-core-flow@Switch"}}}},"component":"data2-core-functions@ArrayMap"}},"component":"data2-core-logical-operators@And","displayName":"has org member for all systems in request"}},"component":"data2-core-flow@If"}]},"component":"data2-core-flow@Series"},"then":{"params":{"content":true},"component":"data2-core-primitives@Boolean"}},"component":"data2-core-flow@If"}},"component":"data2-core-flow@Step"},{"params":{"then":{"system":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"$metadata.system"}}}}},"else":{"params":{"message":{"component":"data2-core-primitives@String","params":{"content":"Invalid Credentials"}},"code":{"component":"data2-core-primitives@String","params":{"content":"401"}}},"component":"data2-core-types@Error"},"compare":{"component":"data2-core-types@Reference","params":{"reference":{"component":"data2-core-primitives@String","params":{"content":"has_access"}}}}},"component":"data2-core-flow@If"}]},"component":"data2-core-flow@Series"},"sessionExpiresIn":{"component":"data2-core-primitives@Number","params":{"content":604800}},"sessionRenewal":{"component":"data2-core-primitives@Boolean","params":{"content":true}},"identityProviders":[{"provider":{"component":"data2-core-primitives@String","params":{"content":"GOOGLE"}},"clientId":{"component":"data2-core-primitives@String","params":{"content":"55470861603-22pvfc1t49lp8cjnbfk71s5ct9hp1q1v.apps.googleusercontent.com"}}}]},"reference":"Data2BuilderAuthentication","updatedAt":"2026-08-06T19:31:23.557Z"},{"_id":"5f060ee51ca96def42f3fbd1","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"UsersTableDataSource"}},"pagination":{"size":{"component":"data2-core-primitives@Number","params":{"content":1}}}},"reference":"UsersDataSet","updatedAt":"2026-03-04T21:16:40.291Z"},{"_id":"68f938cf5fb002e33752a43d","displayName":"InternalApplicationsAuthenticationStrategy","component":"data2-core@AuthenticationStrategy","system":"5e3b796d6228227ca637d0f4","params":{"resetPassword":{"resetEmail":{"artboard":{"params":{"preventEvaluation":true},"component":"data2-core-types@ArtboardReference"}},"resetSuccessEmail":{"artboard":{"params":{"preventEvaluation":true},"component":"data2-core-types@ArtboardReference"}}},"verifier":{"disabled":false,"component":"data2-core-types@DataSetReference","params":{"reference":"InternalApplicationsVerifierDataSet"}},"password":{"disabled":false,"component":"data2-core-types@DataSetColumnReference","params":{"column":"secret"}},"credentials":[{"component":"data2-core-types@FieldReference","params":{"key":"application"}},{"component":"data2-core-types@FieldReference","params":{"key":"secret"}},{"component":"data2-core-types@FieldReference","params":{"key":"status"}}],"session":[{"component":"data2-core-types@FieldReference","params":{"key":"application"}},{"component":"data2-core-types@FieldReference","params":{"key":"secret"}},{"component":"data2-core-types@FieldReference","params":{"key":"status"}}]},"reference":"InternalApplicationsAuthenticationStrategy","updatedAt":"2025-10-22T20:08:54.442Z","createdAt":"2025-10-22T20:04:31.198Z"},{"component":"data2-core@DataSet","reference":"SessionsDataSet","params":{"requiresConfirmation":false,"pk":"key","datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"data2sessionsdatasource"}}}},{"reference":"UsersTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[]}},{"component":"data2-core@ServerSessionsDataSource","reference":"data2sessionsdatasource","params":{}},{"_id":"5f1600b70528b92601890f75","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"ServiceComponentInstancesTableDataSource"}},"pk":"_id","autoEdit":true,"master":{"params":{"dataset":{"component":"data2-core-types@DataSetReference","params":{"reference":"SystemsDataSet"}},"localField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"system"}},"masterField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"_id"}}},"component":"data2-core-types@DataSetMaster"},"autoSelect":{"component":"data2-core-primitives@Boolean","params":{"content":false}},"policies":{"params":{"allowGet":{"component":"data2-core-primitives@Boolean","params":{"content":true}}},"component":"data2@hkXy-UhMjhyfptdE6_fpW"}},"reference":"ServiceComponentInstancesDataSet","updatedAt":"2025-11-06T21:07:20.208Z","createdAt":"2020-07-20T20:38:15.436Z"},{"_id":"5f1602190528b92601890f7d","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"pagination":{"size":40000},"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"ComponentInstancesTableDataSource"}},"sort":{"_id":1},"pk":"_id","autoEdit":true,"master":{"dataset":{"component":"data2-core-types@DataSetReference","params":{"reference":"SystemsDataSet"}},"localField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"system"}},"masterField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"_id"}}},"autoSelect":{"component":"data2-core-primitives@Boolean","params":{"content":false}},"policies":{"params":{"allowGet":{"component":"data2-core-primitives@Boolean","params":{"content":true}}},"component":"data2@hkXy-UhMjhyfptdE6_fpW"}},"reference":"ComponentInstancesDataSet","updatedAt":"2025-11-06T21:07:07.089Z","createdAt":"2020-07-20T20:44:09.350Z"},{"_id":"5f16017f0528b92601890f7a","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"FileComponentInstancesTableDataSource"}},"pk":"_id","autoEdit":true,"filter":{"domain":{"component":"data2-core-types@Reference","params":{"reference":"clientApplicationDomain"}}},"master":{"params":{"dataset":{"component":"data2-core-types@DataSetReference","params":{"reference":"SystemsDataSet"}},"localField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"system"}},"masterField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"_id"}}},"component":"data2-core-types@DataSetMaster"},"autoSelect":{"component":"data2-core-primitives@Boolean","params":{"content":false}}},"reference":"FileComponentInstancesDataSet","updatedAt":"2023-08-03T16:08:18.193Z","createdAt":"2020-07-20T20:41:35.797Z"},{"_id":"5f1601990528b92601890f7b","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"ApplicationsTableDataSource"}},"pk":"_id","autoEdit":{"component":"data2-core-primitives@Boolean","params":{"content":true}},"master":{"dataset":{"component":"data2-core-types@DataSetReference","params":{"reference":"SystemsDataSet"}},"localField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"system"}},"masterField":{"params":{"column":"_id"},"component":"data2-core-types@DataSetColumnReference"}},"autoSelect":{"component":"data2-core-primitives@Boolean","params":{"content":false}}},"reference":"ApplicationsDataSet","updatedAt":"2022-12-13T21:51:13.995Z","createdAt":"2020-07-20T20:42:01.657Z"},{"_id":"5f16172a0528b92601890f85","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"pagination":{"size":{"component":"data2-core-primitives@Number","params":{"content":10000}}},"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"DataComponentInstancesTableDataSource"}},"pk":"_id","autoEdit":true,"master":{"params":{"dataset":{"component":"data2-core-types@DataSetReference","params":{"reference":"SystemsDataSet"}},"localField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"system"}},"masterField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"_id"}}},"component":"data2-core-types@DataSetMaster"},"autoSelect":{"component":"data2-core-primitives@Boolean","params":{"content":false}},"policies":{"params":{"allowGet":{"component":"data2-core-primitives@Boolean","params":{"content":true}}},"component":"data2@hkXy-UhMjhyfptdE6_fpW"}},"reference":"DataComponentInstancesDataSet","updatedAt":"2025-11-06T21:07:12.831Z","createdAt":"2020-07-20T22:14:02.097Z"},{"_id":"60ddc1bbda3861ca65407c5a","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"FileComponentInstancesTableDataSource"}},"pk":"_id","autoEdit":true,"filter":{"domain":{"component":"data2-core-types@Reference","params":{"reference":"clientApplicationDomain"}}},"pagination":{"size":1},"master":{"params":{"dataset":{"component":"data2-core-types@DataSetReference","params":{"reference":"SystemsDataSet"}},"localField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"system"}},"masterField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"_id"}}},"component":"data2-core-types@DataSetMaster"}},"reference":"OneFileComponentInstancesDataSet","updatedAt":"2022-02-09T19:44:38.036Z","createdAt":"2020-07-20T20:41:35.797Z"},{"_id":"63ee3d38b8c9838c62fb05fb","displayName":"DriveFileComponentInstancesDataSet","component":"data2-core@DataSet","system":"5e3b796d6228227ca637d0f4","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"FileComponentInstancesTableDataSource"}},"pk":"_id","autoEdit":true,"filter":{"component":{"component":"data2-core-primitives@String","params":{"content":"data2-core@Drive"}}},"master":{"params":{"dataset":{"component":"data2-core-types@DataSetReference","params":{"reference":"SystemsDataSet"}},"localField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"system"}},"masterField":{"component":"data2-core-types@DataSetColumnReference","params":{"column":"_id"}}},"component":"data2-core-types@DataSetMaster"},"autoSelect":{"component":"data2-core-primitives@Boolean","params":{"content":false}}},"reference":"DriveFileComponentInstancesDataSet","updatedAt":"2025-12-04T21:58:32.367Z","createdAt":"2023-02-16T14:27:07.797Z"},{"reference":"ServiceComponentInstancesTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[{"_id":"6ac4271778f3730f24cb815d","component":"data2-rush@HTTPListener","reference":"categoriasLoja","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac569932f4d9a7641b9df8d","component":"data2-rush@HTTPListener","reference":"cadastrarCliente","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac52d612f4d9a7641b93a1f","component":"data2-rush@HTTPListener","reference":"produtosLoja","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac42cd843b15d0ea6b7bdd7","component":"data2-rush@HTTPListener","reference":"gestaoCategoriasListar","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac428727a27742c857ecb94","component":"data2-rush@HTTPListener","reference":"gestaoCategoriaSalvar","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac427231c34e8ef0a953ff1","component":"data2-rush@HTTPListener","reference":"gestaoCategoriaDesativar","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac4272a005d4042c2e3254d","component":"data2-rush@HTTPListener","reference":"gestaoCategoriaExcluir","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac43a7e76d49ffb413a091f","component":"data2-rush@HTTPListener","reference":"gestaoCategoriaImagem","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac526507a27742c85806af5","component":"data2-rush@HTTPListener","reference":"gestaoProdutosListar","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac4361a7a27742c857eeb94","component":"data2-rush@HTTPListener","reference":"gestaoDestaquesSalvar","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac562ff06e81c2076f3ba1b","component":"data2-rush@HTTPListener","reference":"gestaoDestaquesProdutosSalvar","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac5268b27b4b62e8522a57c","component":"data2-rush@HTTPListener","reference":"gestaoProdutoObter","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac526a02f4d9a7641b92667","component":"data2-rush@HTTPListener","reference":"gestaoProdutoSalvar","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac527097a27742c85806d38","component":"data2-rush@HTTPListener","reference":"gestaoProdutoAtivar","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac527117cfd4d3426c21cb1","component":"data2-rush@HTTPListener","reference":"gestaoProdutoExcluir","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac527066bb5213aca6176e1","component":"data2-rush@HTTPListener","reference":"gestaoGaleriaRemover","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac52d2380918a4cab959650","component":"data2-rush@HTTPListener","reference":"gestaoParceiroSalvar","system":"6ab58b1260cbe7aa719c6d7b","params":{}},{"_id":"6ac526ec5ae4f7827ef7fc6a","component":"data2-rush@HTTPListener","reference":"gestaoGaleriaEnviar","system":"6ab58b1260cbe7aa719c6d7b","params":{}}]}},{"reference":"ComponentInstancesTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[{"_id":"6ac42bf578f3730f24cb8d8c","component":"data2-core-primitives@Router","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Rotas","params":{"routerType":{"component":"data2-core-primitives@String","params":{"content":"browser"}},"routes":[{"component":"data2-core-primitives@Route","params":{"path":"","name":"Gestão — Categorias","content":{"component":"data2-core-types@ArtboardReference","params":{"reference":"VuxTMhbjKlklOB_jH6TcJ"}},"policies":[{"component":"data2-core-auth@Policy","params":{"authenticationStrategy":{"component":"data2-core-types@InteractiveModuleReference","disabled":false,"params":{"reference":"gestaoAuth"}}}}]}},{"component":"data2-core-primitives@Route","params":{"path":"/categorias","name":"Gestão — Categorias","content":{"component":"data2-core-types@ArtboardReference","params":{"reference":"VuxTMhbjKlklOB_jH6TcJ"}},"policies":[{"component":"data2-core-auth@Policy","params":{"authenticationStrategy":{"component":"data2-core-types@InteractiveModuleReference","disabled":false,"params":{"reference":"gestaoAuth"}}}}]}},{"component":"data2-core-primitives@Route","params":{"path":"/categorias/nova","name":"Gestão — Nova categoria","content":{"component":"data2-core-types@ArtboardReference","params":{"reference":"F3CW1j1-4xce0JVIw93kD"}},"policies":[{"component":"data2-core-auth@Policy","params":{"authenticationStrategy":{"component":"data2-core-types@InteractiveModuleReference","disabled":false,"params":{"reference":"gestaoAuth"}}}}]}},{"component":"data2-core-primitives@Route","params":{"path":"/destaques","name":"Gestão — Destaques","content":{"component":"data2-core-types@ArtboardReference","params":{"reference":"Rj_uWXXY6dBQ-W046-ZLv"}},"policies":[{"component":"data2-core-auth@Policy","params":{"authenticationStrategy":{"component":"data2-core-types@InteractiveModuleReference","disabled":false,"params":{"reference":"gestaoAuth"}}}}]}},{"component":"data2-core-primitives@Route","params":{"path":"/produtos","name":"Gestão — Produtos","content":{"component":"data2-core-types@ArtboardReference","params":{"reference":"PEpck1QuiZfIzvaUChMky"}},"policies":[{"component":"data2-core-auth@Policy","params":{"authenticationStrategy":{"component":"data2-core-types@InteractiveModuleReference","disabled":false,"params":{"reference":"gestaoAuth"}}}}]}},{"component":"data2-core-primitives@Route","params":{"path":"/produtos/novo","name":"Gestão — Novo produto","content":{"component":"data2-core-types@ArtboardReference","params":{"reference":"6uGZil8JrrobShrouXzP0"}},"policies":[{"component":"data2-core-auth@Policy","params":{"authenticationStrategy":{"component":"data2-core-types@InteractiveModuleReference","disabled":false,"params":{"reference":"gestaoAuth"}}}}]}}],"login":{"component":"data2-core-types@ArtboardReference","params":{"reference":"Zp3EWkUF0JlxUZbOOcV68"}}},"reference":"gestaoRouter"},{"_id":"6ac42eb32f4d9a7641b7958c","component":"data2-core-primitives@Artboard","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Login","params":{"title":{"component":"data2-core-primitives@String","params":{"content":"Gestão — Login"}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":900}},"position":{"component":"data2-core-types@Position","params":{"x":0,"y":0}}},"reference":"Zp3EWkUF0JlxUZbOOcV68"},{"_id":"6ac528697a27742c85807161","component":"data2-core-primitives@Artboard","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Produto (Formulário)","params":{"title":{"component":"data2-core-primitives@String","params":{"content":"Gestão — Produto (Formulário)"}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":2400}},"position":{"component":"data2-core-types@Position","params":{"x":0,"y":0}}},"reference":"6uGZil8JrrobShrouXzP0"},{"_id":"6ac528665ae4f7827ef80062","component":"data2-core-primitives@Artboard","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Produtos (Lista)","params":{"title":{"component":"data2-core-primitives@String","params":{"content":"Gestão — Produtos (Lista)"}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":1000}},"position":{"component":"data2-core-types@Position","params":{"x":0,"y":0}}},"reference":"PEpck1QuiZfIzvaUChMky"},{"_id":"6ac4368527b4b62e852125e1","component":"data2-core-primitives@Artboard","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Destaques","params":{"title":{"component":"data2-core-primitives@String","params":{"content":"Gestão — Destaques"}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":1000}},"position":{"component":"data2-core-types@Position","params":{"x":0,"y":0}}},"reference":"Rj_uWXXY6dBQ-W046-ZLv"},{"_id":"6ac427cf3ea7d08d375ac111","component":"data2-core-primitives@Artboard","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Categorias · Formulário","params":{"title":{"component":"data2-core-primitives@String","params":{"content":"Gestão — Categorias · Formulário"}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":1000}},"position":{"component":"data2-core-types@Position","params":{"x":0,"y":0}}},"reference":"F3CW1j1-4xce0JVIw93kD"},{"_id":"6ac427cc2f4d9a7641b784be","component":"data2-core-primitives@Artboard","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Categorias · Lista","params":{"title":{"component":"data2-core-primitives@String","params":{"content":"Gestão — Categorias · Lista"}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":1000}},"position":{"component":"data2-core-types@Position","params":{"x":0,"y":0}}},"reference":"VuxTMhbjKlklOB_jH6TcJ"},{"_id":"6b7bc7373970d2c25292f14a","parent":"6ac42eb32f4d9a7641b7958c","component":"babi-lf@GestaoLogin","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Login","params":{"auth":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"gestaoAuth"}},"router":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"gestaoRouter"}},"loginForm":"babi-lf@LoginForm","formField":"babi-lf@FormField","button":"babi-lf@Button","notice":"babi-lf@Notice","iconComponent":"babi-lf@Icon","logo":"babi-lf@Logo","codeField":"babi-lf@CodeField","resendCode":"babi-lf@ResendCode","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}}},"text":""},"reference":"xi3xuGfCo2VQhnt1tQzVj"},{"_id":"4a8ad767daa2500cf3b72c13","parent":"6ac528697a27742c85807161","component":"babi-lf@GestaoProdutos","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Produto (Formulário)","params":{"button":"babi-lf@Button","logo":"babi-lf@Logo","notice":"babi-lf@Notice","emptyState":"babi-lf@EmptyState","backLink":"babi-lf@BackLink","view":"form","super":{"position":{"component":"data2-core-types@Position","params":{"x":0,"y":72,"freeTransform":true,"left":true,"right":true,"top":true,"bottom":true}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":2328}}}},"reference":"yz-PKq07mHt-ZB0UkVq-T"},{"_id":"6dd1da82d4f85fa192eb9baa","parent":"6ac528697a27742c85807161","component":"babi-lf@GestaoMenu","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Menu","params":{"logo":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Logo"}},"button":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Button"}},"auth":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"gestaoAuth"}},"active":"produtos","super":{"position":{"component":"data2-core-types@Position","params":{"x":0,"y":0,"freeTransform":true,"left":true,"right":true,"top":true,"bottom":false}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":72}}}},"reference":"Zk0xxfqvumcP3Esir4kVu"},{"_id":"63892c2e1ef88e3a60763ff3","parent":"6ac528665ae4f7827ef80062","component":"babi-lf@GestaoProdutos","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Produtos (Lista)","params":{"button":"babi-lf@Button","logo":"babi-lf@Logo","notice":"babi-lf@Notice","emptyState":"babi-lf@EmptyState","backLink":"babi-lf@BackLink","view":"lista","super":{"position":{"component":"data2-core-types@Position","params":{"x":0,"y":72,"freeTransform":true,"left":true,"right":true,"top":true,"bottom":true}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":928}}}},"reference":"d3TTlzkRQuss55ptqIt-q"},{"_id":"dda6f0a7698fb84ab156c9fc","parent":"6ac528665ae4f7827ef80062","component":"babi-lf@GestaoMenu","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Menu","params":{"logo":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Logo"}},"button":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Button"}},"auth":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"gestaoAuth"}},"active":"produtos","super":{"position":{"component":"data2-core-types@Position","params":{"x":0,"y":0,"freeTransform":true,"left":true,"right":true,"top":true,"bottom":false}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":72}}}},"reference":"GRhRiwP2hh9vtBMM0niwu"},{"_id":"4bd55c4e508f8a567c31a7ba","parent":"6ac4368527b4b62e852125e1","component":"babi-lf@GestaoDestaques","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Destaques","params":{"button":"babi-lf@Button","logo":"babi-lf@Logo","notice":"babi-lf@Notice","super":{"position":{"component":"data2-core-types@Position","params":{"x":0,"y":72,"freeTransform":true,"left":true,"right":true,"top":true,"bottom":true}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":928}}}},"reference":"5Nl0rOCf327xGKD7CbrdF"},{"_id":"fa68e27168766f0582f1f3f4","parent":"6ac4368527b4b62e852125e1","component":"babi-lf@GestaoMenu","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Menu","params":{"logo":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Logo"}},"button":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Button"}},"auth":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"gestaoAuth"}},"active":"destaques","super":{"position":{"component":"data2-core-types@Position","params":{"x":0,"y":0,"freeTransform":true,"left":true,"right":true,"top":true,"bottom":false}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":72}}}},"reference":"ClHKxDp42p3rRw6BBnvhj"},{"_id":"59e20f4ba871a6ce68c3e894","parent":"6ac427cf3ea7d08d375ac111","component":"babi-lf@GestaoCategorias","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Categorias (Formulário)","params":{"categorias":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"categoriasDataSet"}},"produtos":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"produtosDataSet"}},"button":"babi-lf@Button","logo":"babi-lf@Logo","notice":"babi-lf@Notice","emptyState":"babi-lf@EmptyState","backLink":"babi-lf@BackLink","iconComponent":"babi-lf@Icon","view":"form","super":{"position":{"component":"data2-core-types@Position","params":{"x":0,"y":72,"freeTransform":true,"left":true,"right":true,"top":true,"bottom":true}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":928}}}},"reference":"Mm6rzR1xFLpBYt4NwJEm8"},{"_id":"f9350db1facaa8dfc85840c7","parent":"6ac427cf3ea7d08d375ac111","component":"babi-lf@GestaoMenu","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Menu","params":{"logo":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Logo"}},"button":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Button"}},"auth":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"gestaoAuth"}},"active":"categorias","super":{"position":{"component":"data2-core-types@Position","params":{"x":0,"y":0,"freeTransform":true,"left":true,"right":true,"top":true,"bottom":false}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":72}}}},"reference":"85JAqlCpBJJg1sLvjnqVJ"},{"_id":"18cadff8b3929bffe1662c8c","parent":"6ac427cc2f4d9a7641b784be","component":"babi-lf@GestaoCategorias","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Categorias (Lista)","params":{"categorias":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"categoriasDataSet"}},"produtos":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"produtosDataSet"}},"button":"babi-lf@Button","logo":"babi-lf@Logo","notice":"babi-lf@Notice","emptyState":"babi-lf@EmptyState","backLink":"babi-lf@BackLink","iconComponent":"babi-lf@Icon","view":"lista","super":{"position":{"component":"data2-core-types@Position","params":{"x":0,"y":72,"freeTransform":true,"left":true,"right":true,"top":true,"bottom":true}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":928}}}},"reference":"NNjzLJ7HAEYJYG1ro-0tx"},{"_id":"a0799d3320ced5c1abb5ff65","parent":"6ac427cc2f4d9a7641b784be","component":"babi-lf@GestaoMenu","system":"6ab58b1260cbe7aa719c6d7b","displayName":"Gestão — Menu","params":{"logo":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Logo"}},"button":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"Button"}},"auth":{"component":"data2-core-types@InteractiveModuleReference","params":{"reference":"gestaoAuth"}},"active":"categorias","super":{"position":{"component":"data2-core-types@Position","params":{"x":0,"y":0,"freeTransform":true,"left":true,"right":true,"top":true,"bottom":false}},"dimensions":{"component":"data2-core-types@Dimensions","params":{"width":1440,"height":72}}}},"reference":"Nav9Jl1HPeo6Yk4QP74oq"}]}},{"_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":"6ac42bfa80918a4cab93f726","displayName":"Gestão - App","reference":"cNCmH5b34DdBANILnVt7b","params":{"domain":{"component":"data2-core-primitives@String","params":{"content":"gestao"}},"entryPoint":{"component":"data2-core-types@ComponentInstanceReference","params":{"component":"data2-core-primitives@Router","reference":"gestaoRouter"}}},"system":"6ab58b1260cbe7aa719c6d7b","component":"data2-core-primitives@Application"}]}},{"reference":"DataComponentInstancesTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[{"_id":"6abd7aa38dad80a86684a089","component":"data2-core@Data2TableDataSource","system":"6ab58b1260cbe7aa719c6d7b","params":{"table":"produtos","schema":[{"component":"data2-core-types@Field","params":{"key":"nome","title":"Nome","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"slug","title":"Slug","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"sku","title":"Código (SKU)","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"categoria","title":"Categoria","component":{"component":"data2-core-types@Lookup","params":{"table":"categorias"}}}},{"component":"data2-core-types@Field","params":{"key":"subcategoria","title":"Subcategoria","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"marca","title":"Marca","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"origem","title":"Origem (proprio ou parceiro)","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"preco","title":"Preço (cartão)","component":"data2-core-primitives@Number","required":true}},{"component":"data2-core-types@Field","params":{"key":"precoAntigo","title":"Preço \"de\" (riscado)","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"parcelas","title":"Parcelas sem juros","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"estoque","title":"Estoque","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"vendas","title":"Vendas (para \"Mais vendidos\")","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"imagem","title":"Foto principal (URL)","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"destaque","title":"Destaque na home","component":"data2-core-primitives@Boolean"}},{"component":"data2-core-types@Field","params":{"key":"ativo","title":"Ativo (pausa rápida)","component":"data2-core-primitives@Boolean"}},{"component":"data2-core-types@Field","params":{"key":"descricao","title":"Descrição","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"beneficios","title":"Benefícios","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"ficha_tecnica","title":"Ficha técnica","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"instrucoes_uso","title":"Instruções de uso","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"social_video","title":"Vídeo (YouTube/Instagram)","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"desconto_pix","title":"Desconto Pix (%)","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"parceiro","title":"Parceiro","component":"data2-core-primitives@ObjectId"}},{"component":"data2-core-types@Field","params":{"key":"posicao_destaque","title":"Posição no carrossel de destaques (1 a 12)","component":"data2-core-primitives@Number"}}]},"reference":"produtos"},{"_id":"6ac5569306e81c2076f398ec","component":"data2-core@AuthenticationStrategy","system":"6ab58b1260cbe7aa719c6d7b","params":{"credentials":[{"key":"email"},{"key":"senha"}],"verifier":{"component":"data2-core-types@DataSetReference","params":{"reference":"clientesDataSet"}},"email":"email","password":"senha","sessionExpiresIn":432000},"reference":"lojaAuth"},{"_id":"6ac554f706e81c2076f394fe","component":"data2-core@Data2TableDataSource","system":"6ab58b1260cbe7aa719c6d7b","params":{"table":"enderecos","schema":[{"component":"data2-core-types@Field","params":{"key":"cliente_id","title":"Cliente","component":"data2-core-primitives@ObjectId","required":true}},{"component":"data2-core-types@Field","params":{"key":"apelido","title":"Apelido","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"destinatario","title":"Destinatário","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"cep","title":"CEP","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"logradouro","title":"Logradouro","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"numero","title":"Número","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"complemento","title":"Complemento","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"bairro","title":"Bairro","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"cidade","title":"Cidade","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"estado","title":"Estado","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"principal","title":"Principal","component":"data2-core-primitives@Boolean","required":true}}]},"reference":"enderecos"},{"_id":"6ac425f627b4b62e8520ffa3","component":"data2-core@Data2TableDataSource","system":"6ab58b1260cbe7aa719c6d7b","params":{"table":"categorias","schema":[{"component":"data2-core-types@Field","params":{"key":"nome","title":"Nome","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"slug","title":"Slug","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"ativa","title":"Ativa","component":"data2-core-primitives@Boolean","required":true}},{"component":"data2-core-types@Field","params":{"key":"destaque_home","title":"Destaque na home","component":"data2-core-primitives@Boolean"}},{"component":"data2-core-types@Field","params":{"key":"destaque_menu","title":"Destaque no menu","component":"data2-core-primitives@Boolean"}},{"component":"data2-core-types@Field","params":{"key":"ordem","title":"Ordem (menor aparece primeiro)","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"legenda","title":"Legenda do card da home","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"key":"posicao_home","title":"Vaga na home (1 a 4, 0 = fora)","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"posicao_menu","title":"Vaga no menu (1 a 6, 0 = fora)","component":"data2-core-primitives@Number"}},{"component":"data2-core-types@Field","params":{"key":"imagem","title":"Imagem do card (URL)","component":"data2-core-primitives@String"}}]},"reference":"categorias"},{"_id":"6ac554f206e81c2076f394ef","component":"data2-core@DataSet","system":"6ab58b1260cbe7aa719c6d7b","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"clientes"}}},"reference":"clientesDataSet"},{"_id":"6ac42e7eb4eec9d29421f57b","component":"data2-core@AuthenticationStrategy","system":"6ab58b1260cbe7aa719c6d7b","params":{"verifier":{"component":"data2-core-types@DataSetReference","params":{"reference":"6_3UBkN6d7vNEGCJroFVl"}},"email":{"params":{"column":"email"},"component":"data2-core-types@DataSetColumnReference"},"password":{"params":{"column":"senha"},"component":"data2-core-types@DataSetColumnReference"},"sessionExpiresIn":{"component":"data2-core-primitives@Number","params":{"content":604800}},"credentials":[{"component":"data2-core-types@FieldReference","params":{"key":"email"}},{"component":"data2-core-types@FieldReference","params":{"key":"senha"}}]},"reference":"gestaoAuth"},{"_id":"6ac554f22f525bb523614c0d","component":"data2-core@Data2TableDataSource","system":"6ab58b1260cbe7aa719c6d7b","params":{"table":"clientes","schema":[{"component":"data2-core-types@Field","params":{"key":"nome","title":"Nome","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"email","title":"E-mail","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"whatsapp","title":"WhatsApp","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"tipo_documento","title":"Tipo do documento","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"documento","title":"Documento","component":"data2-core-primitives@String","required":true}},{"component":"data2-core-types@Field","params":{"key":"senha","title":"Senha","component":"data2-core-types@Password","required":true}},{"component":"data2-core-types@Field","params":{"key":"aceite_politica_privacidade","title":"Aceite da Política de Privacidade","component":"data2-core-primitives@Boolean","required":true}},{"component":"data2-core-types@Field","params":{"key":"aceite_comunicacao","title":"Aceite de comunicações","component":"data2-core-primitives@Boolean","required":true}},{"component":"data2-core-types@Field","params":{"key":"aceite_comunicacao_em","title":"Aceite de comunicações em","component":"data2-core-primitives@Date"}}]},"reference":"clientes"},{"_id":"6ac557b8f3014ecbcc85dd15","component":"data2-core@DataSet","system":"6ab58b1260cbe7aa719c6d7b","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"InQsnvuho7YIJaf_l4nOM"}},"autoSelect":{"component":"data2-core-primitives@Boolean","params":{"content":true}},"pagination":{"size":20}},"reference":"6_3UBkN6d7vNEGCJroFVl"},{"_id":"6ac55756f3014ecbcc85dd13","component":"data2-core@Data2TableDataSource","system":"6ab58b1260cbe7aa719c6d7b","params":{"table":"InQsnvuho7YIJaf_l4nOM","multi":["create"],"schema":[{"component":"data2-core-types@Field","params":{"title":"nome","key":"nome","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"title":"email","key":"email","component":"data2-core-primitives@String"}},{"component":"data2-core-types@Field","params":{"title":"senha","key":"senha","component":"data2-core-types@Password"}}]},"reference":"InQsnvuho7YIJaf_l4nOM"},{"_id":"6abd7aa3edeff59159dcced1","component":"data2-core@DataSet","system":"6ab58b1260cbe7aa719c6d7b","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"produtos"}}},"reference":"produtosDataSet"},{"_id":"6ac425f6005d4042c2e322de","component":"data2-core@DataSet","system":"6ab58b1260cbe7aa719c6d7b","params":{"datasource":{"component":"data2-core-types@DataSourceReference","params":{"reference":"categorias"}}},"reference":"categoriasDataSet"}]}},{"reference":"BundlesTableDataSource","component":"data2-core@MemoryDataSource","params":{"initialData":[]}}],"processesParams":{}}}}