diff --git a/tests/artwork_browser_test.mjs b/tests/artwork_browser_test.mjs index dbcfc55..7dd952f 100644 --- a/tests/artwork_browser_test.mjs +++ b/tests/artwork_browser_test.mjs @@ -115,7 +115,7 @@ try{ await call('Runtime.enable');await call('Page.enable'); await call('Emulation.setDeviceMetricsOverride',{width:1440,height:1100,deviceScaleFactor:1,mobile:false}); await call('Page.navigate',{url:`http://127.0.0.1:${server.address().port}/`}); - await waitFor(()=>evaluate(`typeof sel==='function' && typeof AUTO!=='undefined'`),'Site scripts'); + await waitFor(()=>evaluate(`typeof sel==='function' && typeof pintaEntrega==='function'`),'Site scripts'); // Observe the actual engine, without replacing its placement or rendering. await evaluate(`(()=>{ const original=encaixar; @@ -149,6 +149,9 @@ try{ // Navigation links must reach the chooser, never preselect a product. assert.equal(await evaluate(`document.querySelectorAll('[data-modo-cta]').length`),0); await click('[data-modo="file"]'); + // Opening a product paints on the next frame; on a busy runner the check + // must wait for it rather than race it. + await waitFor(()=>evaluate(`!$('tipoEnvio').hidden`),'by-metre product open'); // By-metre opens declaring a mounted sheet; switching is explicit and priced. assert.deepEqual(await evaluate(`({shown:!$('tipoEnvio').hidden, on:[...document.querySelectorAll('#tipoEnvio .cam.on')].map(b=>b.dataset.tipo)})`), @@ -293,13 +296,14 @@ try{ await fill('[data-cm]',10);await fill('[data-q]',4);await packed(4); } // An older image load must not overwrite a newer edit, even before debounce. - await evaluate(`(()=>{window.realLoad=carregarImagem;window.delayed=[]; - carregarImagem=f=>new Promise(resolve=>delayed.push(()=>realLoad(f).then(resolve))); + // The packing loads each artwork's image through imagemDaArte. + await evaluate(`(()=>{window.realLoad=imagemDaArte;window.delayed=[]; + imagemDaArte=a=>new Promise(resolve=>delayed.push(()=>realLoad(a).then(resolve))); })()`); await fill('[data-q]',5); await waitFor(()=>evaluate('delayed.length===1'),'delayed preview'); await fill('[data-q]',7); - await evaluate(`carregarImagem=realLoad;delayed[0]()`); + await evaluate(`imagemDaArte=realLoad;delayed[0]()`); await packed(7); const timeoutCleanup=await evaluate(`(async()=>{ const realLoader=carregarPdfJs, realTimer=setTimeout, realWorker=temWorker; diff --git a/tests/browser_test.mjs b/tests/browser_test.mjs index 94df84a..5ea3f5e 100644 --- a/tests/browser_test.mjs +++ b/tests/browser_test.mjs @@ -62,12 +62,13 @@ try{ await site.call('Page.setBypassCSP',{enabled:false}); await site.call('Page.reload'); await waitFor(()=>site.eval('typeof window.dtfCheckout === "function"'),'reload after security probe'); + // The check above can still pass on the page being replaced; wait for the new one's cards. + await waitFor(()=>site.eval(`!!document.querySelector('[data-modo="file"]') && document.readyState==='complete'`),'product cards after reload'); await site.click('[data-modo="file"]'); // Each product has its own page; the home's parts are not on it. assert.deepEqual(await site.eval(`({path:location.pathname,page:document.documentElement.dataset.rota, cards:getComputedStyle($('cards')).display,cart:getComputedStyle($('carr')).display})`), {path:'/arquivo-por-metro',page:'produto',cards:'none',cart:'none'}); - await site.click('[data-cam="tabela"]'); const root=await site.call('DOM.getDocument'); const input=await site.call('DOM.querySelector',{nodeId:root.root.nodeId,selector:'#inp'}); await site.call('DOM.setFileInputFiles',{nodeId:input.nodeId,files:[resolve('tests/fixtures/local-test.cdr')]}); diff --git a/web/checkout.js b/web/checkout.js index 011c10b..eb80270 100644 --- a/web/checkout.js +++ b/web/checkout.js @@ -112,12 +112,21 @@ return window.dtfUpload(file,{api,scope:session.cart_scope,progress:()=>{}, onBytes:n=>{e.sent=n;pintaEnvio();}}); })(); - e.promise.then(()=>{e.done=true;pintaEnvio();}, - error=>{e.failed=error;envios.delete(k);pintaEnvio();}); + e.promise.then(()=>{e.done=true;falhas.delete(k);pintaEnvio();}, + error=>{envios.delete(k);falhas.set(k,{file,error});pintaEnvio();}); envios.set(k,e); } return e.promise; } + // A failed upload is shown and waits for the customer, never retried behind + // their back: a file the check refused would fail again on every change. + const falhas=new Map(); + function tentaDeNovo() { + const arquivos=[...falhas.values()].map(f=>f.file); + falhas.clear(); + arquivos.forEach(f=>enviar(f).catch(()=>{})); + pintaEnvio(); + } const arquivosDoCarrinho=()=>[...pedido,...(busy&&itemAtual?[itemAtual]:[])].flatMap(it=>it.localFiles||[]); const gb=n=>(n/1073741824).toLocaleString('pt-BR',{maximumFractionDigits:1})+' GB'; const mb=n=>n>=1073741824 ? gb(n) : Math.round(n/1048576)+' MB'; @@ -149,6 +158,20 @@ function pintaEnvio() { const e=estadoEnvio(), texto=textoEnvio(e); const el=document.getElementById('envioArq'); + const falhou=arquivosDoCarrinho().map(f=>falhas.get(chaveArquivo(f))).filter(Boolean); + const topo=document.getElementById('cartEnvio'); + if (falhou.length) { + if (el) { + el.replaceChildren(document.createTextNode('Não foi possível enviar '+falhou[0].file.name+': '+ + (falhou[0].error?.message||'erro no envio').replace(/\.$/,'')+(falhou.length>1?' (e mais '+(falhou.length-1)+')':'')+'. ')); + const b=document.createElement('button'); b.type='button'; b.className='envioDeNovo'; b.textContent='Tentar de novo'; + b.onclick=tentaDeNovo; el.append(b); + el.classList.remove('ok'); el.classList.add('erro'); + } + if (topo) topo.textContent='· falha no envio'; + return; + } + if (el) el.classList.remove('erro'); if (el) { el.replaceChildren(); if (e && e.fase!=='pronto') { @@ -160,7 +183,6 @@ el.classList.toggle('ok', e?.fase==='pronto'); } // Visible on every page while it runs. - const topo=document.getElementById('cartEnvio'); if (topo) topo.textContent = !e || e.fase==='pronto' ? '' : e.fase==='verificando' ? '· verificando' : '· enviando '+e.pct+'%'; if (busy && texto) { message(texto); @@ -173,7 +195,10 @@ if (e && e.fase==='enviando') { event.preventDefault(); event.returnValue=''; } }); // Only what is in the cart: the item on the product page may still change. - window.addEventListener('dtf-cart-changed',()=>{ arquivosDoCarrinho().forEach(f=>{ enviar(f).catch(()=>{}); }); pintaEnvio(); }); + window.addEventListener('dtf-cart-changed',()=>{ + arquivosDoCarrinho().forEach(f=>{ if(!falhas.has(chaveArquivo(f))) enviar(f).catch(()=>{}); }); + pintaEnvio(); + }); async function upload(file) { return enviar(file); } diff --git a/web/index.html b/web/index.html index 51c37bb..b2b76bc 100644 --- a/web/index.html +++ b/web/index.html @@ -234,8 +234,6 @@ h1 em{font-style:normal;color:var(--laranja)} font-family:"Inter",sans-serif;font-weight:700} /* upload */ -/* o cliente escolhe o caminho antes de subir · a declaração orienta, - mas quem decide o preço é o arquivo que chegar */ .caminhos{display:grid;grid-template-columns:1fr 1fr;gap:9px;margin-bottom:13px} @media(max-width:620px){.caminhos{grid-template-columns:1fr}} .caminhos>*{min-width:0} @@ -254,7 +252,6 @@ h1 em{font-style:normal;color:var(--laranja)} .cam span{display:block;font-size:10.5px;color:var(--fraco);line-height:1.45} .cam em{display:block;margin-top:6px;font-style:normal;font-family:"Inter",sans-serif; font-weight:700;font-size:12px;color:var(--verde-ml);line-height:1.3} -.cam em.cheio{color:var(--vermelho)} .trocouCam{margin-top:-4px;margin-bottom:11px;padding:10px 12px;border-radius:9px; background:#FFF6E8;border:1px solid #F0D9AE;font-size:11.5px;color:#7A5A16;line-height:1.5} .trocouCam b{color:#B07A18;font-family:"Inter",sans-serif;font-weight:700} @@ -301,12 +298,6 @@ h1 em{font-style:normal;color:var(--laranja)} /* repetição do FILE */ .rep{background:var(--cinza);border-radius:9px;padding:12px 14px;margin-top:8px} -.somaF{margin-top:10px;padding:11px 13px;border-radius:9px;background:#F1FBF5; - border:1px solid #BFE6CE;display:flex;flex-wrap:wrap;align-items:baseline;gap:8px} -.somaF span{font-size:11.5px;color:#2A6B45} -.somaF b{font-family:"Inter",sans-serif;font-weight:700;font-size:15px;color:#1F5C3A; - margin-left:auto} -.somaF em{flex-basis:100%;font-style:normal;font-size:10.5px;color:#4A7A5E} .rep .l1{display:flex;justify-content:space-between;gap:10px;align-items:center;margin-bottom:9px} .rep .l1 b{font-weight:500;font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} .rep .l1 button{border:0;background:none;color:var(--fraco);cursor:pointer;font-size:15px;flex:none} @@ -317,33 +308,10 @@ h1 em{font-style:normal;color:var(--laranja)} .progF{margin:9px 0 4px;padding:9px 11px;border-radius:7px;background:#FFF6E8; border:1px solid #F0D9AE;font-size:11px;color:#7A5A16;line-height:1.5} .progF b{font-family:"Inter",sans-serif;font-weight:700;color:#B07A18} -.rep .cps{display:grid;grid-template-columns:120px 1fr;gap:10px;align-items:end} .rep label{display:block;font-size:10px;color:var(--fraco);margin-bottom:3px} .rep input{width:100%;padding:7px 9px;border:1px solid var(--linha);border-radius:6px; font-family:inherit;font-size:13px;background:#fff;color:var(--tx)} .rep input:focus{outline:none;border-color:var(--laranja)} -.rep .conta{font-size:11.5px;color:var(--fraco);line-height:1.4} -.rep .conta b{color:var(--tx);font-family:"Inter",sans-serif} -.med{background:#fff;border:1px solid var(--linha);border-radius:8px;padding:10px 12px;margin-top:9px} -.med b{display:block;font-family:"Inter",sans-serif;font-size:15px;font-weight:700;color:var(--tx)} -.med span{display:block;font-size:11px;color:var(--fraco);margin-top:2px} -.med em{display:block;font-style:normal;font-size:11.5px;color:#B07A18;margin-top:7px;line-height:1.45} -.med.alerta{border-color:#E8A796;background:#FFF3F0} -.med.alerta b{color:#8C3B22} -.med.alerta em{color:#8C3B22} -.med.pede{border-color:var(--laranja);background:#FFFAF2} -.med.pede b{font-size:12.5px;color:#B07A18} -.conf{margin-top:9px;padding:9px 11px;border-radius:7px;background:#F1FBF5; - border:1px solid #BFE6CE;line-height:1.5} -.conf b{display:block;font-family:"Inter",sans-serif;font-size:11.5px;color:#1F5C3A; - margin-bottom:3px} -.conf span{display:block;font-size:10.5px;color:#2A6B45} -.med .troca{margin-top:9px;padding:9px 11px;border-radius:7px;background:#F1FBF5; - border:1px solid #BFE6CE;font-size:11.5px;color:#1F5C3A;line-height:1.5} -.med .troca b{display:inline;font-size:11.5px;color:#1F5C3A;font-weight:700} -.med input{width:100%;margin-top:8px;padding:8px 10px;border:1px solid var(--linha); - border-radius:6px;font-family:inherit;font-size:13px;background:#fff;color:var(--tx)} -.med input:focus{outline:none;border-color:var(--laranja)} /* fila de artes ao lado da montagem */ .foco2{display:grid;grid-template-columns:minmax(340px,1fr) 320px;gap:20px; @@ -929,55 +897,39 @@ footer a:hover{color:var(--laranja2)}

—

- -

- -
- - -
+ +
↑
Arraste aqui Até 5 GB por arquivo. ou escolher no computador + Adicionar outra folha ou arraste aqui + Tem CDR, AI, PSD ou TIFF? Pode mandar também. + Alguém abre na mão e o metro sai pelo preço cheio.
- -
-

Revisão de 5 pontos e reencaixe grátis

+

Revisamos e reencaixamos antes de imprimir, sem custo.

+ +
Sua folha +
+
+
diff --git a/web/site-cart.js b/web/site-cart.js index accb66a..bdef20a 100644 --- a/web/site-cart.js +++ b/web/site-cart.js @@ -120,7 +120,7 @@ function carrinho(){ previa(); if(nota<90){ const piso=pisoEscada(), ganho=(base-piso)*cob; - if(ganho>0.5) qm('Dá para chegar ao melhor preço. Corrigindo os pontos e chegando a 90, '+ + if(ganho>0.5) qm('Dá para pagar menos. Com a arte em 300 DPI, '+ 'o metro cai para '+rs(piso)+' — são '+rs(ganho)+' a menos neste pedido.','var(--verde)'); } } diff --git a/web/site-compra.js b/web/site-compra.js index fd2154a..c82857f 100644 --- a/web/site-compra.js +++ b/web/site-compra.js @@ -1,4 +1,4 @@ -/* Site DTF — the product page's buy box: grade, price per metre, billed length, +/* Site DTF — the product page's buy box: price ladder, price per metre, billed length, total and the add-to-cart button, beside the live sheet. It shows the item the other site-*.js files already priced (itemAtual) and never computes a price of its own, so the box and the cart always agree. */ @@ -10,18 +10,29 @@ add.disabled=!it || !itemPodeEnviar(it); if(!it) return; const semNota=!it.nota; - $('cNota').textContent = semNota ? 'sem nota' : it.nota; - $('cNotaBar').style.width=(semNota?0:it.nota)+'%'; - $('cNotaBar').className = semNota ? '' : it.nota>=85 ? 'ok' : it.nota>=50 ? 'av' : 'er'; - $('cTabela').textContent = TABELA[it.modo]-it.unit>0.001 ? rs(TABELA[it.modo]) : ''; + // The price ladder in resolution: nota = DPI ÷ 3, so 90 is 270 DPI. + const faixas=FAIXAS[it.modo], ativa=faixas.findIndex(([min])=>it.nota>=min); + $('cEscada').innerHTML=faixas.map(([min,v],i)=> + ''+ + (min? min*3+'+'+(i? '' : ' DPI') : semNota? 'cheio' : 'menos')+''+ + ''+rs(v).slice(3)+'').join(''); + const analisadas=ehFolha(it.modo) && folhas.length && folhas.every(x=>x.an); + $('cMetroLbl').textContent = semNota ? 'Metro · preço cheio' + : analisadas && folhas.every(x=>x.an.vetor) ? 'Metro · arte vetorial' + : analisadas ? 'Metro · '+Math.min(...folhas.map(x=>x.an.dpi))+' DPI' + : 'Metro'; $('cMetro').textContent=rs(it.unit); $('cMetragem').textContent=fmtM(it.cob)+' m'; + const economia=(TABELA[it.modo]-it.unit)*it.cob; + $('cEco').textContent = economia>0.005 ? rs(economia)+' a menos pela resolução da arte' : ''; + const partes=ehFolha(it.modo) ? Math.ceil(it.metros/20) : 1; + $('cPartes').textContent = partes>1 ? ' Sai em '+partes+' partes de até 20 m.' : ''; const sobraCm=Math.round((it.cob-it.metros)*100); $('cObs').textContent = it.cob===MINIMO_M && it.metros0 ? fmtM(it.metros)+' m de folha, arredondado a cada 10 cm.' : ''; + : ''; $('cTotal').textContent=rs(it.total); } add.addEventListener('click',()=>adicionaAoCarrinho()); diff --git a/web/site-config.js b/web/site-config.js index 815b6ae..b1f5d21 100644 --- a/web/site-config.js +++ b/web/site-config.js @@ -5,28 +5,19 @@ const $=id=>document.getElementById(id); const rs=v=>'R$ '+v.toFixed(2).replace('.',','); -const fmt=b=>b<1048576?(b/1024).toFixed(0)+' KB':(b/1048576).toFixed(1).replace('.',',')+' MB'; +const fmt=b=>b<1048576?(b/1024).toFixed(0)+' KB' + :b<1073741824?(b/1048576).toFixed(1).replace('.',',')+' MB':(b/1073741824).toFixed(1).replace('.',',')+' GB'; // ── modos const MODOS={ - file: {tit:'Arquivo por metro', lg:'DTF têxtil · 57 cm', larg:57, - preco:'R$ 14,90 a R$ 19,90 /m conforme a nota', multi:true, folha:true, - sub:'Sua folha montada. Revisamos, corrigimos e reencaixamos antes de imprimir.', - zt:'Arraste suas folhas montadas', - zs:'uma ou várias · PNG, JPG, TIFF ou PDF · PSD, AI e CDR passam por tratamento'}, - avulsa:{tit:'Artes avulsas', lg:'DTF têxtil · 57 cm', larg:57, - preco:'R$ 24,90 a R$ 29,90 /m conforme a nota', multi:true, - sub:'Cada arte num arquivo. Montamos a folha com o melhor encaixe.', + file: {tit:'Arquivo por metro', lg:'DTF têxtil · 57 cm', larg:57, multi:true, folha:true, + zt:'Arraste sua folha montada aqui', zs:'PNG, JPG ou PDF · 57 cm de largura'}, + avulsa:{tit:'Artes avulsas', lg:'DTF têxtil · 57 cm', larg:57, multi:true, zt:'Arraste suas artes aqui', zs:'PNG ou JPG com fundo transparente · informe a largura de cada uma'}, - uvfile:{tit:'Arquivo por metro · UV', lg:'Adesivo UV · 28,5 cm', larg:28.5, - preco:'R$ 69,90 a R$ 85,90 /m conforme a nota', multi:true, folha:true, - sub:'Sua folha de UV montada. Revisamos, corrigimos e reencaixamos antes de imprimir.', - zt:'Arraste suas folhas de UV', - zs:'uma ou várias · PNG, JPG, TIFF ou PDF · PSD, AI e CDR passam por tratamento'}, - uv: {tit:'Artes avulsas · UV', lg:'Adesivo UV · 28,5 cm', larg:28.5, - preco:'R$ 83,90 a R$ 99,90 /m conforme a nota', multi:true, - sub:'Cada arte de UV num arquivo. Montamos a folha com o melhor encaixe.', + uvfile:{tit:'Arquivo por metro · UV', lg:'Adesivo UV · 28,5 cm', larg:28.5, multi:true, folha:true, + zt:'Arraste sua folha de UV aqui', zs:'PNG, JPG ou PDF · 28,5 cm de largura'}, + uv: {tit:'Artes avulsas · UV', lg:'Adesivo UV · 28,5 cm', larg:28.5, multi:true, zt:'Arraste suas artes de UV', zs:'PNG ou JPG com fundo transparente · informe a largura de cada arte'} }; @@ -77,7 +68,6 @@ let pedido=[]; // itens já fechados · o pagamento // ao que a expedição já recebe hoje, sem criar processo novo. let entrega={tipo:'retira', cep:'', valor:0, cotado:true, end:{}}; let cliente={cnpj:'', zap:'', mail:''}; -let caminho='auto'; // o que o cliente diz que vai mandar // CNPJ com os dois dígitos verificadores · máscara sem conta não vale nada function cnpjOk(v){ diff --git a/web/site-flow.js b/web/site-flow.js index 6140cb1..532468a 100644 --- a/web/site-flow.js +++ b/web/site-flow.js @@ -1,4 +1,4 @@ -/* Site DTF — Carousel, path selector, delivery choice and input masks. +/* Site DTF — Carousel, delivery choice and input masks. Extracted verbatim from the single inline script in web/index.html. Loaded as classic scripts in the order listed there: they share one global scope and run top to bottom, exactly as the original did. */ @@ -73,31 +73,6 @@ $('pVolta').addEventListener('click',()=>{ $('cPro').addEventListener('click',()=>ir(atual()+1)); })(); -// A declaração de formato só orienta: filtra o seletor e mostra o preço esperado. -// Se o arquivo que chegar contrariar, o arquivo ganha e o site avisa. -const AUTO=/[.](png|jpe?g|webp|pdf)$/i; -function pintaCaminhos(){ - if(!$('caminhos')) return; - const ehF=modo&&ehFolha(); - $('caminhos').style.display = ehF? '' : 'none'; - if(!ehF) return; - document.querySelectorAll('#caminhos .cam').forEach(b=>b.classList.toggle('on', b.dataset.cam===caminho)); - $('camA').textContent='a partir de '+rs(pisoEscada()); - $('camB').textContent=rs(TABELA[modo])+' fixo'; - $('inp').accept = caminho==='auto' ? '.png,.jpg,.jpeg,.pdf' - : '.tif,.tiff,.psd,.psb,.ai,.cdr'; - $('zSub').textContent = caminho==='auto' - ? 'PNG, JPG ou PDF · conferência automática, nota na tela' - : 'CDR, AI, PSD ou TIFF · sem conferência, metro pela tabela'; -} -document.querySelectorAll('#caminhos .cam').forEach(b=>b.addEventListener('click',()=>{ - caminho=b.dataset.cam; avisoCam(''); pintaCaminhos(); -})); -function avisoCam(txt){ - const el=$('trocouCam'); if(!el) return; - el.innerHTML=txt; el.style.display = txt? '' : 'none'; -} - function pintaEntrega(){ document.querySelectorAll('.opE').forEach(b=> b.classList.toggle('on', b.dataset.ent===entrega.tipo)); @@ -150,6 +125,14 @@ $('zMenos').addEventListener('click',()=>{ if(zoomI>0){ zoomI--; pintaZoom(); previaAoVivo(); } }); pintaZoom(); +// A ready sheet has nothing to zoom: "Ampliar" shows the same preview bigger. +$('bAmpliar').addEventListener('click',()=>{ + const previas=$('vArea').querySelector('.folhaPrevias'); if(!previas) return; + $('ampliaArea').replaceChildren(previas.cloneNode(true)); + $('ampliaDlg').showModal(); +}); +$('ampliaFecha').addEventListener('click',()=>$('ampliaDlg').close()); +$('ampliaDlg').addEventListener('click',e=>{ if(e.target===$('ampliaDlg')) $('ampliaDlg').close(); }); document.querySelectorAll('.opE').forEach(b=>b.addEventListener('click',()=>{ entrega.tipo=b.dataset.ent; diff --git a/web/site-modes.js b/web/site-modes.js index 4173f42..7eca571 100644 --- a/web/site-modes.js +++ b/web/site-modes.js @@ -15,7 +15,7 @@ function abrir(m){ avisoTipo(''); pintaModo(); $('lista').innerHTML=''; $('rA').style.display='none'; recusa([]); - recemChegada=null; caminho='auto'; avisoCam(''); pintaCaminhos(); + recemChegada=null; $('vMt').textContent='—'; previaAoVivo(); agendaAvaliacao(); limpaPaineis(); // o carrinho só some se o pedido estiver vazio vaiPara(PAGINAS[m]); @@ -25,10 +25,13 @@ function pintaModo(){ const c=MODOS[m]; $('cards').style.display='none'; $('foco').classList.add('on'); $('fTit').textContent=c.tit; $('fLg').textContent=c.lg; - $('fPreco').textContent=c.preco; $('fSub').textContent=c.sub; $('zTit').textContent=c.zt; $('zSub').textContent=c.zs; + $('zManual').hidden=!ehFolha(m); + $('zOutra').textContent = ehFolha(m) ? 'Adicionar outra folha' : 'Adicionar mais artes'; + $('zona').classList.remove('compacta'); $('inp').multiple=c.multi; - $('inp').accept = ehFolha(m) ? '.png,.jpg,.jpeg,.pdf' + // The file decides the price: PNG, JPG and PDF are checked here, the others by hand. + $('inp').accept = ehFolha(m) ? '.png,.jpg,.jpeg,.pdf,.tif,.tiff,.psd,.psb,.ai,.cdr' : '.png,.jpg,.jpeg,.webp'; $('catFoco').className='cat '+(ehFolha(m)?'file':'av'); $('larguraFolhaPronta').textContent=String(c.larg).replace('.',','); @@ -46,8 +49,8 @@ function pintaTipoEnvio(){ if(el.hidden) return; const folha = ehFolha() ? modo : PAR[modo]; const avulsa = ehFolha() ? PAR[modo] : modo; - $('tipoFolhaPreco').textContent='a partir de '+rs(pisoEscada(folha)); - $('tipoAvulsaPreco').textContent='a partir de '+rs(pisoEscada(avulsa))+' · montagem inclusa'; + $('tipoFolhaPreco').textContent=rs(pisoEscada(folha))+' a '+rs(TABELA[folha]).slice(3)+' /m'; + $('tipoAvulsaPreco').textContent='+ '+rs(MONTAGEM[avulsa])+' /m'; $('larguraFolhaPronta').textContent=String(MODOS[folha].larg).replace('.',','); const atual = ehFolha() ? 'folha' : 'avulsa'; el.querySelectorAll('.cam').forEach(b=>{ @@ -89,8 +92,7 @@ function trocaTipo(destino){ modo=destino; history.replaceState(history.state,'',PAGINAS[modo]); document.title=tituloPagina(); $('lista').innerHTML=''; $('rA').style.display='none'; recusa([]); - caminho='auto'; avisoCam(''); - pintaModo(); pintaCaminhos(); limpaPaineis(); agendaAvaliacao(); previaAoVivo(); + pintaModo(); limpaPaineis(); agendaAvaliacao(); previaAoVivo(); } $('bVoltar').addEventListener('click',()=>{ itemAtual=null; modo=null; $('atual').style.display='none'; $('carrLin').innerHTML=''; pintaPedido(); diff --git a/web/site-packing.js b/web/site-packing.js index 05c6881..9edfdcf 100644 --- a/web/site-packing.js +++ b/web/site-packing.js @@ -286,6 +286,7 @@ function previaAoVivo(){ clearTimeout(tMont); montagemLayout=null; $('vArea').montagemVersao=($('vArea').montagemVersao||0)+1; + if(!ehFolha()) $('bAmpliar').hidden=true; if(ehFolha()){ $('vUso').innerHTML=''; const tot=folhaTotalM(); @@ -319,7 +320,9 @@ function previaAoVivo(){ figura.append(pilha,legenda); painel.append(figura); }); $('vArea').replaceChildren(painel); + $('bAmpliar').hidden=false; }else{ + $('bAmpliar').hidden=true; $('vArea').innerHTML = medidas.length ? '
'+(medidas.length>1 ? medidas.length+' folhas · '+fmtM(tot)+' m' diff --git a/web/site-pdf.js b/web/site-pdf.js index 929ad87..26a1b01 100644 --- a/web/site-pdf.js +++ b/web/site-pdf.js @@ -356,6 +356,15 @@ function textoProgresso(x){ if(x.med && x.med.grande) return 'gerando a prévia e conferindo a arte… '+x.pct+'%'; return x.pct<50?'lendo o arquivo…':x.pct<70?'medindo a folha…':'conferindo a arte…'; } +// The file card's thumbnail (52 x 96 px, drawn at twice that for sharp screens). +function miniatura(fonte){ + const w=fonte.naturalWidth||fonte.width, h=fonte.naturalHeight||fonte.height; + if(!(w>0 && h>0)) return null; + const s=Math.min(1,104/w,192/h), cv=document.createElement('canvas'); + cv.width=Math.max(1,Math.round(w*s)); cv.height=Math.max(1,Math.round(h*s)); + cv.getContext('2d').drawImage(fonte,0,0,cv.width,cv.height); + return cv.toDataURL('image/webp',0.8); +} // Moves one sheet's progress bar in place: repainting the whole list and the // preview on every step made "Sua folha" flicker while a large file was read. function pintaProgressoFolha(x){ @@ -364,66 +373,79 @@ function pintaProgressoFolha(x){ if(!barra){ pintaFolha(); return; } barra.style.width=x.pct+'%'; if(texto) texto.textContent=textoProgresso(x); } +// What the check found, as chips: ok (verde), av (atenção), er (resolva você), +// fix (arrumamos de graça), nt (a equipe confere). Details stay one click away. +function chipsDaFolha(a){ + const chip=(k,t)=>'
  • '+t+'
  • '; + const dpi = a.vetor ? chip('ok','Arte vetorial') + : chip(a.dpi>=DPI_AVISA?'ok':a.dpi>=DPI_RECUSA?'av':'er', a.dpi+' DPI'); + if(a.grande) return dpi+chip('nt','Peças, resíduos e fundo: a equipe confere'); + return dpi+ + (a.fundoChapado? chip('er','Fundo chapado') : chip('ok','Fundo transparente'))+ + (a.residuos? chip('er',a.residuos+' resíduo'+(a.residuos>1?'s':'')) : chip('ok','Sem resíduos'))+ + (a.encostadas? chip('fix',a.encostadas+' peças coladas · separamos grátis') : chip('ok','Peças separadas')); +} +function avisosDaFolha(a){ + if(a.grande) return ''; + return (a.fundoChapado? '

    O fundo não é transparente. '+ + 'Branco parecendo transparente sai branco no filme. Exporte com fundo transparente.

    ' : '')+ + (a.residuos? '

    '+a.residuos+' pontinho'+(a.residuos>1?'s soltos serão impressos':' solto será impresso')+ + '. A impressora imprime qualquer resíduo de recorte. Apague no arquivo e envie de novo.

    ' : ''); +} +function detalhesDaFolha(a,i,aberto){ + const linhas = a.grande + ? ['Resolução '+a.dpi+' DPI, lida do arquivo', + 'Arquivo grande: peças, resíduos e fundo são conferidos pela equipe'] + : [a.artes+' peça'+(a.artes===1?'':'s')+' · '+a.aproveitamento+'% da folha com arte', + 'Resolução '+a.dpi+' DPI · '+(a.fonteDpi==='imagens'? 'medida imagem por imagem dentro do PDF' + : a.fonteDpi==='vetor'? 'arte vetorial, sem imagem embutida' : 'lida do arquivo'), + 'Conferido numa grade de '+n1(a.grade)+' mm']; + return '
    '+ + 'Ver detalhes da conferência'+ + linhas.map(l=>''+l+'').join('')+'
    '; +} function pintaFolha(){ invalidaItemAtual(); const L=larguraFilme(); pintaTipoEnvio(); // trava o seletor enquanto houver folha + $('zona').classList.toggle('compacta', folhas.length>0); if(!folhas.length){ $('lista').innerHTML=''; agendaAvaliacao(); previaAoVivo(); return; } - $('lista').innerHTML = folhas.map((x,i)=>{ + const tot=folhaTotalM(); + $('lista').innerHTML = '

    Seus arquivos

    '+ + folhas.length+' folha'+(folhas.length>1?'s':'')+(tot>0? ' · '+fmtM(tot)+' m' : '')+'
    '+ + folhas.map((x,i)=>{ const lido=!!x.med, larga=lido && x.med.larg>L, suspeito=lido && x.med.foraDoPadrao; - const sub=(x.m||0)*(x.rep||1); - let medida=''; + const sub=(x.m||0)*(x.rep||1), a=lido && x.an; + let medida='', manual=''; if(lido){ - const a=x.an; - const conferido = a && a.grande - ? '
    Arquivo grande · '+a.dpi+' DPI'+ - 'nota pela resolução · peças, resíduos e fundo conferidos pela equipe
    ' - : a - ? '
    Conferido de verdade'+ - ''+a.artes+' peça'+(a.artes===1?'':'s')+' · '+a.aproveitamento+ - '% da folha virou arte · '+ - (a.residuos? a.residuos+' resíduo'+(a.residuos>1?'s':'') : 'sem resíduo')+' · '+ - (a.fundoChapado? 'fundo chapado' : 'fundo transparente')+''+ - 'resolução '+a.dpi+' DPI · '+ - (a.fonteDpi==='imagens'? 'medida imagem por imagem dentro do PDF' - : a.fonteDpi==='vetor'? 'arte vetorial, sem imagem embutida' - : 'lida do arquivo')+ - ' · grade de '+n1(a.grade)+' mm
    ' - : ''; - medida='
    '+ - ''+n1(x.med.larg)+' × '+n1(x.med.alt)+' cm'+ - ''+x.med.fonte+' · '+fmtM(x.m)+' m de folha'+ - conferido+ - (suspeito? 'Este PDF passa do tamanho que o formato comporta. '+ + medida='
    '+n1(x.med.larg)+' × '+n1(x.med.alt)+' cm'+ + ''+escapeHTML(extDe(x.f.name))+' · '+fmt(x.f.size)+'
    '+ + (a? '
      '+chipsDaFolha(a)+'
    '+avisosDaFolha(a)+detalhesDaFolha(a,i,x.detAberto) : '')+ + (suspeito? '

    Este PDF passa do tamanho que o formato comporta. '+ 'A especificação para em 508 cm e o seu tem '+n1(x.med.alt)+' cm. '+ 'Ele abre certo só em quem o gerou — aqui vai precisar de tratamento. '+ - 'Manda em PNG ou TIFF, ou divide em partes de até 5 m, que sai na hora.':'')+ - (larga? 'Esta folha não roda neste filme. Ela tem '+n1(x.med.larg)+ + 'Manda em PNG ou TIFF, ou divide em partes de até 5 m, que sai na hora.

    ':'')+ + (larga? '

    Esta folha não roda neste filme. Ela tem '+n1(x.med.larg)+ ' cm de largura e o filme aqui tem '+n1(L)+' cm. Não dá para reduzir: '+ 'encolher a folha encolheria cada arte junto.'+ (x.med.larg<=57.5 ? ' Ela cabe no DTF têxtil de 57 cm — troque de produto ali em cima.' - : ' Remonte a folha em '+n1(L)+' cm e suba de novo.')+'':'')+ - '

    '; + : ' Remonte a folha em '+n1(L)+' cm e suba de novo.')+'

    ':''); }else if(x.measurementError){ - medida='
    Este PDF não pode ser orçado'+ - escapeHTML(x.measurementError)+'
    '; + medida=''+escapeHTML(extDe(x.f.name))+' · '+fmt(x.f.size)+''+ + '

    Este PDF não pode ser orçado. '+escapeHTML(x.measurementError)+'

    '; }else{ const teto=TABELA[modo], piso=pisoEscada(); const dif=(x.m>0)? (teto-piso)*cobrar(x.m*(x.rep||1)) : 0; - medida='
    '+ - ''+escapeHTML(extDe(x.f.name))+' não abre no navegador'+ - 'Sem conseguir conferir o arquivo, não temos como dar nota — e sem nota '+ - 'o metro sai pela tabela, '+rs(teto)+'. Alguém vai abrir esse arquivo na mão '+ - 'antes de imprimir.'+ - '
    Exportando a mesma folha em PNG ou PDF, a conferência é '+ - 'automática e o metro pode cair até '+rs(piso)+''+ - (dif>0.5? ' — '+rs(dif)+' a menos só nesta folha' : '')+'.
    '+ - 'Informe o comprimento para seguir:'+ - ''+ - '
    '; + medida='Conferência manual · preço cheio'+ + '

    O navegador não abre '+escapeHTML(extDe(x.f.name))+', então alguém da equipe '+ + 'confere antes de imprimir e o metro sai pela tabela, '+rs(teto)+'. '+ + 'Exportando em PNG ou PDF, o metro pode cair até '+rs(piso)+''+ + (dif>0.5? ' — '+rs(dif)+' a menos só nesta folha' : '')+'.

    '; + manual='
    '+ + 'm
    '; } const barra = x.pct!=null ? '
    '+ @@ -433,36 +455,41 @@ function pintaFolha(){ '. Seguimos com o preço de tabela — se quiser a nota e o desconto, exporte a mesma '+ 'folha em PNG, que a conferência é bem mais leve.
    ' : ''; - return '
    '+ - (folhas.length>1? (i+1)+'. ':'')+escapeHTML(x.f.name)+''+ - ''+fmt(x.f.size)+''+ - '
    '+ - barra+medida+ - (x.m>0 ? - '
    '+ - '
    '+ - '
    '+ - '
    '+fmtM(sub)+' m'+ - (x.rep>1? ' · '+x.rep+' × '+fmtM(x.m)+' m':'')+'
    '+ - '
    ' : '')+ + // A small thumbnail made once: the list is rebuilt on every change, and the + // full preview of a file up to 150 MB would be re-parsed each time. + const mini = x.miniSrc + ? '' + : ''+escapeHTML(extDe(x.f.name))+''; + const copias = x.m>0 || manual ? + '
    '+manual+ + (x.m>0 ? + '
    '+ + ''+ + ''+ + '
    '+ + '
    '+(x.rep>1? x.rep+' × '+fmtM(x.m)+' m = ' : '')+''+fmtM(sub)+' m
    ' : '')+ + '
    ' : ''; + return '
    '+ + '
    '+mini+'
    '+ + '
    '+(folhas.length>1? (i+1)+'. ':'')+escapeHTML(x.f.name)+''+ + '
    '+ + (lido || x.measurementError ? '' : ''+escapeHTML(extDe(x.f.name))+' · '+fmt(x.f.size)+'')+ + barra+medida+ + '
    '+copias+ '
    '; }).join(''); - // total do pedido, quando há mais de uma folha - const tot=folhaTotalM(), partes=Math.ceil(tot/20); - if(folhas.length>1 && tot>0){ - $('lista').innerHTML += '
    '+ - ''+folhas.length+' folhas neste pedido'+ - ''+fmtM(tot)+' m no total'+ - (partes>1? 'vai em '+partes+' partes de até 20 m':'')+'
    '; - }else if(partes>1 && tot>0){ - $('lista').innerHTML += '
    folha longa'+ - ''+fmtM(tot)+' mvai em '+partes+' partes de até 20 m
    '; - } - $('lista').querySelectorAll('[data-rmf]').forEach(b=>b.addEventListener('click',()=>{ folhas.splice(+b.dataset.rmf,1); pintaFolha(); })); + $('lista').querySelectorAll('[data-det]').forEach(d=>d.addEventListener('toggle',()=>{ + folhas[+d.dataset.det].detAberto=d.open; + })); + $('lista').querySelectorAll('[data-passo]').forEach(b=>b.addEventListener('click',()=>{ + const el=$('repf'+b.dataset.i); + el.value=Math.max(1,Math.min(200,(+el.value||1)+(+b.dataset.passo))); + el.dispatchEvent(new Event('change')); + })); $('lista').querySelectorAll('[data-repf]').forEach(el=>el.addEventListener('change',e=>{ folhas[+el.dataset.repf].rep=Math.max(1,Math.min(200,+e.target.value||1)); pintaFolha(); })); @@ -501,6 +528,7 @@ function pintaProgressoArte(a){ } function pintaArtes(){ invalidaItemAtual(); + $('zona').classList.toggle('compacta', artes.length>0); $('lista').innerHTML=artes.map((a,i)=>{ let barra='', dica='', calc='informe a largura para ver a qualidade'; if(a.lendo!=null){ diff --git a/web/site-upload.js b/web/site-upload.js index ec52099..77fea3b 100644 --- a/web/site-upload.js +++ b/web/site-upload.js @@ -48,21 +48,6 @@ function sel(fs){ } if(!fs.length) return; if(ehFolha()){ - const auto=fs.filter(f=>AUTO.test(f.name)).length; - const manual=fs.length-auto; - if(caminho==='auto' && manual){ - caminho='tabela'; - avisoCam('Trocamos o caminho para você. Você marcou conferência automática, '+ - 'mas '+(manual>1? manual+' arquivos vieram':'o arquivo veio')+' em formato que não '+ - 'abrimos. O metro vai pela tabela, '+rs(TABELA[modo])+'.'); - pintaCaminhos(); - }else if(caminho==='tabela' && auto){ - caminho='auto'; - avisoCam('Boa notícia. Você marcou o caminho sem conferência, mas '+ - (auto>1? 'os arquivos vieram':'o arquivo veio')+' em formato que a gente confere. '+ - 'Vamos avaliar e o metro pode cair até '+rs(pisoEscada())+'.'); - pintaCaminhos(); - } const novas=fs.map(f=>({f, med:null, rep:1, m:0, semAnalise:null})); folhas=folhas.concat(novas); // soma, não substitui pintaFolha(); @@ -87,7 +72,7 @@ function sel(fs){ if(pct-mostrado>=1){ mostrado=pct; x.pct=pct; pintaProgressoFolha(x); } }).then(cv=>{ if(cv && folhas.includes(x)){ - x.previewSrc=cv.toDataURL('image/webp',0.85); + x.previewSrc=cv.toDataURL('image/webp',0.85); x.miniSrc=miniatura(cv); try{ const an=analisarFolha(cv, md.larg); x.an={...an, dpi:md.dpiFolha, fonteDpi:'arquivo', grande:false}; @@ -96,7 +81,7 @@ function sel(fs){ }).catch(()=>{}).finally(()=>{ x.pct=null; pintaFolha(); }); }else if(md && RENDERIZA.test(x.f.name)){ carregarImagem(x.f).then(img=>{ - if(img){ x.previewSrc=img.src; try{ x.an=analisarFolha(img, md.larg); if(x.an) x.an.fonteDpi='arquivo'; } + if(img){ x.previewSrc=img.src; x.miniSrc=miniatura(img); try{ x.an=analisarFolha(img, md.larg); if(x.an) x.an.fonteDpi='arquivo'; } catch(e){} } x.pct=null; pintaFolha(); }); @@ -112,6 +97,7 @@ function sel(fs){ : ''); } if(r && r.tela){ + x.miniSrc=miniatura(r.tela); try{ x.an=analisarFolha(r.tela, md.larg); // vetor puro não tem resolução · nota máxima, e está certo diff --git a/web/site-v2.css b/web/site-v2.css index c685c4c..a3ac1c8 100644 --- a/web/site-v2.css +++ b/web/site-v2.css @@ -104,35 +104,48 @@ section+section{border-top:0} .voltar:hover{color:var(--laranja-escuro)} .focoGrid{grid-template-columns:minmax(0,1fr);gap:20px} .cat,.cat.file{border:0;background:transparent;box-shadow:none;overflow:visible} -.cabfoco,.cat.file .cabfoco{padding:0 0 20px!important;background:transparent;border:0;display:grid; - grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"t e" "s e" "p e";column-gap:24px;align-items:end} -.cabfoco>div:first-child{grid-area:t;display:flex;flex-direction:column-reverse;gap:4px} -.cabfoco .lg{font-size:12px;color:#707070;letter-spacing:.05em} -.cabfoco h3{font-size:32px;font-weight:800;letter-spacing:-.02em;line-height:1.1} -.cabfoco p{grid-area:s;margin-top:6px;font-size:15px;color:var(--texto2)} -.cabfoco .pr2{grid-area:p;margin-top:4px;font-size:14px;font-weight:600;color:var(--fraco);white-space:normal} -.tipoEnvio{grid-area:e;margin:0} -.tipoEnvio:not([hidden]){display:inline-flex;gap:4px;padding:4px;border-radius:10px;background:#EFEFEF} -.tipoEnvio .cam,.tipoEnvio .cam.on{border:0;box-shadow:none;background:transparent;padding:0 14px;min-height:40px;border-radius:8px;align-items:center} -.tipoEnvio .cam.on{background:#fff;box-shadow:0 1px 2px rgba(3,6,11,.14)} -.tipoEnvio .cam .mk2,.tipoEnvio .cam span,.tipoEnvio .cam em{display:none} -.tipoEnvio .cam b{margin:0;font-size:13.5px;font-weight:600;white-space:nowrap} -.tipoEnvio .cam.on b{font-weight:800} +.cabfoco,.cat.file .cabfoco{padding:0 0 24px!important;background:transparent;border:0;display:flex;flex-direction:column;gap:20px} +.cabfoco>div:first-child{display:flex;flex-direction:column-reverse;gap:4px} +.cabfoco .lg{font-size:12.5px;font-weight:800;color:var(--laranja-escuro);letter-spacing:.06em;text-transform:uppercase} +.cabfoco h3{font-size:36px;font-weight:800;letter-spacing:-.02em;line-height:1.1} +.tipoEnvio{margin:0} +.tipoEnvio:not([hidden]){display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;max-width:calc(100% - 452px)} +.tipoEnvio .cam,.tipoEnvio .cam.on{padding:14px 16px;min-height:0;border-radius:12px;border:1px solid var(--linha);background:#F9F9F9;box-shadow:none;align-items:flex-start} +.tipoEnvio .cam.on{padding:13px 15px;border:2px solid var(--preto);background:#fff} +.tipoEnvio .cam .mk2{display:none} +.tipoEnvio .cam div{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:12px;row-gap:4px;align-items:baseline} +.tipoEnvio .cam b{margin:0;font-size:15px;font-weight:700;color:var(--texto2)} +.tipoEnvio .cam.on b{color:var(--preto);font-weight:800} +.tipoEnvio .cam em{margin:0;font-size:13px;font-weight:500;color:var(--fraco);white-space:nowrap} +.tipoEnvio .cam.on em{font-weight:600;color:var(--preto)} +.tipoEnvio .cam div>span{grid-column:1/-1;font-size:13px;color:var(--fraco);line-height:1.4} +.tipoEnvio .cam.on div>span{color:var(--texto2)} .tipoEnvio .cam:disabled{cursor:default} -.tipoEnvio .cam:disabled:not(.on){opacity:.5} +.tipoEnvio .cam:disabled:not(.on){opacity:.55} +@media(max-width:1100px){.tipoEnvio:not([hidden]){max-width:none}} .cat .in{padding:0!important} .foco2{grid-template-columns:minmax(0,1fr) 420px;gap:32px} .fila{display:flex;flex-direction:column;gap:12px} .fila>*{margin:0} .cam{border-radius:var(--raio2)} .cam.on{border-color:var(--laranja);background:var(--aviso-fundo)} -#larguraFolhaPronta{display:inline} +#larguraFolhaPronta{display:inline;font-size:inherit;color:inherit} .zona{display:grid;grid-template-columns:44px minmax(0,1fr);column-gap:16px;row-gap:2px;align-items:center;text-align:left;padding:16px 20px;margin:0;border:2px dashed #F2B25A;background:var(--aviso-fundo);border-radius:var(--raio)} .zona .ico{grid-row:1/4;display:flex;align-items:center;justify-content:center;width:44px;height:44px;line-height:1;margin:0;border-radius:10px;background:var(--laranja);color:var(--preto);font-size:20px;box-shadow:none} .zona b{font-size:15px;margin:0} .zona span{max-width:none;margin:0;font-size:13px;color:var(--fraco)} .zona .bt{display:none} .zona:hover,.zona.sobre{border-color:var(--laranja2);box-shadow:none} +.zona .zManual{grid-column:1/-1;margin-top:12px;padding-top:12px;border-top:1px solid var(--aviso-linha);color:var(--texto2);line-height:1.5} +.zona .zManual[hidden]{display:none} +.zona .zManual b{display:inline;font-size:13px} +.zona .zOutra{display:none} +.zona.compacta{display:flex;justify-content:center;align-items:center;min-height:56px;padding:0 20px;border:1.5px dashed #D0D0D0;background:#fff;cursor:pointer} +.zona.compacta>*{display:none} +.zona.compacta .zOutra{display:inline;font-size:14px;color:var(--fraco)} +.zona.compacta .zOutra b{display:inline;font-size:14px;font-weight:600;color:var(--preto)} +.zona.compacta .zOutra b::before{content:"+";margin-right:8px;font-weight:700} +.zona.compacta:hover,.zona.compacta.sobre{border-color:var(--laranja2)} #lista{display:flex;flex-direction:column;gap:10px} #lista:empty{display:none} .art{margin:0;padding:14px 16px;border-radius:12px;background:#fff;border:1px solid var(--linha)} @@ -141,14 +154,69 @@ section+section{border-top:0} .art label{font-size:12px} .art input{height:42px;font-size:15px;font-weight:600;border-radius:8px} .art .cps{grid-template-columns:repeat(2,minmax(0,160px))} -.rep{margin:0;padding:14px 16px;border-radius:12px;background:#fff;border:1px solid var(--linha)} +.listaCab{display:flex;justify-content:space-between;align-items:baseline;gap:12px} +.listaCab h4{margin:0;font-size:18px;font-weight:700} +.listaCab span{font-size:13px;color:var(--fraco)} +.rep{margin:0;padding:20px;border-radius:14px;background:#fff;border:1px solid var(--linha);display:flex;flex-direction:column;gap:16px} +.repTopo{display:flex;gap:16px;align-items:flex-start} +.miniF{flex:none;width:52px;height:96px;border-radius:6px;border:1px solid #D6D6D6;background:#F4F4F2;display:flex;align-items:center;justify-content:center;overflow:hidden} +.miniF img{width:100%;height:100%;object-fit:contain;display:block} +.miniF span{font-size:11px;font-weight:800;color:var(--texto2)} +.repInfo{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px} +.rep .l1{margin:0} +.rep .l1 b{font-size:14px;font-weight:600;color:var(--preto)} +.rep .l1 button{width:32px;height:32px;margin:-6px -6px -6px 0;border-radius:8px;font-size:18px} +.rep .l1 button:hover{background:#F1F1F1;color:var(--preto)} +.repMed{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap} +.repMed b{font-family:"Inter",sans-serif;font-size:22px;font-weight:700;letter-spacing:-.01em} +.repMed span,.repPeso{font-size:13px;color:var(--fraco)} +.chips{list-style:none;margin:4px 0 0;padding:0;display:flex;flex-wrap:wrap;gap:8px} +.chip{display:inline-flex;align-items:center;gap:6px;padding:5px 10px;border-radius:999px;font-size:13px;font-weight:600;line-height:1.2} +.chip::before{font-weight:800} +.chip.ok{background:var(--verde-fundo);color:var(--verde)}.chip.ok::before{content:"✓"} +.chip.av{background:#FFF1DB;color:#8A4B00}.chip.av::before{content:"!"} +.chip.er{background:#FDE8E6;color:#B3261E}.chip.er::before{content:"×"} +.chip.fix{background:#E8F0FB;color:#1F4E8C}.chip.fix::before{content:"✓"} +.chip.nt{background:#F1F1F1;color:var(--texto2)} +.chipSo{align-self:flex-start;padding:5px 10px;border-radius:999px;background:#F1F1F1;color:var(--texto2);font-size:13px;font-weight:600} +.avisoF{margin:4px 0 0;padding:10px 12px;border-radius:10px;background:#FDE8E6;font-size:13px;line-height:1.5;color:var(--preto)} +.avisoF b{color:#B3261E} +.repTxt{margin:2px 0 0;font-size:13.5px;line-height:1.5;color:var(--texto2)} +.repTxt b{color:var(--preto)} +.confDet{font-size:13px} +.confDet summary{display:inline;cursor:pointer;list-style:none;color:var(--laranja-escuro);font-weight:500} +.confDet summary::-webkit-details-marker{display:none} +.confDet summary:hover{text-decoration:underline} +.confDet[open] summary{display:inline-block;margin-bottom:6px} +.confDet span{display:block;color:var(--texto2);line-height:1.6} +.rep .cps{display:flex;align-items:center;gap:16px 24px;flex-wrap:wrap;margin:0;padding-top:16px;border-top:1px solid #EFEFEF} +.rep .campo{display:flex;align-items:center;gap:12px} +.rep .campo label{margin:0;font-size:14px;font-weight:600;color:var(--preto)} +.passo{display:inline-flex;border:1px solid #D6D6D6;border-radius:10px;overflow:hidden} +.passo button{width:44px;height:44px;border:0;background:#F9F9F9;font-size:18px;color:var(--preto);cursor:pointer} +.passo button:hover{background:#EFEFEF} +.rep .passo input{width:56px;height:44px;padding:0;border:0;border-radius:0;text-align:center;font-size:16px;font-weight:700;-moz-appearance:textfield;appearance:textfield} +.passo input::-webkit-inner-spin-button,.passo input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0} +.rep .un{display:inline-flex;align-items:center;gap:6px;height:44px;padding:0 12px;border:1px solid #D6D6D6;border-radius:10px} +.rep .un input{width:64px;padding:0;border:0;font-size:16px;font-weight:700;text-align:right} +.rep .un i{font-style:normal;font-size:14px;color:var(--fraco)} +.rep .conta{margin-left:auto;font-size:14px;color:var(--texto2)} +.rep .conta b{font-family:"Inter",sans-serif;font-size:16px;color:var(--preto)} .calc{font-size:13px;margin-top:8px} .dica{display:flex;align-items:center;gap:12px;margin-top:10px;padding:10px 12px;border:0;border-radius:8px;background:var(--verde-fundo);font-size:13px;color:#14532D} .dica.av{background:var(--aviso-fundo);color:#5A3A00} .dica button{display:inline-flex;width:auto;margin:0 0 0 auto;flex:none;height:34px;align-items:center;padding:0 12px;border-radius:7px;border:1px solid var(--verde);background:#fff;color:var(--verde);box-shadow:none;font-size:13px} .dica button:hover{background:var(--verde);color:#fff;box-shadow:none} -.req{position:static;padding:16px 20px 6px;border-radius:12px;box-shadow:none} -.reqcab{font-size:15px;margin-bottom:6px} +.req{position:static;padding:8px 0 0;border:0;border-radius:0;background:none;box-shadow:none;display:flex;flex-wrap:wrap;align-items:baseline;gap:8px 20px} +.reqcab{margin:0;font-size:13px;font-weight:400;color:var(--fraco)} +.req details,.req details:first-of-type{border:0} +.req summary{display:inline;padding:0;font-size:13px;font-weight:500;color:var(--laranja-escuro)} +.req summary::before{display:none} +.req summary:hover{text-decoration:underline} +.req details[open]{order:1;flex-basis:100%;padding:14px 16px 4px;border-radius:12px;background:var(--cinza)} +.req details[open] summary{display:block;margin-bottom:6px;font-size:14px;font-weight:700;color:var(--preto);text-decoration:none} +.req li{font-size:13px} +.req .obs2{font-size:12px} /* The buy box */ .mont{position:sticky;top:var(--topo-passos,128px);padding:20px;border-radius:16px;background:#fff;box-shadow:none;display:flex;flex-direction:column;gap:12px} @@ -160,12 +228,36 @@ section+section{border-top:0} .compra .aoVivo.pronto{display:none} #compraVals{display:flex;flex-direction:column;gap:10px;font-size:15px} #compraVals[hidden]{display:none} -.cNota{display:flex;align-items:center;gap:12px} -.cNota span,.cLin>span:first-child{color:var(--texto2)} -.cNota>i{flex:1;height:6px;border-radius:999px;background:#EFEFEF;overflow:hidden} -.cNota>i i{display:block;height:100%;border-radius:999px;background:#C9CCD1} -.cNota>i i.ok{background:var(--verde)}.cNota>i i.av{background:var(--laranja)}.cNota>i i.er{background:var(--vermelho)} -.cNota b{font-family:"Inter",sans-serif;font-weight:800} +.cat.file .zoomB{display:none} +.ampliar{margin-left:auto;height:32px;padding:0 12px;border-radius:8px;border:1px solid #D6D6D6;background:#fff;font-size:12.5px;font-weight:600;color:var(--preto);cursor:pointer} +.ampliar:hover{border-color:var(--preto)} +.ampliar[hidden]{display:none} +.cat.file #vArea{max-height:340px} +.cEscada{display:flex;flex-direction:column;gap:8px;margin-bottom:4px} +.cEscada>span{font-size:13px;font-weight:600} +.cEscada ol{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:4px} +.cEscada li{padding:8px 2px;border-radius:8px;background:#F4F4F2;border:1.5px solid transparent;display:flex;flex-direction:column;align-items:center;gap:2px} +.cEscada li span{font-size:11px;color:var(--fraco);white-space:nowrap} +.cEscada li b{font-size:13px;font-weight:500;color:var(--texto2)} +.cEscada li.on{background:var(--verde-fundo);border-color:var(--verde)} +.cEscada li.on span,.cEscada li.on b{font-weight:700;color:var(--verde)} +.cEscada li.on:last-child{background:#F1F1F1;border-color:var(--preto)} +.cEscada li.on:last-child span,.cEscada li.on:last-child b{color:var(--preto)} +.cLin>span:first-child{color:var(--texto2)} +.cLin small{font-size:12px;color:var(--fraco)} +.cEco{margin:-6px 0 0;text-align:right;font-size:13px;font-weight:600;color:var(--verde)} +.cEco:empty{display:none} +#cPartes{display:block} +.ampliaDlg{width:min(960px,calc(100vw - 32px));max-height:calc(100vh - 48px);padding:0;border:0;border-radius:16px;box-shadow:0 20px 60px rgba(3,6,11,.3)} +.ampliaDlg::backdrop{background:rgba(3,6,11,.55)} +.ampliaCab{position:sticky;top:0;z-index:1;display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--linha);background:#fff} +.ampliaCab b{font-size:16px;font-weight:800} +.ampliaCab button{width:40px;height:40px;border:0;border-radius:8px;background:#F1F1F1;font-size:20px;cursor:pointer} +#ampliaArea .folhaPrevias{display:grid;gap:16px;padding:16px;background:#F8F9FA} +#ampliaArea .folhaPrevia{margin:0;background:#fff;border:1px solid var(--linha);border-radius:8px;overflow:hidden} +#ampliaArea .folhaPilha{display:flex;flex-direction:column;align-items:center;gap:4px} +#ampliaArea .folhaPilha img{display:block;width:auto;max-width:100%;height:auto;max-height:calc(100vh - 180px)!important} +#ampliaArea figcaption{padding:8px 12px;font-size:13px;color:var(--texto2);border-top:1px solid var(--linha)} .cLin{display:flex;align-items:baseline;gap:8px} .cLin>span:last-child,.cLin>b{margin-left:auto;display:flex;gap:8px;align-items:baseline} .cLin s{font-size:13px;color:#707070} @@ -184,8 +276,14 @@ section+section{border-top:0} .cPe{margin:0;font-size:13px;color:var(--fraco);text-align:center} @media(max-width:1100px){.foco2{grid-template-columns:1fr}.mont{position:static}} @media(max-width:620px){.montcab b{font-size:15px} - .cabfoco,.cat.file .cabfoco{grid-template-columns:1fr;grid-template-areas:"t" "s" "p" "e"} - .tipoEnvio:not([hidden]){display:grid;grid-template-columns:1fr 1fr;margin-top:14px}} + .cabfoco h3{font-size:28px} + .tipoEnvio .cam div{grid-template-columns:1fr} + .tipoEnvio .cam div>span{display:none} + .rep{padding:16px} + .repTopo{gap:12px} + .miniF{width:40px;height:80px} + .repMed b{font-size:20px} + .rep .conta{margin-left:0}} /* The quality, preview, cart and checkout panels sit directly in #envio, outside .w; they share the page column so nothing runs edge to edge. */ @@ -231,6 +329,8 @@ html:is([data-rota="pagamento"],[data-rota="pix"]) .checkout{max-width:1040px;ma html:is([data-rota="pagamento"],[data-rota="pix"]) .pagGrid{display:grid;grid-template-columns:minmax(0,1fr) 340px;gap:32px;align-items:start} .envioArq{font-size:13px;color:var(--texto2);margin-top:14px;line-height:1.5} .envioArq.ok{color:var(--verde)} +.envioArq.erro{color:#B42318} +.envioDeNovo{margin-left:4px;padding:0;border:0;background:none;color:inherit;font:inherit;font-weight:700;text-decoration:underline;cursor:pointer} .envioBarra{height:6px;border-radius:999px;background:#EDEDED;overflow:hidden;margin-bottom:6px} .envioBarra i{display:block;height:100%;background:var(--laranja);border-radius:999px;transition:width .4s} .cartEnvio{font-size:13px;font-weight:700;color:var(--laranja-escuro);margin-left:6px}