2890 lines
149 KiB
HTML
2890 lines
149 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="pt-BR">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>DTF Dropstar · mande sua arte e veja a qualidade</title>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
|
||
<style>
|
||
:root{
|
||
/* tokens do site institucional */
|
||
--font-family-base:"Roboto",sans-serif; --font-family-title:"Inter",sans-serif;
|
||
--font-color-base:#03060b; --font-color-title:#03060b;
|
||
--font-weight-base:400; --font-weight-title:700; --font-weight-subtitle:600; --font-weight-button:600;
|
||
--font-size-title:3rem; --font-size-subtitle:2rem; --font-size-button:1.4rem;
|
||
--font-size-small:1.2rem; --font-size-base:1.4rem; --font-size-medium:1.6rem; --font-size-big:1.8rem;
|
||
--line-height:1.5;
|
||
--white:#fff; --black:#03060b;
|
||
--gray-1:#f9f9f9; --gray-2:#c3c3c3; --gray-3:#707070; --gray-4:#363636;
|
||
--primary-color:#ffa81a; --secondary-color:#ff7f0a;
|
||
--white-transparency:#ffffffb3; --transition:all .4s ease;
|
||
/* apelidos usados nesta pagina, mapeados nos tokens acima */
|
||
--marinho:var(--black); --papel:var(--white); --cinza:var(--gray-1);
|
||
--tx:var(--font-color-base); --fraco:var(--gray-3); --linha:#e6e6e6;
|
||
--laranja:var(--primary-color); --laranja2:var(--secondary-color);
|
||
--vermelho:#D94A28; --verde:#2E9E5B; --verde-ml:#00A650; --verde-claro:#57D68A;
|
||
--sombra:0 1px 2px rgba(3,6,11,.05), 0 4px 14px rgba(3,6,11,.05);
|
||
--sombra-alta:0 2px 6px rgba(3,6,11,.07), 0 10px 30px rgba(3,6,11,.11)}
|
||
*{box-sizing:border-box;margin:0;padding:0}
|
||
html{scroll-behavior:smooth;font-size:62.5%}
|
||
body{background:var(--white);color:var(--font-color-base);font-family:var(--font-family-base);
|
||
font-size:var(--font-size-base);font-weight:var(--font-weight-base);line-height:var(--line-height);
|
||
-webkit-font-smoothing:antialiased}
|
||
h1,h2,h3{font-family:var(--font-family-title);color:var(--font-color-title);
|
||
font-weight:var(--font-weight-title);letter-spacing:normal;line-height:1.15}
|
||
.w{max-width:1020px;margin:0 auto;padding:0 22px}
|
||
section{padding:clamp(34px,5vw,56px) 0}
|
||
section+section{border-top:1px solid var(--linha)}
|
||
.prova+section{border-top:0}
|
||
|
||
/* tarja rotativa, como no site */
|
||
.tarja{background:var(--laranja);color:#111;text-align:center;padding:8px 16px;
|
||
font-family:"Inter",sans-serif;font-weight:700;font-size:12px;letter-spacing:.02em}
|
||
.tarja a{color:#111;text-decoration:none}
|
||
|
||
/* topo */
|
||
.topo{background:#fff;border-bottom:1px solid var(--linha);position:sticky;top:0;z-index:60}
|
||
.topo .w{display:flex;align-items:center;gap:22px;padding-top:15px;padding-bottom:15px}
|
||
.logo{display:flex;align-items:center;text-decoration:none;white-space:nowrap;flex:none}
|
||
.logo img{height:26px;width:auto;display:block}
|
||
.logotexto{font-family:"Inter",sans-serif;font-weight:700;font-size:19px;color:var(--black);
|
||
letter-spacing:-.03em}
|
||
.logotexto i{font-style:normal;color:var(--laranja)}
|
||
.busca{flex:1;max-width:420px;position:relative}
|
||
.busca input{width:100%;padding:9px 14px 9px 36px;border:1px solid var(--linha);border-radius:22px;
|
||
font-family:inherit;font-size:13px;background:var(--cinza);color:var(--tx)}
|
||
.busca input:focus{outline:none;border-color:var(--laranja);background:#fff}
|
||
.busca .lupa{position:absolute;left:13px;top:50%;transform:translateY(-50%);color:var(--fraco);font-size:13px}
|
||
.acts{margin-left:auto;display:flex;gap:18px;align-items:center;font-size:12.5px}
|
||
.acts a{color:var(--tx);text-decoration:none;display:flex;align-items:center;gap:6px}
|
||
.acts a:hover{color:var(--laranja)}
|
||
|
||
/* menu */
|
||
.menu{background:#fff;border-bottom:1px solid var(--linha)}
|
||
.menu .w{display:flex;gap:0;flex-wrap:wrap}
|
||
.mi{position:relative}
|
||
.mi>a{display:block;padding:13px 16px;font-family:"Inter",sans-serif;font-weight:600;
|
||
font-size:12.5px;color:var(--tx);text-decoration:none;white-space:nowrap}
|
||
.mi:hover>a{color:var(--laranja)}
|
||
.mi.on>a{color:var(--laranja);box-shadow:inset 0 -2px 0 var(--laranja)}
|
||
.sub{display:none;position:absolute;top:100%;left:0;background:#fff;border:1px solid var(--linha);
|
||
border-radius:0 0 9px 9px;min-width:224px;padding:7px 0;z-index:70;
|
||
box-shadow:0 10px 26px rgba(0,0,0,.09)}
|
||
.mi:hover .sub,.mi:focus-within .sub{display:block}
|
||
.sub a{display:block;padding:8px 17px;font-size:12.5px;color:var(--fraco);text-decoration:none}
|
||
.sub a:hover{color:var(--laranja);background:var(--cinza)}
|
||
@media(max-width:820px){
|
||
.menu .w{overflow-x:auto;flex-wrap:nowrap}
|
||
.sub{display:none!important}
|
||
.busca{display:none}
|
||
}
|
||
|
||
.hero{background:#000;color:#fff;position:relative;overflow:hidden}
|
||
.hero .fundo{position:absolute;inset:0;pointer-events:none}
|
||
.hero .fundo svg{width:100%;height:100%;display:block;opacity:.22}
|
||
/* escurece do lado do texto, para o título não competir com o fundo */
|
||
.hero .fundo::after{content:"";position:absolute;inset:0;
|
||
background:linear-gradient(100deg,#000 0%,#000 32%,rgba(0,0,0,.85) 52%,rgba(0,0,0,.55) 100%)}
|
||
.hero .w{position:relative;z-index:2}
|
||
.hgrid{display:grid;grid-template-columns:1.15fr auto;gap:38px;align-items:center;
|
||
padding:clamp(26px,3.6vw,40px) 0}
|
||
@media(max-width:940px){.hgrid{grid-template-columns:1fr;gap:22px}}
|
||
h1{font-size:clamp(24px,3.6vw,38px);font-weight:700;max-width:20ch;line-height:1.08}
|
||
h1 em{font-style:normal;color:var(--laranja)}
|
||
.hero .sub2{color:#B7C1D2;font-size:14px;max-width:56ch;margin-top:10px}
|
||
.hero .sub2 b{color:#fff}
|
||
.hcta{display:flex;gap:12px;margin-top:16px;flex-wrap:wrap;align-items:center}
|
||
.btn1{background:var(--laranja);color:#241703;border:0;border-radius:9px;padding:12px 24px;
|
||
font-family:"Inter",sans-serif;font-weight:700;font-size:14.5px;cursor:pointer;text-decoration:none}
|
||
.btn1:hover{background:var(--laranja2)}
|
||
.mini{font-size:12px;color:#8D9AB0}
|
||
|
||
/* preços lado a lado, em faixa */
|
||
.pfaixa{display:flex;gap:10px;flex-wrap:wrap}
|
||
@media(max-width:940px){.pfaixa{flex-wrap:wrap}}
|
||
.pcard{flex:1 1 44%;min-width:128px;background:rgba(255,255,255,.055);
|
||
border:1px solid rgba(255,255,255,.13);border-radius:11px;padding:13px 15px;
|
||
text-decoration:none;position:relative;transition:.15s}
|
||
.pcard:hover{background:rgba(255,168,26,.12);border-color:rgba(255,168,26,.45)}
|
||
.pcard.dest{border-color:rgba(255,168,26,.5);background:rgba(255,168,26,.09)}
|
||
.pcard .marc{position:absolute;top:-8px;left:13px;background:var(--verde);color:#fff;
|
||
font-family:"Inter",sans-serif;font-size:8.5px;font-weight:700;letter-spacing:.09em;
|
||
text-transform:uppercase;padding:2px 8px;border-radius:4px;white-space:nowrap}
|
||
.pcard .apartir{display:block;font-size:9.5px;color:var(--verde-claro);letter-spacing:.09em;
|
||
text-transform:uppercase;font-family:"Inter",sans-serif;font-weight:700;margin-bottom:2px}
|
||
.pcard .vl{font-family:"Inter",sans-serif;font-size:20px;font-weight:700;color:var(--laranja);
|
||
line-height:1;display:block;margin-bottom:3px}
|
||
.pcard .vl small{font-size:11px;font-weight:600;color:#8D9AB0}
|
||
.pcard .nm{font-family:"Inter",sans-serif;font-size:12.5px;font-weight:700;color:#fff;display:block}
|
||
.pcard .dsc{font-size:10.5px;color:#8D9AB0;display:block;margin-top:1px}
|
||
|
||
/* selos e barra */
|
||
.selos1{display:flex;gap:7px;flex-wrap:wrap;align-items:center;margin-bottom:11px}
|
||
.sel{font-family:"Inter",sans-serif;font-size:9.5px;font-weight:700;letter-spacing:.09em;
|
||
text-transform:uppercase;padding:3px 9px;border-radius:5px}
|
||
.sel.top{background:var(--laranja);color:#241703}
|
||
.sel.novo{background:rgba(46,158,91,.18);color:#7FD4A0;border:1px solid rgba(46,158,91,.4)}
|
||
.sel.pos{background:rgba(255,255,255,.09);color:#B7C1D2;border:1px solid rgba(255,255,255,.16)}
|
||
.barrah{border-top:1px solid rgba(255,255,255,.1);padding:11px 0 14px;
|
||
display:flex;gap:24px;flex-wrap:wrap;font-size:12px;color:#B7C1D2}
|
||
.barrah span{display:flex;align-items:center;gap:7px}
|
||
.barrah b{color:#fff;font-family:"Inter",sans-serif}
|
||
.barrah i{color:var(--laranja);font-style:normal;font-size:9px}
|
||
|
||
|
||
/* aviso do topo do envio */
|
||
|
||
/* escolha em 3 cards */
|
||
.escolha{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-top:24px;
|
||
align-items:stretch}
|
||
.escolha .ec{display:flex;flex-direction:column}
|
||
.escolha .ec .in{flex:1}
|
||
@media(max-width:1000px){.escolha{grid-template-columns:repeat(2,1fr)}}
|
||
@media(max-width:600px){.escolha{grid-template-columns:1fr}}
|
||
.ec{border:1px solid var(--linha);border-radius:14px;background:#fff;padding:0;
|
||
cursor:pointer;text-align:left;font-family:inherit;overflow:hidden;
|
||
box-shadow:var(--sombra);transition:var(--transition);
|
||
display:block;width:100%;position:relative}
|
||
/* marca d'agua dos cards · mesma da foto de produto: curva de nivel + sacola Dropstar
|
||
(a sacola e uma reconstrucao; trocar pelo arquivo oficial do designer) */
|
||
.ec::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:0;
|
||
background-repeat:no-repeat;background-position:right -60px center;background-size:auto 150%;
|
||
background-image:url("data:image/svg+xml;utf8,\
|
||
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 300'>\
|
||
<g fill='none' stroke='%23000000' stroke-opacity='.055' stroke-width='1.6'>\
|
||
<path d='M200 46c66 0 138 40 138 104s-72 104-138 104S62 214 62 150 134 46 200 46z'/>\
|
||
<path d='M200 46c66 0 138 40 138 104s-72 104-138 104S62 214 62 150 134 46 200 46z' transform='translate(200 150) scale(.86) translate(-200 -150)'/>\
|
||
<path d='M200 46c66 0 138 40 138 104s-72 104-138 104S62 214 62 150 134 46 200 46z' transform='translate(200 150) scale(.72) translate(-200 -150)'/>\
|
||
<path d='M200 46c66 0 138 40 138 104s-72 104-138 104S62 214 62 150 134 46 200 46z' transform='translate(200 150) scale(.58) translate(-200 -150)'/>\
|
||
<path d='M200 46c66 0 138 40 138 104s-72 104-138 104S62 214 62 150 134 46 200 46z' transform='translate(200 150) scale(.44) translate(-200 -150)'/>\
|
||
<path d='M200 46c66 0 138 40 138 104s-72 104-138 104S62 214 62 150 134 46 200 46z' transform='translate(200 150) scale(.30) translate(-200 -150)'/>\
|
||
<path d='M200 46c66 0 138 40 138 104s-72 104-138 104S62 214 62 150 134 46 200 46z' transform='translate(200 150) scale(1.16) translate(-200 -150)'/>\
|
||
<path d='M200 46c66 0 138 40 138 104s-72 104-138 104S62 214 62 150 134 46 200 46z' transform='translate(200 150) scale(1.34) translate(-200 -150)'/>\
|
||
</g></svg>")}
|
||
.ec::after{content:"";position:absolute;right:16px;bottom:14px;width:104px;height:26px;
|
||
opacity:.16;pointer-events:none;z-index:0;background-repeat:no-repeat;
|
||
background-position:right bottom;background-size:contain;
|
||
background-image:url("https://cdn.vnda.com.br/dropstar/2025/12/17/logo-header-15125700-16129080.png?v=1766009286")}
|
||
.ec .top,.ec .in{position:relative;z-index:1}
|
||
.ec:hover{border-color:var(--laranja);box-shadow:var(--sombra-alta);transform:translateY(-2px)}
|
||
.ec .marc{display:block;background:var(--verde-ml);color:#fff;text-align:center;
|
||
font-family:"Inter",sans-serif;font-size:9px;font-weight:700;letter-spacing:.14em;
|
||
text-transform:uppercase;padding:5px 8px;position:relative;z-index:2}
|
||
.ec.f{border-color:var(--verde-ml)}
|
||
.ec.f:hover{border-color:var(--verde-ml)}
|
||
/* anéis verdes por trás do card destacado, mesma família dos selos */
|
||
.ec.f::before{background-image:url("data:image/svg+xml;utf8,\
|
||
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 300'>\
|
||
<g fill='none' stroke='%2300A650' stroke-opacity='.10' stroke-width='1.6'>\
|
||
<path d='M200 46c66 0 138 40 138 104s-72 104-138 104S62 214 62 150 134 46 200 46z'/>\
|
||
<path d='M200 46c66 0 138 40 138 104s-72 104-138 104S62 214 62 150 134 46 200 46z' transform='translate(200 150) scale(.82) translate(-200 -150)'/>\
|
||
<path d='M200 46c66 0 138 40 138 104s-72 104-138 104S62 214 62 150 134 46 200 46z' transform='translate(200 150) scale(.64) translate(-200 -150)'/>\
|
||
<path d='M200 46c66 0 138 40 138 104s-72 104-138 104S62 214 62 150 134 46 200 46z' transform='translate(200 150) scale(.46) translate(-200 -150)'/>\
|
||
<path d='M200 46c66 0 138 40 138 104s-72 104-138 104S62 214 62 150 134 46 200 46z' transform='translate(200 150) scale(.28) translate(-200 -150)'/>\
|
||
<path d='M200 46c66 0 138 40 138 104s-72 104-138 104S62 214 62 150 134 46 200 46z' transform='translate(200 150) scale(1.2) translate(-200 -150)'/>\
|
||
</g></svg>")}
|
||
.ec .top{padding:17px 20px;display:flex;justify-content:space-between;align-items:flex-start;gap:10px}
|
||
.ec.f .top{background:#FFF4E3} .ec.a .top{background:var(--cinza)} .ec.u .top{background:#EEF4FB}
|
||
.ec .top h3{font-family:"Inter",sans-serif;font-size:17px;font-weight:700;color:var(--tx)}
|
||
|
||
|
||
.ec .top .p{font-family:"Inter",sans-serif;font-weight:700;font-size:15px;white-space:nowrap;
|
||
color:var(--tx);text-align:right;line-height:1.15}
|
||
.ec .top .p i{display:block;font-style:normal;font-family:"Roboto",sans-serif;font-size:10px;
|
||
font-weight:500;color:var(--fraco);margin-bottom:1px;letter-spacing:0;
|
||
text-transform:uppercase;letter-spacing:.1em}
|
||
.chama2{background:#F1FBF5;border-top:1px solid #BFE6CE;border-bottom:1px solid #BFE6CE;
|
||
padding:9px 20px;font-size:11.5px;color:#1F5C3A;line-height:1.45;position:relative;z-index:1}
|
||
.chama2 b{font-family:"Inter",sans-serif;font-weight:700;color:var(--verde-ml);font-size:12.5px}
|
||
.ec .top .p small{font-size:11px;font-weight:600;color:var(--fraco)}
|
||
.ec .in{padding:18px 20px 20px}
|
||
.ec .in p{font-size:13px;color:var(--fraco);margin-bottom:13px}
|
||
.ec ul{list-style:none;font-size:12.5px;margin-bottom:15px}
|
||
.ec li{padding:4px 0 4px 19px;position:relative;color:var(--fraco)}
|
||
.ec li::before{content:"✓";position:absolute;left:2px;color:var(--verde);font-size:11px}
|
||
.ec .go{font-family:"Inter",sans-serif;font-weight:700;font-size:13.5px;color:var(--laranja);display:block}
|
||
.ec .lg{display:block;font-size:10.5px;color:var(--fraco);letter-spacing:.1em;
|
||
text-transform:uppercase;font-family:"Inter",sans-serif;font-weight:700;margin-bottom:5px}
|
||
|
||
/* painel focado */
|
||
.foco{display:none}
|
||
.foco.on{display:block}
|
||
.focoGrid{display:grid;grid-template-columns:minmax(0,1fr) 264px;gap:16px;align-items:start}
|
||
.focoGrid>*{min-width:0}
|
||
@media(max-width:820px){.focoGrid{grid-template-columns:1fr}}
|
||
.voltar{display:inline-flex;align-items:center;gap:7px;background:#fff;
|
||
border:1px solid var(--linha);border-radius:8px;padding:8px 14px 8px 11px;
|
||
font-family:"Inter",sans-serif;font-weight:600;font-size:12.5px;color:var(--tx);
|
||
cursor:pointer;margin-bottom:14px;box-shadow:var(--sombra);transition:var(--transition)}
|
||
.voltar span{font-size:15px;line-height:1;color:var(--fraco)}
|
||
.voltar:hover{border-color:var(--laranja);color:var(--laranja)}
|
||
.voltar:hover span{color:var(--laranja)}
|
||
.cat{border:1px solid var(--linha);border-radius:14px;background:#fff;overflow:hidden;
|
||
box-shadow:var(--sombra)}
|
||
.cat.file{border-color:var(--laranja);border-width:2px}
|
||
.cabfoco{display:flex;justify-content:space-between;align-items:baseline;gap:14px;
|
||
flex-wrap:wrap;border-bottom:1px solid var(--linha);background:var(--cinza);padding:18px 22px}
|
||
.cat.file .cabfoco{background:#FFF4E3}
|
||
.cabfoco h3{font-family:"Inter",sans-serif;font-size:20px;font-weight:700}
|
||
.cabfoco .pr2{font-family:"Inter",sans-serif;font-weight:700;font-size:17px;white-space:nowrap}
|
||
.cabfoco p{font-size:12.5px;color:var(--fraco);width:100%;margin-top:4px}
|
||
.cabfoco .lg{font-size:10.5px;color:var(--fraco);letter-spacing:.1em;text-transform:uppercase;
|
||
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}
|
||
.cam{display:flex;gap:9px;align-items:flex-start;text-align:left;background:#fff;
|
||
border:1px solid var(--linha);border-radius:10px;padding:11px 12px;cursor:pointer;
|
||
font-family:inherit;color:var(--tx);transition:var(--transition);
|
||
min-width:0;overflow:hidden}
|
||
.cam:hover{border-color:var(--gray-3)}
|
||
.cam.on{border-color:var(--verde-ml);background:#F4FCF7;box-shadow:0 0 0 1px var(--verde-ml)}
|
||
.cam .mk2{flex:none;width:15px;height:15px;border-radius:50%;margin-top:2px;
|
||
border:2px solid var(--gray-2);background:#fff}
|
||
.cam.on .mk2{border-color:var(--verde-ml);
|
||
background:radial-gradient(circle,var(--verde-ml) 0 3px,#fff 4px)}
|
||
.cam div{flex:1;min-width:0;overflow-wrap:anywhere}
|
||
.cam b{display:block;font-family:"Inter",sans-serif;font-size:12.5px;margin-bottom:2px}
|
||
.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}
|
||
.trocarModo{margin:-4px 0 11px;padding:10px 12px;border-radius:9px;background:#F1FBF5;
|
||
border:1px solid #BFE6CE;font-size:11.5px;color:#1F5C3A;line-height:1.5}
|
||
.trocarModo b{font-family:"Inter",sans-serif;font-weight:700}
|
||
.trocarModo label{display:block;margin-top:7px;cursor:pointer}
|
||
.zona{border:2px dashed var(--laranja);border-radius:13px;padding:44px 20px;text-align:center;
|
||
cursor:pointer;margin-bottom:14px;background:#FFF6E8;transition:var(--transition)}
|
||
.zona:hover,.zona.sobre{border-color:var(--laranja2);background:#FFEFD6;
|
||
box-shadow:0 6px 22px rgba(255,168,26,.22)}
|
||
.zona .ico{width:46px;height:46px;margin:0 auto 12px;border-radius:50%;
|
||
background:var(--laranja);color:#fff;font-size:22px;line-height:46px;font-weight:700;
|
||
box-shadow:0 0 0 7px rgba(255,168,26,.18)}
|
||
.zona:hover .ico,.zona.sobre .ico{background:var(--laranja2)}
|
||
.zona b{display:block;font-family:"Inter",sans-serif;font-size:18px;font-weight:700;
|
||
margin-bottom:5px;color:var(--tx);line-height:1.2}
|
||
.zona span{font-size:12px;color:#8A6A2E;display:block;max-width:30ch;margin:0 auto;line-height:1.5}
|
||
.zona .bt{display:inline-block;margin-top:13px;background:var(--laranja);color:#241703;
|
||
font-family:"Inter",sans-serif;font-weight:700;font-size:13px;border-radius:8px;
|
||
padding:9px 18px}
|
||
.zona:hover .bt{background:var(--laranja2)}
|
||
.recusa{margin-top:11px;padding:11px 13px;border-radius:9px;background:#FFF3F0;
|
||
border:1px solid #F0C4B8;font-size:11.5px;color:#8C3B22;line-height:1.5}
|
||
.recusa b{font-family:"Inter",sans-serif;font-weight:700;color:#8C3B22}
|
||
.aoVivo{margin-top:11px;padding:11px 13px;border-radius:9px;background:var(--cinza);
|
||
border:1px solid var(--linha);font-size:12px;color:var(--fraco);line-height:1.45;
|
||
display:flex;align-items:center;gap:9px}
|
||
.aoVivo b{font-family:"Inter",sans-serif;font-weight:700;color:var(--tx);font-size:12.5px}
|
||
.aoVivo .pt2{flex:none;width:8px;height:8px;border-radius:50%;background:var(--gray-2)}
|
||
.aoVivo.pronto{background:#F1FBF5;border-color:#BFE6CE;color:#2A6B45}
|
||
.aoVivo.pronto .pt2{background:var(--verde-ml)}
|
||
.aoVivo.pronto b{color:#1F5C3A}
|
||
.b2{width:100%;padding:13px;border-radius:9px;border:1px solid var(--marinho);background:#fff;
|
||
color:var(--tx);font-family:"Inter",sans-serif;font-weight:600;font-size:14.5px;cursor:pointer}
|
||
.cat.file .b2{background:var(--laranja);border-color:var(--laranja);color:#241703}
|
||
.b2:hover{background:#111;color:#fff}
|
||
.cat.file .b2:hover{background:var(--laranja2);color:#241703}
|
||
.it{display:flex;justify-content:space-between;gap:9px;padding:10px 13px;background:var(--cinza);
|
||
border-radius:8px;margin-bottom:7px;align-items:center;font-size:12.5px}
|
||
.it b{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||
.it span{color:var(--fraco);font-size:11px;flex:none}
|
||
.it button{border:0;background:none;color:var(--fraco);cursor:pointer;font-size:15px}
|
||
|
||
/* 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}
|
||
.prog{height:5px;border-radius:4px;background:#E4E7EC;overflow:hidden;margin:9px 0 5px}
|
||
.prog i{display:block;height:100%;background:var(--laranja);border-radius:4px;
|
||
transition:width .35s ease}
|
||
.progT{display:block;font-size:10.5px;color:var(--fraco)}
|
||
.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;
|
||
align-items:start;margin-top:2px}
|
||
.foco2>*{min-width:0}
|
||
.foco2.sofila{grid-template-columns:1fr}
|
||
.foco2.sofila .mont{display:none}
|
||
@media(max-width:1360px){.foco2{grid-template-columns:1fr}}
|
||
.mont{position:sticky;top:104px;border:1px solid var(--linha);border-radius:11px;
|
||
background:var(--cinza);padding:12px;box-shadow:var(--sombra)}
|
||
.montcab{display:flex;justify-content:space-between;align-items:baseline;gap:10px;margin-bottom:9px}
|
||
.montcab b{font-family:"Inter",sans-serif;font-size:12.5px;font-weight:700}
|
||
.zoomB{display:flex;align-items:center;gap:4px;margin-left:auto}
|
||
.zoomB button{width:22px;height:22px;border-radius:6px;border:1px solid var(--linha);
|
||
background:#fff;color:var(--tx);cursor:pointer;font-size:14px;line-height:1;padding:0}
|
||
.zoomB button:hover{border-color:var(--laranja);color:var(--laranja)}
|
||
.zoomB button:disabled{opacity:.35;cursor:not-allowed}
|
||
.zoomB span{font-family:"Inter",sans-serif;font-size:10.5px;font-weight:700;
|
||
color:var(--fraco);min-width:34px;text-align:center}
|
||
#vArea.ampliado{overflow:auto}
|
||
.montcab span{font-family:"Inter",sans-serif;font-weight:700;font-size:16px;color:var(--tx)}
|
||
#vArea{max-height:min(56vh,560px);min-height:200px;overflow-y:auto;overscroll-behavior:contain;
|
||
border:1px solid var(--linha);border-radius:8px;background:#fff}
|
||
#vArea::-webkit-scrollbar{width:8px}
|
||
#vArea::-webkit-scrollbar-thumb{background:var(--gray-2);border-radius:6px;
|
||
border:2px solid #fff}
|
||
#vArea::-webkit-scrollbar-track{background:transparent}
|
||
#vArea canvas{max-width:100%;height:auto;display:block;background:#fff}
|
||
#vArea.ampliado canvas{max-width:none}
|
||
#vArea .folhaPrevias{min-height:200px;padding:10px;display:grid;gap:12px;background:#F8F9FA}
|
||
#vArea .folhaPrevia{margin:0;background:#fff;border:1px solid var(--linha);border-radius:6px;overflow:hidden}
|
||
#vArea .folhaPrevia img{width:100%;height:auto;max-height:520px;object-fit:contain;display:block;background:#fff}
|
||
#vArea .folhaPrevia figcaption{padding:7px 9px;font-size:10.5px;color:var(--fraco);border-top:1px solid var(--linha)}
|
||
#vArea .semmont{border:0;min-height:200px;display:flex;flex-direction:column;
|
||
align-items:center;justify-content:center}
|
||
#vUso:empty{display:none}
|
||
.semmont{border:1px dashed var(--linha);border-radius:8px;background:#fff;
|
||
padding:30px 14px;text-align:center}
|
||
.semmont b{display:block;font-family:"Inter",sans-serif;font-size:13px;margin-bottom:4px}
|
||
.semmont span{font-size:11.5px;color:var(--fraco);line-height:1.4;display:block}
|
||
.montpe{font-size:10.5px;color:var(--fraco);margin-top:9px;line-height:1.45}
|
||
|
||
/* caixa de requisitos · o que a máquina aceita */
|
||
.req{position:sticky;top:104px;background:#fff;border:1px solid var(--linha);
|
||
border-radius:14px;box-shadow:var(--sombra);padding:16px 16px 6px}
|
||
@media(max-width:820px){.req{position:static}}
|
||
.reqcab{font-family:"Inter",sans-serif;font-size:18px;font-weight:700;line-height:1.15;
|
||
letter-spacing:normal;color:var(--tx);margin-bottom:12px}
|
||
.req details{border-top:1px solid var(--linha)}
|
||
.req details:first-of-type{border-top:0}
|
||
.req summary{cursor:pointer;list-style:none;padding:9px 0;font-family:"Inter",sans-serif;
|
||
font-size:13px;font-weight:700;color:var(--tx);display:flex;align-items:center;gap:8px}
|
||
.req summary::-webkit-details-marker{display:none}
|
||
.req summary::before{content:"+";flex:none;width:16px;height:16px;border-radius:50%;
|
||
border:1px solid rgba(0,166,80,.45);background:#fff;color:var(--verde-ml);font-size:11px;
|
||
line-height:14px;text-align:center;font-weight:700}
|
||
.req summary:hover::before{background:#F1FBF5}
|
||
.req details[open] summary::before{content:"−";background:var(--verde-ml);
|
||
border-color:var(--verde-ml);color:#fff}
|
||
.req ul{list-style:none;padding:0 0 9px;margin:0}
|
||
.req li{position:relative;padding:4px 0 4px 17px;font-size:11.5px;color:var(--fraco);
|
||
line-height:1.5}
|
||
.req li b{color:var(--tx);font-weight:700;font-family:"Inter",sans-serif}
|
||
.req li::before{position:absolute;left:0;top:4px;font-size:11px;font-weight:700}
|
||
.req li.s::before{content:"✓";color:var(--verde-ml)}
|
||
.req li.a::before{content:"!";color:var(--laranja)}
|
||
.req li.n::before{content:"×";color:var(--vermelho)}
|
||
.req .obs2{font-size:10.5px;color:var(--fraco);padding:0 0 9px;line-height:1.45;
|
||
font-style:italic}
|
||
.mont .usoBom,.mont .usoRuim{margin-top:8px;font-size:11px;line-height:1.4}
|
||
|
||
/* artes avulsas */
|
||
.art{background:var(--cinza);border-radius:9px;padding:11px 12px;margin-bottom:7px;
|
||
transition:box-shadow .3s,background .3s}
|
||
.art.nova{background:#FFF6E8;box-shadow:inset 0 0 0 1px rgba(255,168,26,.55)}
|
||
.art.nova .l1 b::after{content:"nova";font-family:"Inter",sans-serif;font-size:9px;
|
||
font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#B07A18;
|
||
background:#FFE9C4;border-radius:3px;padding:1px 5px;margin-left:7px;vertical-align:1px}
|
||
.art .l1{display:flex;justify-content:space-between;gap:8px;align-items:center;margin-bottom:8px}
|
||
.art .l1 b{font-weight:500;font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||
.art .l1 button{border:0;background:none;color:var(--fraco);cursor:pointer;font-size:15px;flex:none}
|
||
.art .cps{display:grid;grid-template-columns:1fr 1fr;gap:8px}
|
||
.atalhos{display:flex;flex-wrap:wrap;gap:5px;align-items:center;margin-top:9px}
|
||
.atalhos .tm,.atalhos .gr{border:1px solid var(--linha);background:#fff;border-radius:6px;
|
||
padding:5px 9px;font-family:"Inter",sans-serif;font-size:11px;font-weight:600;
|
||
color:var(--tx);cursor:pointer;transition:var(--transition)}
|
||
.atalhos .tm:hover,.atalhos .gr:hover{border-color:var(--laranja);color:var(--laranja)}
|
||
.atalhos .tm.on{background:var(--verde-ml);border-color:var(--verde-ml);color:#fff}
|
||
.atalhos .gr{font-size:14px;line-height:1;padding:4px 9px}
|
||
.atalhos .gr.on{background:var(--laranja);border-color:var(--laranja);color:#241703}
|
||
.atalhos .sep{flex:1;min-width:4px}
|
||
.art label{display:block;font-size:10px;color:var(--fraco);margin-bottom:3px}
|
||
.art 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)}
|
||
.art input:focus{outline:none;border-color:var(--laranja)}
|
||
.qb2{height:7px;border-radius:5px;background:#E4E7EC;overflow:hidden;margin-top:9px}
|
||
.qb2 i{display:block;height:100%;border-radius:5px}
|
||
.qb2 i.ok{background:var(--verde)}.qb2 i.av{background:var(--laranja)}.qb2 i.er{background:var(--vermelho)}
|
||
.calc{font-size:10.5px;margin-top:6px;display:flex;justify-content:space-between;gap:8px;color:var(--fraco)}
|
||
.calc .ok{color:var(--verde)}.calc .av{color:var(--laranja)}.calc .er{color:var(--vermelho)}
|
||
.dica{margin-top:9px;background:#FFF8EE;border:1px solid #F0D9AE;border-radius:8px;
|
||
padding:10px 12px;font-size:11.5px;color:#7A5A16;line-height:1.45}
|
||
.dica b{display:block;font-family:"Inter",sans-serif;color:#B07A18;font-size:12px;margin-bottom:3px}
|
||
.dica button{display:block;width:100%;margin-top:10px;padding:10px 14px;border-radius:7px;
|
||
border:1px solid var(--verde-ml);background:var(--verde-ml);color:#fff;
|
||
font-family:"Inter",sans-serif;font-weight:700;font-size:13px;letter-spacing:.01em;
|
||
cursor:pointer;box-shadow:0 2px 8px rgba(0,166,80,.28);transition:var(--transition)}
|
||
.dica button:hover{background:#00934A;border-color:#00934A;box-shadow:0 4px 14px rgba(0,166,80,.38)}
|
||
.dicaok{margin-top:8px;font-size:11px;color:var(--verde)}
|
||
|
||
/* cota em escala da peça dentro da largura do filme */
|
||
.viz{margin-top:10px;max-width:100%}
|
||
.vizL{display:flex;align-items:center;gap:7px;margin-bottom:5px}
|
||
.vizL i{flex:1;height:1px;background:var(--gray-2);position:relative}
|
||
.vizL i::before{content:"";position:absolute;top:-3px;width:1px;height:7px;background:var(--gray-2)}
|
||
.vizL i:first-child::before{left:0} .vizL i:last-child::before{right:0}
|
||
.vizL b{font-family:"Inter",sans-serif;font-size:9.5px;font-weight:700;letter-spacing:.08em;
|
||
text-transform:uppercase;color:var(--fraco)}
|
||
.vizRow{display:flex;gap:7px;align-items:flex-end}
|
||
.vizTira{flex:none;max-width:100%}
|
||
.vizH{flex:none;display:flex;align-items:center;justify-content:center;padding-left:4px;
|
||
border-left:1px solid var(--gray-2);min-height:22px}
|
||
.vizH span{writing-mode:vertical-rl;font-family:"Inter",sans-serif;font-size:9.5px;
|
||
font-weight:700;color:var(--fraco);white-space:nowrap}
|
||
.tira{display:flex;background:#fff;border:1px solid var(--linha);border-radius:4px;
|
||
padding:2px;overflow:hidden;min-height:22px;width:100%}
|
||
.pc{flex:none;overflow:hidden;display:flex;align-items:center;justify-content:center;
|
||
background:#F2F2F2;border-radius:2px}
|
||
.pc img{width:100%;height:100%;object-fit:contain;display:block}
|
||
.pc span{font-family:"Inter",sans-serif;font-size:9px;font-weight:700;color:var(--fraco)}
|
||
.folga{flex:1;min-width:0;display:flex;align-items:center;justify-content:center;border-radius:2px;
|
||
background:repeating-linear-gradient(45deg,#FBFBFB,#FBFBFB 4px,#F0F0F0 4px,#F0F0F0 8px)}
|
||
.folga span{font-size:8.5px;color:var(--fraco);white-space:nowrap;overflow:hidden}
|
||
.vizPe{font-size:10.5px;color:var(--fraco);margin-top:6px;line-height:1.4}
|
||
.vizPe b{color:var(--tx);font-family:"Inter",sans-serif;font-weight:700}
|
||
.resumoA{background:#fff;border:1px solid var(--linha);border-radius:9px;padding:11px 13px;
|
||
font-size:12px;margin-bottom:12px;display:none}
|
||
.resumoA.on{display:block}
|
||
.resumoA .r{display:flex;justify-content:space-between;padding:2px 0}
|
||
.resumoA .r b{font-family:"Inter",sans-serif}
|
||
|
||
/* nota de qualidade */
|
||
.qual{background:#fff;border:1px solid var(--linha);border-radius:13px;padding:22px;margin-top:16px;display:none}
|
||
.qual.on{display:block}
|
||
.qh{display:flex;justify-content:space-between;align-items:flex-end;gap:14px;flex-wrap:wrap;margin-bottom:14px}
|
||
.qh h3{font-family:"Inter",sans-serif;font-size:17px;font-weight:700}
|
||
.qh .pct{font-family:"Inter",sans-serif;font-weight:700;font-size:38px;line-height:1;color:var(--verde)}
|
||
.qh .pct small{font-size:14px;color:var(--fraco)}
|
||
.qbar{height:13px;border-radius:8px;background:var(--cinza);overflow:hidden}
|
||
.qbar i{display:block;height:100%;border-radius:8px;background:var(--verde)}
|
||
.qitens{display:grid;grid-template-columns:repeat(auto-fit,minmax(178px,1fr));gap:7px;margin-top:13px}
|
||
.qi{display:flex;gap:8px;align-items:center;border:1px solid var(--linha);border-radius:8px;
|
||
padding:7px 10px;font-size:11.5px}
|
||
.qi .c{width:15px;height:15px;border-radius:50%;display:grid;place-items:center;font-size:8.5px;
|
||
flex:none;color:#fff;font-family:"Inter",sans-serif;font-weight:700}
|
||
.qi b{display:block;font-family:"Inter",sans-serif;font-size:11.5px}
|
||
.qi span{color:var(--fraco);font-size:10.5px}
|
||
.qi.ok .c{background:var(--verde)}.qi.av .c{background:var(--laranja);color:#241703}
|
||
.qi.er .c{background:var(--vermelho)}
|
||
.qi.fix{border-color:#BBD9E8;background:#F2F9FC}
|
||
.qi.fix .c{background:#2F7FA8}
|
||
.ciente{background:#FFF8EE;border:1px solid #F0D9AE;border-radius:10px;padding:14px 17px;
|
||
margin-top:14px;display:none}
|
||
.ciente.on{display:block}
|
||
.ciente.recusa{background:#FFF3F0;border-color:#E8A796}
|
||
.ciente.recusa h4{color:#8C3B22}
|
||
.ciente.recusa label{display:none}
|
||
.ciente.recusa .lista{color:#8C3B22}
|
||
.ciente h4{font-family:"Inter",sans-serif;font-size:14px;font-weight:700;color:#B07A18;margin-bottom:5px}
|
||
.ciente p{font-size:12.5px;color:#7A5A16;line-height:1.5}
|
||
.ciente .lista{margin:10px 0 0;font-size:12px;color:#7A5A16}
|
||
.ciente .lista div{padding:3px 0 3px 15px;position:relative}
|
||
.ciente .lista div::before{content:"·";position:absolute;left:4px;font-weight:700}
|
||
.ciente label{display:flex;gap:9px;align-items:flex-start;margin-top:12px;padding-top:11px;
|
||
border-top:1px solid #F0D9AE;cursor:pointer;font-size:12.5px;color:#5E4512}
|
||
.ciente input{margin-top:2px;width:16px;height:16px;flex:none;accent-color:#B07A18}
|
||
@keyframes pulsa{0%,100%{transform:scale(1);box-shadow:0 0 0 0 rgba(217,74,40,.55)}
|
||
50%{transform:scale(1.04);box-shadow:0 0 0 12px rgba(217,74,40,0)}}
|
||
.qbts{display:flex;gap:9px;flex-wrap:wrap;margin-top:16px}
|
||
.qbts .qb{flex:1;min-width:220px}
|
||
.qb{padding:11px 17px;border-radius:8px;border:1px solid var(--linha);background:#fff;
|
||
font-family:"Inter",sans-serif;font-weight:600;font-size:13.5px;cursor:pointer;color:var(--tx)}
|
||
.qb.p{background:var(--laranja);border-color:var(--laranja);color:#241703}
|
||
.qb.chama{background:var(--vermelho);border-color:var(--vermelho);color:#fff;
|
||
animation:pulsa 1.6s ease-in-out infinite}
|
||
.qb.chama:hover{background:#C1421F;animation:none}
|
||
.qb:disabled{opacity:.45;cursor:not-allowed}
|
||
@media(prefers-reduced-motion:reduce){.qb.chama{animation:none}}
|
||
|
||
/* prévia */
|
||
.prev{background:#fff;border:1px solid var(--linha);border-radius:13px;padding:22px;margin-top:16px;display:none}
|
||
.prev.on{display:block}
|
||
.prev .ph{display:flex;justify-content:space-between;align-items:flex-end;gap:14px;flex-wrap:wrap;margin-bottom:14px}
|
||
.prev .ph h3{font-family:"Inter",sans-serif;font-size:17px;font-weight:700}
|
||
.prev .ph p{font-size:12.5px;color:var(--fraco)}
|
||
.prev .ph .mt{font-family:"Inter",sans-serif;font-weight:700;font-size:22px;white-space:nowrap}
|
||
.prev .ph .mt small{font-size:12px;color:var(--fraco);font-weight:600}
|
||
.pgrid{display:grid;grid-template-columns:300px 1fr;gap:18px;align-items:start}
|
||
@media(max-width:760px){.pgrid{grid-template-columns:1fr}}
|
||
.pfolha{background:var(--cinza);border:1px solid var(--linha);border-radius:10px;padding:12px}
|
||
.pfolha canvas,.pfolha img{width:100%;height:auto;display:block;border-radius:6px;background:#fff}
|
||
.pfolha .semprev,.pfolha .carregando{padding:40px 16px;text-align:center;color:var(--fraco);
|
||
font-size:12px;background:#fff;border-radius:6px}
|
||
.pfolha .semprev b{display:block;font-family:"Inter",sans-serif;color:var(--tx);font-size:13px;margin-bottom:4px}
|
||
.usoBom,.usoRuim{margin-top:10px;border-radius:8px;padding:9px 12px;font-size:11.5px;line-height:1.45}
|
||
.usoBom{background:#F1F8F3;border:1px solid #CDE6D6;color:#2A6B45}
|
||
.usoRuim{background:#FFF8EE;border:1px solid #F0D9AE;color:#7A5A16}
|
||
.usoBom b,.usoRuim b{display:block;font-family:"Inter",sans-serif;font-size:12.5px;margin-bottom:2px}
|
||
.pinfo .li{display:flex;gap:10px;align-items:flex-start;padding:7px 0;font-size:12.5px;
|
||
border-bottom:1px solid var(--linha)}
|
||
.pinfo .li:last-child{border:0}
|
||
.pinfo .li .c{width:19px;height:19px;border-radius:50%;display:grid;place-items:center;flex:none;
|
||
margin-top:1px;font-size:10px;color:#fff;font-family:"Inter",sans-serif;font-weight:700}
|
||
.pinfo .li b{display:block;font-family:"Inter",sans-serif;font-size:12.5px}
|
||
.pinfo .li span{color:var(--fraco);font-size:11.5px}
|
||
.pcta{display:flex;gap:9px;flex-wrap:wrap;margin-top:16px;padding-top:15px;border-top:1px solid var(--linha)}
|
||
.pb{padding:11px 18px;border-radius:8px;border:1px solid var(--linha);background:#fff;
|
||
font-family:"Inter",sans-serif;font-weight:600;font-size:13.5px;cursor:pointer;color:var(--tx)}
|
||
.pb.p{background:var(--laranja);border-color:var(--laranja);color:#241703}
|
||
.pb:hover{border-color:#111}
|
||
|
||
/* carrinho */
|
||
/* faixa de prova · cinco motivos logo abaixo do topo */
|
||
.prova{padding:clamp(22px,3vw,34px) 0}
|
||
.prova .w{display:grid;grid-template-columns:repeat(auto-fit,minmax(178px,1fr));gap:14px}
|
||
.p1{border-left:2px solid var(--laranja);padding:2px 0 2px 13px}
|
||
.p1 b{display:block;font-family:"Inter",sans-serif;font-size:14px;font-weight:700;
|
||
line-height:1.25;color:var(--tx);margin-bottom:5px}
|
||
.p1 b em{font-style:normal;color:var(--laranja)}
|
||
.p1 span{display:block;font-size:11.5px;color:var(--fraco);line-height:1.5}
|
||
|
||
/* ── Carrinho no padrão de checkout: entrega à esquerda, resumo fixo à direita ── */
|
||
.carr{display:none;margin-top:18px}
|
||
.carr.on{display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:18px;align-items:start}
|
||
@media(max-width:900px){.carr.on{grid-template-columns:1fr}}
|
||
.carr h3{font-family:"Inter",sans-serif;font-size:19px;font-weight:700;margin-bottom:12px}
|
||
.cxE{background:#fff;border:1px solid var(--linha);border-radius:12px;
|
||
box-shadow:var(--sombra);padding:17px 18px;margin-bottom:14px}
|
||
.cxE h4{font-family:"Inter",sans-serif;font-size:15px;font-weight:700;margin-bottom:11px}
|
||
|
||
/* itens do pedido */
|
||
.item{display:flex;gap:11px;align-items:flex-start;padding:11px 0;border-top:1px solid var(--linha)}
|
||
.item:first-child{border-top:0;padding-top:2px}
|
||
.item .nm2{flex:1;min-width:0}
|
||
.item .nm2 b{display:block;font-family:"Inter",sans-serif;font-size:13.5px;color:var(--tx)}
|
||
.item .nm2 span{font-size:11.5px;color:var(--fraco)}
|
||
.item .vl2{font-family:"Inter",sans-serif;font-weight:700;font-size:14px;color:var(--tx);
|
||
white-space:nowrap}
|
||
.item .x{border:0;background:none;color:var(--gray-2);cursor:pointer;font-size:17px;
|
||
line-height:1;padding:0 0 0 4px}
|
||
.item .x:hover{color:var(--vermelho)}
|
||
.rot{font-family:"Inter",sans-serif;font-size:10px;font-weight:700;letter-spacing:.12em;
|
||
text-transform:uppercase;color:var(--fraco);margin:0 0 7px}
|
||
.carr .l{display:flex;justify-content:space-between;font-size:12.5px;padding:5px 0;
|
||
color:var(--fraco);gap:14px}
|
||
.carr .l b{color:var(--tx);font-family:"Inter",sans-serif;font-weight:700;white-space:nowrap}
|
||
|
||
/* identificação do cliente */
|
||
.subC{font-size:11.5px;color:var(--fraco);line-height:1.5;margin:-4px 0 12px}
|
||
.campos{display:grid;grid-template-columns:1fr 1fr;gap:11px}
|
||
@media(max-width:620px){.campos{grid-template-columns:1fr}}
|
||
.cp.larga{grid-column:1/-1}
|
||
.cp label{display:block;font-size:10.5px;color:var(--fraco);margin-bottom:5px}
|
||
.cp input{width:100%;padding:11px 12px;border-radius:8px;border:1px solid var(--linha);
|
||
background:#fff;font-family:inherit;font-size:13.5px;color:var(--tx)}
|
||
.cp input:focus{outline:none;border-color:var(--laranja)}
|
||
.cp input.ruim{border-color:var(--vermelho);background:#FFF6F4}
|
||
.cp input.bom{border-color:var(--verde-ml)}
|
||
.cp .err{display:block;font-size:10.5px;color:var(--vermelho);margin-top:4px;min-height:13px}
|
||
|
||
/* forma de entrega, como no checkout do marketplace */
|
||
.entrega{display:grid;gap:9px}
|
||
.opE{display:flex;gap:11px;align-items:flex-start;text-align:left;width:100%;
|
||
background:#fff;border:1px solid var(--linha);border-radius:10px;padding:13px 14px;
|
||
cursor:pointer;font-family:inherit;color:var(--tx);transition:var(--transition)}
|
||
.opE:hover{border-color:var(--gray-3)}
|
||
.opE.on{border-color:var(--verde-ml);background:#F4FCF7;box-shadow:0 0 0 1px var(--verde-ml)}
|
||
.opE .mk{flex:none;width:17px;height:17px;border-radius:50%;margin-top:2px;
|
||
border:2px solid var(--gray-2);background:#fff}
|
||
.opE.on .mk{border-color:var(--verde-ml);
|
||
background:radial-gradient(circle,var(--verde-ml) 0 4px,#fff 5px)}
|
||
.opE div{flex:1;min-width:0}
|
||
.opE b{display:block;font-family:"Inter",sans-serif;font-size:13.5px;margin-bottom:2px}
|
||
.opE span{font-size:11.5px;color:var(--fraco);line-height:1.5}
|
||
.opE em{flex:none;font-style:normal;font-family:"Inter",sans-serif;font-weight:700;
|
||
font-size:13px;color:var(--verde-ml);white-space:nowrap}
|
||
.cep{display:none;margin-top:10px;padding:12px;background:var(--cinza);border-radius:9px}
|
||
.cep.on{display:block}
|
||
.cep label{display:block;font-size:10.5px;color:var(--fraco);margin-bottom:6px}
|
||
.cepL{display:flex;gap:8px}
|
||
.cepL input{flex:1;min-width:0;padding:10px 12px;border-radius:8px;background:#fff;
|
||
border:1px solid var(--linha);font-family:inherit;font-size:13px;color:var(--tx)}
|
||
.cepL input:focus{outline:none;border-color:var(--laranja)}
|
||
.cepL button{flex:none;width:auto;padding:10px 18px;border-radius:8px;
|
||
border:1px solid var(--linha);cursor:pointer;background:#fff;color:var(--tx);
|
||
font-family:"Inter",sans-serif;font-weight:600;font-size:12.5px}
|
||
.cepL button:hover{border-color:var(--laranja);color:var(--laranja)}
|
||
.cep p{font-size:11.5px;color:var(--fraco);margin-top:9px;line-height:1.5}
|
||
.avisoE:empty{display:none}
|
||
.avisoE{font-size:11.5px;color:#1F5C3A;background:#F1FBF5;border:1px solid #BFE6CE;
|
||
border-radius:8px;padding:10px 12px;line-height:1.5;margin-top:9px}
|
||
|
||
/* resumo da compra */
|
||
.resumo{position:sticky;top:104px;background:#fff;border:1px solid var(--linha);
|
||
border-radius:12px;box-shadow:var(--sombra);padding:17px 18px}
|
||
@media(max-width:900px){.resumo{position:static}}
|
||
.resumo h4{font-family:"Inter",sans-serif;font-size:16px;font-weight:700;margin-bottom:12px}
|
||
.resumo .l{padding:6px 0}
|
||
.carr .tot{display:flex;justify-content:space-between;align-items:baseline;gap:12px;
|
||
font-family:"Inter",sans-serif;font-size:15px;font-weight:700;padding-top:12px;margin-top:8px;
|
||
border-top:1px solid var(--linha);color:var(--tx)}
|
||
.carr .tot b{font-size:23px;color:var(--tx)}
|
||
.cbts{display:grid;gap:9px;margin-top:14px}
|
||
.cbts button{width:100%;padding:13px;border-radius:9px;border:0;background:var(--laranja);
|
||
color:#241703;font-family:"Inter",sans-serif;font-weight:700;font-size:14.5px;cursor:pointer;
|
||
transition:var(--transition)}
|
||
.cbts button:hover{background:var(--laranja2)}
|
||
.cbts button:disabled{opacity:.4;cursor:not-allowed}
|
||
.cbts .sec{background:#fff;color:var(--tx);border:1px solid var(--linha);font-weight:600}
|
||
.cbts .sec:hover{background:#fff;border-color:var(--laranja);color:var(--laranja)}
|
||
.carr .obs{font-size:11px;color:var(--fraco);margin-top:11px;line-height:1.5}
|
||
|
||
.carro{position:relative;margin-top:22px}
|
||
.trilho{display:flex;gap:14px;overflow-x:auto;scroll-snap-type:x mandatory;
|
||
scroll-behavior:smooth;padding-bottom:6px;-webkit-overflow-scrolling:touch}
|
||
.trilho::-webkit-scrollbar{height:0}
|
||
.slide{flex:0 0 clamp(244px,76%,316px);scroll-snap-align:start;
|
||
background:var(--cinza);border:1px solid var(--linha);border-radius:13px;padding:17px 18px}
|
||
.slide .et2{font-family:"Inter",sans-serif;font-size:9.5px;font-weight:700;letter-spacing:.14em;
|
||
text-transform:uppercase;color:var(--laranja);margin-bottom:8px;display:block}
|
||
.slide h3{font-family:"Inter",sans-serif;font-size:16px;font-weight:700;margin-bottom:6px;line-height:1.18}
|
||
.slide p{font-size:12.5px;color:var(--fraco);line-height:1.5}
|
||
/* selo circular · o benefício em número, com os anéis da marca em volta */
|
||
.slide{position:relative;overflow:hidden}
|
||
.stop{display:flex;justify-content:space-between;align-items:flex-start;gap:12px}
|
||
.sinfo{min-width:0;flex:1}
|
||
.selo{flex:none;position:relative;width:74px;height:74px;border-radius:50%;
|
||
display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;
|
||
background:#fff;border:2px solid var(--verde-ml);margin:2px 4px 0 0}
|
||
.selo i{position:absolute;inset:-6px;border-radius:50%;border:1px solid rgba(0,166,80,.34)}
|
||
.selo::before,.selo::after{content:"";position:absolute;border-radius:50%;pointer-events:none}
|
||
.selo::before{inset:-13px;border:1px solid rgba(0,166,80,.18)}
|
||
.selo::after{inset:-21px;border:1px solid rgba(0,166,80,.09)}
|
||
.selo b{font-family:"Inter",sans-serif;font-weight:700;font-size:19px;line-height:1;
|
||
color:var(--verde-ml);letter-spacing:-.01em}
|
||
.selo b em{font-style:normal;font-size:11px;margin-left:1px}
|
||
.selo span{font-family:"Inter",sans-serif;font-weight:700;font-size:8px;line-height:1.2;
|
||
letter-spacing:.07em;text-transform:uppercase;color:var(--fraco);margin-top:4px;padding:0 5px}
|
||
.slide .num{font-family:"Inter",sans-serif;font-weight:700;font-size:26px;
|
||
color:var(--laranja);line-height:1;margin-bottom:6px}
|
||
.slide ul{list-style:none;font-size:12px;margin-top:9px}
|
||
.slide li{padding:4px 0 4px 19px;position:relative;color:var(--fraco)}
|
||
.slide li::before{content:"✓";position:absolute;left:2px;color:var(--verde);font-size:11px}
|
||
.slide li.no::before{content:"!";color:var(--laranja);font-weight:700}
|
||
.slide table{width:100%;font-size:12px;margin-top:9px;border-collapse:collapse}
|
||
.slide td{padding:5px 0;border-bottom:1px solid #E3E3E3;color:var(--fraco)}
|
||
.slide td+td{text-align:right;font-family:"Inter",sans-serif;font-weight:700;color:var(--tx)}
|
||
.slide td.cab{font-family:"Inter",sans-serif;font-size:9.5px;font-weight:700;letter-spacing:.1em;
|
||
text-transform:uppercase;color:var(--fraco)}
|
||
.slide tr:last-child td{border:0}
|
||
.slide .dest{background:#fff;border-radius:8px;padding:9px 11px;margin-top:9px;
|
||
font-size:11.5px;color:var(--tx)}
|
||
.navc{display:flex;gap:8px;align-items:center;margin-top:14px}
|
||
.navc button{width:32px;height:32px;border-radius:50%;border:1px solid var(--linha);
|
||
background:#fff;color:var(--tx);cursor:pointer;font-size:15px;line-height:1}
|
||
.navc button:hover{border-color:var(--laranja);color:var(--laranja)}
|
||
.pontos{display:flex;gap:5px;margin-left:auto}
|
||
.pt{width:20px;height:3px;border-radius:2px;background:var(--linha);border:0;padding:0;cursor:pointer}
|
||
.pt.on{background:var(--laranja)}
|
||
@media(prefers-reduced-motion:reduce){.trilho{scroll-behavior:auto}}
|
||
|
||
h2{font-size:clamp(23px,3.6vw,34px);font-weight:700;max-width:20ch}
|
||
h2 em{font-style:normal;color:var(--laranja)}
|
||
.et{font-size:11px;letter-spacing:.2em;text-transform:uppercase;color:var(--laranja);
|
||
font-family:"Inter",sans-serif;font-weight:700;margin-bottom:10px}
|
||
.lead{color:var(--fraco);font-size:15px;max-width:56ch;margin-top:12px}
|
||
.dor{display:grid;grid-template-columns:repeat(auto-fit,minmax(215px,1fr));gap:13px;margin-top:24px}
|
||
.dc{background:#fff;border:1px solid var(--linha);border-radius:12px;padding:18px 19px}
|
||
.dc .ic{width:30px;height:30px;border-radius:9px;display:grid;place-items:center;
|
||
font-family:"Inter",sans-serif;font-weight:700;font-size:14px;margin-bottom:11px;
|
||
background:#FBEEEA;color:var(--vermelho)}
|
||
.dc h3{font-size:15px;font-weight:700;margin-bottom:4px}
|
||
.dc p{font-size:12.5px;color:var(--fraco)}
|
||
.nota{background:var(--cinza);border-radius:11px;padding:14px 18px;margin-top:15px;font-size:13px;color:var(--fraco)}
|
||
.nota b{color:var(--tx);font-family:"Inter",sans-serif}
|
||
|
||
footer{background:#000;color:#8D9AB0;padding:26px 0 20px;font-size:12.5px}
|
||
.frow{display:flex;gap:26px;align-items:flex-start;flex-wrap:wrap;padding-bottom:18px}
|
||
.fmarca{display:flex;align-items:center;gap:9px;font-family:"Inter",sans-serif;
|
||
font-weight:700;font-size:13px;color:var(--laranja);letter-spacing:.06em;white-space:nowrap}
|
||
.fmarca img{height:22px;width:auto;display:block;filter:brightness(0) invert(1)}
|
||
footer a{color:#8D9AB0;text-decoration:none}
|
||
footer a:hover{color:var(--laranja2)}
|
||
.flinks{display:flex;gap:18px;flex-wrap:wrap;font-size:12.5px}
|
||
.fcont{margin-left:auto;text-align:right;font-size:12.5px;line-height:1.7}
|
||
@media(max-width:720px){.fcont{margin-left:0;text-align:left}}
|
||
.fbase{border-top:1px solid rgba(255,255,255,.1);padding-top:14px;display:flex;
|
||
justify-content:space-between;gap:12px;flex-wrap:wrap;font-size:11px;color:#5A6570}
|
||
@media(prefers-reduced-motion:reduce){*{transition:none!important;scroll-behavior:auto}}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="tarja">
|
||
ENVIE SEU ARQUIVO DTF PELO SITE · DTF TÊXTIL COM O MENOR PREÇO DO METRO EM FRANCA-SP
|
||
</div>
|
||
|
||
<header class="topo"><div class="w">
|
||
<a class="logo" href="https://www.dropstaratacado.com.br" aria-label="Dropstar Atacado"><img src="https://cdn.vnda.com.br/dropstar/2025/12/17/logo-header-15125700-16129080.png?v=1766009286" alt="Dropstar"></a>
|
||
<div class="busca">
|
||
<span class="lupa">⌕</span>
|
||
<input type="search" placeholder="Buscar" aria-label="Buscar">
|
||
</div>
|
||
<div class="acts">
|
||
<a href="/portal.html">Minha conta</a>
|
||
<a href="#carr" id="cartLink">Carrinho (0)</a>
|
||
</div>
|
||
</div></header>
|
||
|
||
<nav class="menu"><div class="w">
|
||
<div class="mi">
|
||
<a href="https://www.dropstaratacado.com.br/camiseta" target="_blank" rel="noopener">Vestuários</a>
|
||
<div class="sub">
|
||
<a href="https://www.dropstaratacado.com.br/camiseta/modelo-blcs" target="_blank" rel="noopener">Camiseta Premium</a>
|
||
<a href="https://www.dropstaratacado.com.br/camiseta/modelo-blos" target="_blank" rel="noopener">Camiseta Oversized</a>
|
||
<a href="https://www.dropstaratacado.com.br/moletom-canguru/modelo-blmc" target="_blank" rel="noopener">Moletom Canguru</a>
|
||
<a href="https://www.dropstaratacado.com.br/camiseta/modelo-blmp" target="_blank" rel="noopener">Camiseta Pima</a>
|
||
<a href="https://www.dropstaratacado.com.br/camiseta/modelo-blcp" target="_blank" rel="noopener">Camiseta Poliamida</a>
|
||
<a href="https://www.dropstaratacado.com.br/camiseta/modelo-blcd" target="_blank" rel="noopener">Camiseta Dry Fit</a>
|
||
<a href="https://www.dropstaratacado.com.br/camiseta/modelo-blci" target="_blank" rel="noopener">Camiseta Infantil</a>
|
||
<a href="https://www.dropstaratacado.com.br/camiseta/modelo-blrm" target="_blank" rel="noopener">Regata Machão</a>
|
||
<a href="https://www.dropstaratacado.com.br/camiseta/modelo-blgp" target="_blank" rel="noopener">Camisa Polo</a>
|
||
<a href="https://www.dropstaratacado.com.br/modelo-blmi" target="_blank" rel="noopener">Moletom Canguru Infantil</a>
|
||
</div>
|
||
</div>
|
||
<div class="mi on">
|
||
<a href="#envio" data-modo-cta="avulsa">Impressão DTF</a>
|
||
<div class="sub">
|
||
<a href="#envio" data-modo-cta="avulsa">DTF Têxtil · 57 cm</a>
|
||
<a href="#envio" data-modo-cta="uv">DTF UV · 28,5 cm</a>
|
||
</div>
|
||
</div>
|
||
<div class="mi">
|
||
<a href="https://www.dropstaratacado.com.br/modelo-emb" target="_blank" rel="noopener">Embalagens</a>
|
||
<div class="sub">
|
||
<a href="https://www.dropstaratacado.com.br/modelo-emb/modelo-sacseg" target="_blank" rel="noopener">Saco de Segurança</a>
|
||
<a href="https://www.dropstaratacado.com.br/modelo-emb/fit-adesiva" target="_blank" rel="noopener">Fita Adesiva</a>
|
||
<a href="https://www.dropstaratacado.com.br/modelo-emb/modelo-etiqtermica" target="_blank" rel="noopener">Etiqueta Térmica</a>
|
||
</div>
|
||
</div>
|
||
<div class="mi">
|
||
<a href="https://www.dropstaratacado.com.br/modelo-acessorios" target="_blank" rel="noopener">Acessórios</a>
|
||
<div class="sub">
|
||
<a href="https://www.dropstaratacado.com.br/modelo-acessorios/modelo-bon" target="_blank" rel="noopener">Boné Trucker</a>
|
||
<a href="https://www.dropstaratacado.com.br/chinelo-tradicional-unissex" target="_blank" rel="noopener">Chinelo Tradicional Unissex</a>
|
||
</div>
|
||
</div>
|
||
<div class="mi">
|
||
<a href="https://www.dropstaratacado.com.br/insumos" target="_blank" rel="noopener">Insumos</a>
|
||
<div class="sub">
|
||
<a href="https://www.dropstaratacado.com.br/filme-dtf" target="_blank" rel="noopener">Filme DTF</a>
|
||
<a href="https://www.dropstaratacado.com.br/poliamida-dtf" target="_blank" rel="noopener">Poliamida DTF</a>
|
||
<a href="https://www.dropstaratacado.com.br/tinta-dtf" target="_blank" rel="noopener">Tinta DTF</a>
|
||
<a href="https://www.dropstaratacado.com.br/fluido-limpeza" target="_blank" rel="noopener">Fluído Limpeza</a>
|
||
<a href="https://www.dropstaratacado.com.br/primer-limpeza" target="_blank" rel="noopener">Primer Limpeza</a>
|
||
</div>
|
||
</div>
|
||
<div class="mi">
|
||
<a href="https://www.dropstaratacado.com.br/produto/personalizacao-premium-sua-estampa-aqui-envie-a-estampa-16-99230-2546-59" target="_blank" rel="noopener">Personalizados</a>
|
||
</div>
|
||
</div></nav>
|
||
|
||
<header class="hero">
|
||
<div class="fundo" aria-hidden="true">
|
||
<svg viewBox="0 0 1400 300" preserveAspectRatio="xMidYMid slice">
|
||
<g fill="#fff">
|
||
<rect x="20" y="16" width="118" height="140" rx="5"/>
|
||
<rect x="150" y="16" width="118" height="140" rx="5"/>
|
||
<rect x="280" y="16" width="76" height="66" rx="5"/>
|
||
<rect x="368" y="16" width="76" height="66" rx="5"/>
|
||
<rect x="280" y="94" width="164" height="62" rx="5"/>
|
||
<rect x="456" y="16" width="96" height="96" rx="5"/>
|
||
<rect x="564" y="16" width="96" height="96" rx="5"/>
|
||
<rect x="456" y="124" width="204" height="32" rx="5"/>
|
||
<rect x="672" y="16" width="118" height="140" rx="5"/>
|
||
<rect x="802" y="16" width="112" height="66" rx="5"/>
|
||
<rect x="802" y="94" width="112" height="62" rx="5"/>
|
||
<rect x="926" y="16" width="150" height="140" rx="5"/>
|
||
<rect x="1088" y="16" width="86" height="86" rx="5"/>
|
||
<rect x="1186" y="16" width="86" height="86" rx="5"/>
|
||
<rect x="1088" y="114" width="184" height="42" rx="5"/>
|
||
<rect x="1284" y="16" width="96" height="140" rx="5"/>
|
||
<rect x="20" y="168" width="76" height="76" rx="5"/>
|
||
<rect x="108" y="168" width="76" height="76" rx="5"/>
|
||
<rect x="196" y="168" width="76" height="76" rx="5"/>
|
||
<rect x="284" y="168" width="160" height="76" rx="5"/>
|
||
<rect x="456" y="168" width="104" height="118" rx="5"/>
|
||
<rect x="572" y="168" width="104" height="118" rx="5"/>
|
||
<rect x="688" y="168" width="226" height="54" rx="5"/>
|
||
<rect x="688" y="234" width="108" height="52" rx="5"/>
|
||
<rect x="808" y="234" width="106" height="52" rx="5"/>
|
||
<rect x="926" y="168" width="150" height="118" rx="5"/>
|
||
<rect x="1088" y="168" width="184" height="56" rx="5"/>
|
||
<rect x="1088" y="236" width="86" height="50" rx="5"/>
|
||
<rect x="1186" y="236" width="86" height="50" rx="5"/>
|
||
<rect x="1284" y="168" width="96" height="118" rx="5"/>
|
||
<rect x="20" y="256" width="424" height="30" rx="5"/>
|
||
</g>
|
||
</svg>
|
||
</div>
|
||
|
||
<div class="w">
|
||
<div class="hgrid">
|
||
<div>
|
||
<div class="selos1">
|
||
<span class="sel top">Metro a partir de R$ 14,90</span>
|
||
<span class="sel novo">Revisão inclusa</span>
|
||
<span class="sel pos">Franca · SP</span>
|
||
</div>
|
||
<h1>A gente encaixa sua folha<br><em>e você paga menos metro</em></h1>
|
||
<p class="sub2">Mande a arte, veja a nota em segundos e a folha montada antes de fechar.
|
||
<b>Revisão e remanejamento por nossa conta.</b></p>
|
||
<div class="hcta">
|
||
<a href="#envio" class="btn1" data-modo-cta="avulsa">Enviar minha arte</a>
|
||
<span class="mini">sem cadastro · resposta em segundos</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="pfaixa">
|
||
<a class="pcard dest" href="#envio">
|
||
<span class="marc">mais vendido</span>
|
||
<span class="apartir">com arte boa</span>
|
||
<span class="vl">R$ 14,90<small> /m</small></span>
|
||
<span class="nm">Arquivo por metro</span>
|
||
<span class="dsc">têxtil · 57 cm</span>
|
||
</a>
|
||
<a class="pcard" href="#envio">
|
||
<span class="apartir">com arte boa</span>
|
||
<span class="vl">R$ 24,90<small> /m</small></span>
|
||
<span class="nm">Artes avulsas</span>
|
||
<span class="dsc">têxtil · montamos a folha</span>
|
||
</a>
|
||
<a class="pcard" href="#envio">
|
||
<span class="apartir">com arte boa</span>
|
||
<span class="vl">R$ 69,90<small> /m</small></span>
|
||
<span class="nm">Arquivo UV</span>
|
||
<span class="dsc">rígido · 28,5 cm</span>
|
||
</a>
|
||
<a class="pcard" href="#envio">
|
||
<span class="apartir">com arte boa</span>
|
||
<span class="vl">R$ 83,90<small> /m</small></span>
|
||
<span class="nm">Artes avulsas UV</span>
|
||
<span class="dsc">rígido · montamos a folha</span>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="barrah">
|
||
<span><i>◆</i> Revisão de <b>5 pontos</b> sem custo</span>
|
||
<span><i>◆</i> Cobrança por <b>proporção</b>, a cada 10 cm</span>
|
||
<span><i>◆</i> Filme de <b>57 cm</b>, o dobro do padrão</span>
|
||
<span><i>◆</i> Prévia da folha <b>antes de pagar</b></span>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
|
||
<!-- PROVA -->
|
||
<section class="prova"><div class="w">
|
||
<div class="p1"><b>Quanto melhor sua arte,<br><em>menor o preço do metro</em></b>
|
||
<span>Têxtil de R$ 19,90 a R$ 14,90 · UV de R$ 99,90 a R$ 69,90.
|
||
A nota aparece na tela antes de você pagar.</span></div>
|
||
<div class="p1"><b>Filme de 57 cm,<br><em>o dobro do padrão</em></b>
|
||
<span>Cabe o dobro de arte por metro. E reencaixamos sua folha sem cobrar.</span></div>
|
||
<div class="p1"><b>Você paga só<br><em>o que usa</em></b>
|
||
<span>Cobrança a cada 10 cm. Folha de 2,75 m custa 2,80 — não 3.</span></div>
|
||
<div class="p1"><b>Erro pego<br><em>antes de imprimir</em></b>
|
||
<span>5 pontos conferidos e a nota na tela. Sem custo.</span></div>
|
||
<div class="p1"><b>Envio em<br><em>até 24 horas</em></b>
|
||
<span>E avisamos por WhatsApp a cada etapa do pedido.</span></div>
|
||
</div></section>
|
||
|
||
<!-- ENVIO -->
|
||
<section id="envio"><div class="w">
|
||
|
||
<!-- 3 cards -->
|
||
<div id="cards">
|
||
<div class="et">Comece por aqui</div>
|
||
<h2>Qual é o seu <em>caso</em>?</h2>
|
||
<div class="escolha">
|
||
<button class="ec f" data-modo="file">
|
||
<span class="marc">Mais vendido</span>
|
||
<div class="top"><h3>Arquivo por metro</h3>
|
||
<span class="p"><i>tabela</i>R$ 19,90<small>/m</small></span></div>
|
||
<div class="chama2">Quer pagar <b>R$ 14,90</b>? Arte em 300 DPI, em arquivo que a gente confere.</div>
|
||
<div class="in">
|
||
<span class="lg">DTF têxtil · 57 cm</span>
|
||
<p>Você monta a folha e manda pronta. Revisamos, corrigimos e reencaixamos.</p>
|
||
<ul><li>Remanejamos e sua folha encolhe</li><li>Arquivo bom paga o mínimo</li>
|
||
<li>Você continua no controle do layout</li></ul>
|
||
<span class="go">Enviar minha folha ›</span>
|
||
</div>
|
||
</button>
|
||
|
||
<button class="ec a" data-modo="avulsa">
|
||
<div class="top"><h3>Artes avulsas</h3><span class="p"><i>tabela</i>R$ 29,90<small>/m</small></span></div>
|
||
<div class="chama2">Quer pagar <b>R$ 24,90</b>? Arte em 300 DPI, em arquivo que a gente confere.</div>
|
||
<div class="in">
|
||
<span class="lg">DTF têxtil · 57 cm</span>
|
||
<p>Cada arte num arquivo. Montamos a folha com o melhor encaixe.</p>
|
||
<ul><li>Sugerimos a largura que rende mais</li><li>Sobreposição não acontece</li>
|
||
<li>Montagem inclusa · R$ 10,00 no metro</li></ul>
|
||
<span class="go">Enviar minhas artes ›</span>
|
||
</div>
|
||
</button>
|
||
|
||
<button class="ec u" data-modo="uvfile">
|
||
<div class="top"><h3>Arquivo por metro · UV</h3><span class="p"><i>tabela</i>R$ 85,90<small>/m</small></span></div>
|
||
<div class="chama2">Quer pagar <b>R$ 69,90</b>? Arte em 300 DPI, em arquivo que a gente confere.</div>
|
||
<div class="in">
|
||
<span class="lg">Adesivo UV · 28,5 cm</span>
|
||
<p>Sua folha de UV montada. Revisamos, corrigimos e reencaixamos.</p>
|
||
<ul><li>Arquivo bom paga o mínimo</li><li>Remanejamos e sua folha encolhe</li>
|
||
<li>Rígido: caneca, garrafa, case</li></ul>
|
||
<span class="go">Enviar minha folha de UV ›</span>
|
||
</div>
|
||
</button>
|
||
|
||
<button class="ec u" data-modo="uv">
|
||
<div class="top"><h3>Artes avulsas · UV</h3><span class="p"><i>tabela</i>R$ 99,90<small>/m</small></span></div>
|
||
<div class="chama2">Quer pagar <b>R$ 83,90</b>? Arte em 300 DPI, em arquivo que a gente confere.</div>
|
||
<div class="in">
|
||
<span class="lg">Adesivo UV · 28,5 cm</span>
|
||
<p>Cada arte num arquivo. Montamos a folha de UV com o melhor encaixe.</p>
|
||
<ul><li>Sugerimos a largura que rende mais</li><li>Montagem inclusa</li>
|
||
<li>Não precisa de prensa</li></ul>
|
||
<span class="go">Enviar minhas artes de UV ›</span>
|
||
</div>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- painel focado -->
|
||
<div class="foco" id="foco">
|
||
<button class="voltar" id="bVoltar"><span>‹</span>Trocar de produto</button>
|
||
<div class="focoGrid">
|
||
<div class="cat" id="catFoco">
|
||
<div class="cabfoco" style="padding:20px 22px 14px;margin:0">
|
||
<div><h3 id="fTit">—</h3><span class="lg" id="fLg" style="display:block"></span></div>
|
||
<span class="pr2" id="fPreco"></span>
|
||
<p id="fSub"></p>
|
||
</div>
|
||
<div class="in" style="padding:0 22px 22px">
|
||
<div class="foco2" id="foco2">
|
||
<div class="fila">
|
||
<div class="trocouCam" id="trocouCam" style="display:none"></div>
|
||
<div class="trocarModo" id="trocarParaAvulsa" hidden>
|
||
<b>PNG e JPG entram como artes avulsas.</b> Informe largura e quantidade;
|
||
montamos a folha, com o preço de artes avulsas.
|
||
<label><input type="checkbox" id="imagemComoFolha">
|
||
Minha imagem já é uma folha montada de <span id="larguraFolhaPronta">57</span> cm
|
||
· usar o preço de arquivo por metro</label>
|
||
</div>
|
||
<div class="caminhos" id="caminhos">
|
||
<button class="cam on" data-cam="auto">
|
||
<span class="mk2"></span>
|
||
<div><b>PNG, JPG ou PDF</b>
|
||
<span>Conferimos sozinhos e a nota desconta no metro</span>
|
||
<em id="camA">—</em></div>
|
||
</button>
|
||
<button class="cam" data-cam="tabela">
|
||
<span class="mk2"></span>
|
||
<div><b>CDR, AI, PSD ou TIFF</b>
|
||
<span>Ninguém consegue conferir · alguém abre na mão</span>
|
||
<em id="camB" class="cheio">—</em></div>
|
||
</button>
|
||
</div>
|
||
<div class="zona" id="zona" tabindex="0" role="button">
|
||
<div class="ico">↑</div>
|
||
<b id="zTit">Arraste aqui</b><span id="zSub"></span>
|
||
<span class="bt">ou escolher no computador</span>
|
||
</div>
|
||
<div class="recusa" id="recusa" style="display:none"></div>
|
||
<div id="lista"></div>
|
||
<div class="resumoA" id="rA" style="display:none"></div>
|
||
<input type="file" id="inp" hidden>
|
||
<div class="aoVivo" id="aoVivo"></div>
|
||
</div>
|
||
<aside class="mont" id="mont">
|
||
<div class="montcab"><b id="montcabTit">Montagem ao vivo</b>
|
||
<div class="zoomB"><button id="zMenos" title="Diminuir">−</button>
|
||
<span id="zTxt">100%</span>
|
||
<button id="zMais" title="Aumentar">+</button></div>
|
||
<span id="vMt">—</span></div>
|
||
<div id="vArea"></div>
|
||
<div id="vUso"></div>
|
||
<p class="montpe">Prévia aproximada. No servidor o encaixe é refeito do zero —
|
||
o resultado sai igual ou melhor, nunca pior.</p>
|
||
|
||
</aside>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<aside class="req" id="req">
|
||
<h3 class="reqcab">O que devo saber<br>sobre a arte</h3>
|
||
|
||
<details open>
|
||
<summary>Como pagar o menor metro</summary>
|
||
<ul>
|
||
<li class="s"><b>300 DPI no tamanho que vai imprimir.</b> É a nota máxima
|
||
e o menor preço da tabela</li>
|
||
<li class="s"><b>O tamanho manda mais que o arquivo.</b> A mesma arte passa
|
||
em 20 cm e não passa em 40. Reduzir um pouco costuma pular uma faixa
|
||
de preço inteira</li>
|
||
<li class="s"><b>Larguras parecidas rendem mais.</b> Se as suas artes têm
|
||
medidas próximas, cabem mais por fileira e a folha encolhe</li>
|
||
</ul>
|
||
<p class="obs2">Resolução é a única coisa que mexe no preço — porque é a
|
||
única que a gente não consegue melhorar por você.</p>
|
||
</details>
|
||
|
||
<details>
|
||
<summary>O que arrumamos sem cobrar</summary>
|
||
<ul>
|
||
<li class="s"><b>Artes coladas.</b> Separamos com 5 mm, sem você refazer nada</li>
|
||
<li class="s"><b>Encaixe mal aproveitado.</b> Remanejamos e a sua folha
|
||
encolhe — você paga menos metro do que enviou</li>
|
||
<li class="s"><b>Peça passando da largura.</b> Remanejamos em vez de cortar</li>
|
||
<li class="s"><b>Margem.</b> Não precisa deixar. Só respeitar a largura do filme</li>
|
||
</ul>
|
||
</details>
|
||
|
||
<details>
|
||
<summary>Manda em PNG e sai na hora</summary>
|
||
<ul>
|
||
<li class="s"><b>PNG ou JPG</b> com fundo transparente entram direto, sem passar
|
||
por ninguém, e não têm limite de comprimento. Só que a gente lê a resolução
|
||
<b>do arquivo</b>: se a arte foi ampliada antes de exportar, isso não aparece
|
||
para nós — e sai serrilhado no filme do mesmo jeito</li>
|
||
<li class="s"><b>PDF é o que conferimos melhor.</b> Nele medimos a resolução de
|
||
cada imagem dentro da folha, uma por uma. Se a sua arte é boa, é onde a nota
|
||
aparece com mais precisão</li>
|
||
<li class="a"><b>PDF só até 5 m.</b> O limite é do próprio formato: a página do PDF
|
||
para em 508 cm. Acima disso o arquivo sai fora do padrão e só abre certo em quem
|
||
o gerou — divida em partes ou mande PNG</li>
|
||
<li class="a"><b>TIFF, PSD, AI e CDR</b> a gente aceita, mas ninguém consegue
|
||
conferir sozinho: alguém abre na mão, sai mais devagar e o metro vai pela
|
||
tabela, sem desconto de nota</li>
|
||
<li class="a">Em <b>artes avulsas</b> só PNG e JPG: a montagem precisa
|
||
enxergar a sua arte para encaixar pela forma</li>
|
||
</ul>
|
||
</details>
|
||
|
||
<details>
|
||
<summary>O que só você resolve</summary>
|
||
<ul>
|
||
<li class="n"><b>Fundo branco ou colorido.</b> Precisa ser transparente de
|
||
verdade — branco parecendo transparente sai branco no filme</li>
|
||
<li class="n"><b>Pontinho de recorte.</b> A impressora enxerga qualquer
|
||
resíduo e imprime. Não existe pequeno demais</li>
|
||
<li class="n"><b>Cópias sobrepostas.</b> Duas iguais com 1 mm de diferença
|
||
saem duplicadas</li>
|
||
<li class="n"><b>Menos de 96 DPI.</b> Abaixo disso não imprimimos: sai
|
||
serrilhado a ponto de não valer o filme</li>
|
||
<li class="n"><b>Degradê de transparência</b>, comum em arte de IA. O branco
|
||
por baixo sai irregular e sai assim mesmo</li>
|
||
</ul>
|
||
</details>
|
||
</aside>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- nota -->
|
||
<div class="qual" id="qual">
|
||
<div class="qh">
|
||
<div><h3 id="qNome">sua folha</h3>
|
||
<span style="font-size:12px;color:var(--fraco)" id="qSub"></span></div>
|
||
<div style="text-align:right"><div class="pct" id="pct">—</div>
|
||
<span style="font-size:11px;color:var(--fraco)">qualidade</span></div>
|
||
</div>
|
||
<div class="qbar"><i id="qbi" style="width:0%"></i></div>
|
||
<div class="qitens" id="qitens"></div>
|
||
<div class="ciente" id="ciente">
|
||
<h4 id="cienteTit">Ressalva de resolução</h4>
|
||
<div id="cienteTxt"></div>
|
||
<label><input type="checkbox" id="cienteOk">
|
||
<span>Li e entendi. Quero imprimir assim mesmo.</span></label>
|
||
</div>
|
||
<div class="qbts">
|
||
<button class="qb chama" id="qOk">Seguir para o pedido</button>
|
||
</div>
|
||
<div id="qmsg" style="margin-top:12px;font-size:12.5px;display:none"></div>
|
||
</div>
|
||
|
||
<!-- prévia da montagem -->
|
||
<div class="prev" id="prev">
|
||
<div class="ph">
|
||
<div><h3>Como sua folha vai sair</h3>
|
||
<p id="pSub">confira antes de fechar o pedido</p></div>
|
||
<div style="text-align:right">
|
||
<div class="mt" id="pMt">—</div>
|
||
<span style="font-size:11px;color:var(--fraco)">cobrado por proporção</span></div>
|
||
</div>
|
||
<div class="pgrid">
|
||
<div class="pfolha"><div id="pArea"></div></div>
|
||
<div class="pinfo" id="pInfo"></div>
|
||
</div>
|
||
<div class="pcta">
|
||
<button class="pb p" id="pOk">Está certo, fechar o pedido</button>
|
||
<button class="pb" id="pMais">Adicionar mais artes</button>
|
||
<button class="pb" id="pVolta">Trocar o arquivo</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- carrinho -->
|
||
<div class="carr" id="carr">
|
||
|
||
<div>
|
||
<h3>Seu pedido</h3>
|
||
|
||
<div class="cxE">
|
||
<h4>Itens</h4>
|
||
<div id="itens"></div>
|
||
<div id="atual">
|
||
<div class="rot" style="margin-top:12px">Item que você está montando</div>
|
||
<div id="carrLin"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="cxE">
|
||
<h4>Seus dados</h4>
|
||
<p class="subC">A conta nasce aqui, no pagamento. O CNPJ é o mesmo da nota fiscal,
|
||
e é por ele que suas artes ficam guardadas para o próximo pedido.</p>
|
||
<div class="campos">
|
||
<div class="cp"><label>CNPJ</label>
|
||
<input id="fCnpj" inputmode="numeric" maxlength="18" placeholder="00.000.000/0000-00">
|
||
<span class="err" id="eCnpj"></span></div>
|
||
<div class="cp"><label>WhatsApp</label>
|
||
<input id="fZap" inputmode="numeric" maxlength="15" placeholder="(16) 99999-9999">
|
||
<span class="err" id="eZap"></span></div>
|
||
<div class="cp larga"><label>E-mail para a nota</label>
|
||
<input id="fMail" type="email" placeholder="voce@empresa.com.br">
|
||
<span class="err" id="eMail"></span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="cxE">
|
||
<h4>Forma de entrega</h4>
|
||
<div class="entrega" id="entrega">
|
||
<button class="opE on" data-ent="retira">
|
||
<span class="mk"></span>
|
||
<div>
|
||
<b>Retirar em Franca</b>
|
||
<span>Av. Major Elias Motta, 1281 · Jardim São Luís<br>
|
||
Segunda a sexta, das 7h às 17h</span>
|
||
</div>
|
||
<em>Grátis</em>
|
||
</button>
|
||
<button class="opE" data-ent="frete">
|
||
<span class="mk"></span>
|
||
<div>
|
||
<b>Receber em casa</b>
|
||
<span>Cotamos com a transportadora pelo seu CEP</span>
|
||
</div>
|
||
<em id="vFrete">—</em>
|
||
</button>
|
||
<div class="cep" id="cep">
|
||
<label>CEP de entrega</label>
|
||
<div class="cepL">
|
||
<input id="cepIn" inputmode="numeric" maxlength="9" placeholder="00000-000">
|
||
<button id="bCep">Calcular</button>
|
||
</div>
|
||
<p id="cepMsg"></p>
|
||
</div>
|
||
<p class="avisoE" id="avisoE"></p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<aside class="resumo">
|
||
<h4>Resumo da compra</h4>
|
||
<div id="resLin"></div>
|
||
<div class="tot"><span>Total</span><b id="carrTot">R$ 0,00</b></div>
|
||
<div class="cbts">
|
||
<button id="bPagar">Ir para o pagamento</button>
|
||
<button id="bMais" class="sec">Adicionar outro produto</button>
|
||
</div>
|
||
<p id="checkoutStatus" class="avisoE" role="status" aria-live="polite"></p>
|
||
<div id="checkoutActions"></div>
|
||
<p class="obs">A nota fiscal sai no CNPJ informado. O arquivo fica guardado por 90 dias e o histórico
|
||
do pedido por 12 meses, para você repetir sem subir de novo.</p>
|
||
</aside>
|
||
|
||
</div>
|
||
</div></section>
|
||
|
||
<!-- INFORMAÇÃO EM CARROSSEL -->
|
||
<section id="info"><div class="w">
|
||
<div class="et">Como funciona</div>
|
||
<h2>Tudo o que você precisa saber, <em>em cinco cartões</em></h2>
|
||
|
||
<div class="carro">
|
||
<div class="trilho" id="trilho">
|
||
|
||
<div class="slide">
|
||
<div class="stop">
|
||
<div class="sinfo"><span class="et2">Preço</span><h3>Arte melhor,<br>metro mais barato</h3></div>
|
||
<div class="selo"><i></i><b>−25<em>%</em></b><span>no metro</span></div>
|
||
</div>
|
||
<p>Vale nos quatro produtos. Preço da folha que você monta:</p>
|
||
<table>
|
||
<tr><td class="cab">nota</td><td class="cab">têxtil</td><td class="cab">UV</td></tr>
|
||
<tr><td>90–100</td><td>R$ 14,90</td><td>R$ 69,90</td></tr>
|
||
<tr><td>75–89</td><td>R$ 16,20</td><td>R$ 73,90</td></tr>
|
||
<tr><td>60–74</td><td>R$ 17,50</td><td>R$ 77,90</td></tr>
|
||
<tr><td>40–59</td><td>R$ 18,70</td><td>R$ 81,90</td></tr>
|
||
<tr><td>abaixo de 40</td><td>R$ 19,90</td><td>R$ 85,90</td></tr>
|
||
</table>
|
||
<div class="dest">Se a montagem for nossa, some <b>R$ 10,00</b> no têxtil e
|
||
<b>R$ 14,00</b> no UV — mesma escada, em qualquer faixa</div>
|
||
</div>
|
||
|
||
<div class="slide">
|
||
<div class="stop">
|
||
<div class="sinfo"><span class="et2">Largura</span><h3>O dobro do<br>filme padrão</h3></div>
|
||
<div class="selo"><i></i><b>57<em>cm</em></b><span>de filme</span></div>
|
||
</div>
|
||
<p>A maioria trabalha com 28,5 cm. Na nossa largura cabe o dobro de arte
|
||
por metro corrido — e o metro sai mais barato por peça.</p>
|
||
<ul>
|
||
<li>Duas artes de 28 cm lado a lado</li>
|
||
<li>Menos emenda, menos corte</li>
|
||
<li>DTF UV também disponível, em 28,5 cm</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="slide">
|
||
<div class="stop">
|
||
<div class="sinfo"><span class="et2">Encaixe</span><h3>Reencaixamos<br>sua folha de graça</h3></div>
|
||
<div class="selo"><i></i><b>grátis</b><span>reencaixe</span></div>
|
||
</div>
|
||
<p>Se a sua montagem deixa espaço sobrando, refazemos o encaixe com o mesmo
|
||
motor que usamos nas nossas montagens.</p>
|
||
<ul>
|
||
<li>Artes que se tocam, separadas com 5 mm</li>
|
||
<li>Giramos as peças para aproveitar a largura</li>
|
||
<li>A folha encolhe e a sua conta diminui</li>
|
||
</ul>
|
||
<div class="dest">Refazemos o encaixe <b>antes de imprimir</b>, sem cobrar nada</div>
|
||
</div>
|
||
|
||
<div class="slide">
|
||
<div class="stop">
|
||
<div class="sinfo"><span class="et2">Cobrança</span><h3>Você paga<br>o que usa</h3></div>
|
||
<div class="selo"><i></i><b>10<em>cm</em></b><span>de cada vez</span></div>
|
||
</div>
|
||
<p>Arredondamos a cada 10 cm. Uma folha de 2,75 m custa 2,80 m — quem cobra
|
||
metro cheio cobraria 3.</p>
|
||
<ul>
|
||
<li>Pedido mínimo de 1 metro</li>
|
||
<li>A identificação do pedido é por nossa conta</li>
|
||
<li>Sem taxa de arquivo, sem taxa de revisão</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="slide">
|
||
<div class="stop">
|
||
<div class="sinfo"><span class="et2">Sem burocracia</span><h3>Conta só na<br>hora de pagar</h3></div>
|
||
<div class="selo"><i></i><b>0</b><span>conta e senha</span></div>
|
||
</div>
|
||
<p>Sobe a arte e vê o preço sem conta nenhuma. A conta nasce no pagamento, junto com o CNPJ da nota — e o próximo pedido já vem com suas artes anteriores. A revisão de 5 pontos vem junto —
|
||
há quem cobre R$ 19,90 por pedido só por isso.</p>
|
||
<ul>
|
||
<li>Sem cadastro para subir e ver o preço</li>
|
||
<li>Envio em até 24 horas</li>
|
||
<li>WhatsApp a cada etapa do pedido</li>
|
||
<li>Arquivo guardado 90 dias · histórico 12 meses</li>
|
||
</ul>
|
||
</div>
|
||
|
||
</div>
|
||
<div class="navc">
|
||
<button id="cAnt" aria-label="Anterior">‹</button>
|
||
<button id="cPro" aria-label="Próximo">›</button>
|
||
<div class="pontos" id="cPontos"></div>
|
||
</div>
|
||
</div>
|
||
</div></section>
|
||
|
||
<footer><div class="w">
|
||
<div class="frow">
|
||
<span class="fmarca"><img src="https://cdn.vnda.com.br/dropstar/2025/12/17/logo-header-15125700-16129080.png?v=1766009286" alt="Dropstar">DTF</span>
|
||
<div class="flinks">
|
||
<a href="https://www.dropstaratacado.com.br" target="_blank" rel="noopener">Loja de atacado</a>
|
||
<a href="https://www.dropstaratacado.com.br/p/termos" target="_blank" rel="noopener">Trocas e privacidade</a>
|
||
<a href="https://www.dropstaratacado.com.br/p/atendimento" target="_blank" rel="noopener">Fale conosco</a>
|
||
<a href="https://www.instagram.com/dropstar.ofc/" target="_blank" rel="noopener">Instagram</a>
|
||
</div>
|
||
<div class="fcont">
|
||
<a href="https://wa.me/message/NJ76CLIOUGXLB1" target="_blank" rel="noopener">16 99428-0056</a>
|
||
· arquivos 16 99230-2546<br>
|
||
<a href="mailto:atendimentodropstar@gmail.com">atendimentodropstar@gmail.com</a><br>
|
||
Segunda a sexta, 07h às 17h
|
||
</div>
|
||
</div>
|
||
<div class="fbase">
|
||
<span>© Dropstar Atacado · CNPJ 55.786.635/0001-58 · Franca-SP</span>
|
||
<span>Visa · Master · Elo · Amex · Pix · Boleto</span>
|
||
<span>têxtil 57 cm · UV 28,5 cm</span>
|
||
</div>
|
||
</div></footer>
|
||
|
||
<script>
|
||
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';
|
||
|
||
// ── modos
|
||
const MODOS={
|
||
file: {tit:'Arquivo por metro', lg:'DTF têxtil · 57 cm', larg:57,
|
||
preco:'tabela R$ 19,90/m · até R$ 14,90', 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:'tabela R$ 29,90/m · até R$ 24,90', multi:true,
|
||
sub:'Cada arte num arquivo. Montamos a folha com o melhor encaixe.',
|
||
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:'tabela R$ 85,90/m · até R$ 69,90', 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:'tabela R$ 99,90/m · até R$ 83,90', multi:true,
|
||
sub:'Cada arte de UV num arquivo. Montamos a folha com o melhor encaixe.',
|
||
zt:'Arraste suas artes de UV',
|
||
zs:'PNG ou JPG com fundo transparente · informe a largura de cada arte'}
|
||
};
|
||
// Quatro escadas. A de artes avulsas e a da folha pronta mais a montagem:
|
||
// R$ 10,00 no têxtil, R$ 14,00 no UV, constante em todas as faixas.
|
||
const FAIXAS={
|
||
file: [[90,14.90],[75,16.20],[60,17.50],[40,18.70],[0,19.90]],
|
||
avulsa:[[90,24.90],[75,26.20],[60,27.50],[40,28.70],[0,29.90]],
|
||
uvfile:[[90,69.90],[75,73.90],[60,77.90],[40,81.90],[0,85.90]],
|
||
uv: [[90,83.90],[75,87.90],[60,91.90],[40,95.90],[0,99.90]]
|
||
};
|
||
const TABELA={file:19.90, avulsa:29.90, uvfile:85.90, uv:99.90}; // teto de cada escada
|
||
const MONTAGEM={avulsa:10.00, uv:14.00}; // o que a montagem soma sobre a folha pronta
|
||
const ehFolha=m=>!!MODOS[m||modo].folha;
|
||
const pisoEscada=m=>FAIXAS[m||modo][0][1];
|
||
const MINIMO_M=1, GAP_CM=0.5, RODAPE_CM=5;
|
||
const RENDERIZA=/[.](png|jpe?g|webp|gif|bmp)$/i;
|
||
// Folha pronta: dá para medir PNG, JPG e PDF. PSD, AI, TIFF e CDR entram, mas
|
||
// o navegador não abre — o cliente informa o comprimento e o arquivo passa por
|
||
// tratamento antes de imprimir.
|
||
const ACEITA={
|
||
folha: /[.](png|jpe?g|tiff?|pdf|psd|psb|ai|cdr)$/i,
|
||
avulsa: /[.](png|jpe?g|webp)$/i
|
||
};
|
||
const MEDE=/[.](png|jpe?g|webp|gif|bmp|pdf)$/i;
|
||
const DPI_RECUSA=96, DPI_AVISA=300; // régua dos designers · 02/09/2026
|
||
// A especificação do PDF limita a página a 14.400 unidades — 200 pol, 508 cm.
|
||
// Passar disso só é válido com UserUnit (PDF 1.6+), que a maioria dos programas
|
||
// não escreve: o arquivo sai fora do padrão e só o gerador lê direito.
|
||
const PDF_MAX_PT=14400, PT_CM=2.54/72;
|
||
const extDe=n=>(n.split('.').pop()||'').toUpperCase();
|
||
let CLIENTE='SEU NOME AQUI', PEDIDO='000000';
|
||
|
||
let modo=null, artes=[], recemChegada=null, metros=0, nota=0, reencaixado=false;
|
||
let folhas=[]; // [{f, med, rep, m}] · o cliente pode subir várias
|
||
const folhaTotalM=()=>folhas.reduce((t,x)=>t+(x.m||0)*(x.rep||1),0);
|
||
let montagemCm=0; // altura da folha montada pelo motor, em cm
|
||
const ZOOMS=[1,1.5,2,3,4]; let zoomI=0; // ampliação da montagem ao vivo
|
||
let pedido=[]; // itens já fechados · o pagamento é um só
|
||
// A escolha de entrega vale para o pedido inteiro, não por item. No Tiny, retirada
|
||
// grava forma_envio X, transportador DropStar e frete por conta do remetente — igual
|
||
// ao que a expedição já recebe hoje, sem criar processo novo.
|
||
let entrega={tipo:'retira', cep:'', valor:0, cotado:true};
|
||
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){
|
||
const d=(v||'').replace(/\D/g,'');
|
||
if(d.length!==14 || /^(\d)\1{13}$/.test(d)) return false;
|
||
const calc=(base,pesos)=>{
|
||
const soma=base.split('').reduce((t,n,i)=>t+ +n*pesos[i],0);
|
||
const r=soma%11; return r<2? 0 : 11-r;
|
||
};
|
||
const p1=[5,4,3,2,9,8,7,6,5,4,3,2], p2=[6,...p1];
|
||
return calc(d.slice(0,12),p1)===+d[12] && calc(d.slice(0,13),p2)===+d[13];
|
||
}
|
||
const zapOk=v=>{ const d=(v||'').replace(/\D/g,''); return d.length===10||d.length===11; };
|
||
const mailOk=v=>/^[^\s@]+@[^\s@]+\.[a-z]{2,}$/i.test((v||'').trim());
|
||
const clienteOk=()=>cnpjOk(cliente.cnpj)&&zapOk(cliente.zap)&&mailOk(cliente.mail);
|
||
const larguraFilme=()=>MODOS[modo].larg;
|
||
// cobrança proporcional: arredonda para cima em 10 cm · 2,75 m vira 2,80 m
|
||
const cobrar=m=>Math.max(MINIMO_M, Math.ceil(m*10)/10);
|
||
const fmtM=m=>m.toFixed(2).replace('.',',');
|
||
const precoBase=n=>
|
||
(FAIXAS[modo].find(f=>n>=f[0])||FAIXAS[modo][FAIXAS[modo].length-1])[1];
|
||
const descontoMetragem=()=>0; // sem progressão por quantidade
|
||
const cls=n=>n>=85?'ok':n>=50?'av':'er';
|
||
const dpiDe=a=>a.cm>0? a.px/(a.cm/2.54) : 0;
|
||
// girar 90° inverte a proporção · espelhar não muda medida, só o desenho
|
||
const propDe=a=>{ const p=a.prop||1; return a.giro? 1/p : p; };
|
||
const TAMANHOS={57:[10,15,20,25,28.2], 28.5:[5,8,10,14,28.2]};
|
||
const px=f=>Math.round(Math.min(6000,Math.max(600,Math.sqrt(f.size/1024)*95)));
|
||
|
||
// ── escolha
|
||
document.querySelectorAll('.ec').forEach(b=>b.addEventListener('click',()=>abrir(b.dataset.modo)));
|
||
document.querySelectorAll('[data-modo-cta]').forEach(b=>b.addEventListener('click',e=>{
|
||
e.preventDefault(); abrir(b.dataset.modoCta);
|
||
}));
|
||
function abrir(m){
|
||
modo=m; artes=[]; folhas=[]; metros=0; nota=0; reencaixado=false;
|
||
montagemCm=0;
|
||
$('imagemComoFolha').checked=false;
|
||
$('imagemComoFolha').disabled=false;
|
||
pintaModo();
|
||
$('lista').innerHTML=''; $('rA').style.display='none'; recusa([]);
|
||
recemChegada=null; caminho='auto'; avisoCam(''); pintaCaminhos();
|
||
$('vMt').textContent='—'; previaAoVivo(); agendaAvaliacao();
|
||
limpaPaineis(); // o carrinho só some se o pedido estiver vazio
|
||
$('foco').scrollIntoView({behavior:'smooth',block:'start'});
|
||
}
|
||
function pintaModo(){
|
||
const m=modo;
|
||
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;
|
||
$('inp').multiple=c.multi;
|
||
$('inp').accept = ehFolha(m) ? '.png,.jpg,.jpeg,.pdf'
|
||
: '.png,.jpg,.jpeg,.webp';
|
||
$('catFoco').className='cat '+(ehFolha(m)?'file':'av');
|
||
$('trocarParaAvulsa').hidden=!ehFolha(m);
|
||
$('larguraFolhaPronta').textContent=String(c.larg).replace('.',',');
|
||
$('foco2').classList.remove('sofila'); // a caixa de requisitos vale nos 4 modos
|
||
$('montcabTit').textContent = ehFolha(m) ? 'Sua folha' : 'Montagem ao vivo';
|
||
}
|
||
$('bVoltar').addEventListener('click',()=>{
|
||
itemAtual=null; $('atual').style.display='none'; $('carrLin').innerHTML=''; pintaPedido();
|
||
$('foco').classList.remove('on'); $('cards').style.display='';
|
||
['qual','prev'].forEach(id=>$(id).classList.remove('on'));
|
||
if(!pedido.length) $('carr').classList.remove('on');
|
||
document.getElementById('envio').scrollIntoView({behavior:'smooth'});
|
||
});
|
||
|
||
// ── upload
|
||
// Untrusted filenames and recovered cart text must never become HTML.
|
||
function escapeHTML(value){
|
||
return String(value).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
||
}
|
||
function recusa(lista){
|
||
const el=$('recusa'); if(!el) return;
|
||
if(!lista.length){ el.style.display='none'; el.innerHTML=''; return; }
|
||
const exts=escapeHTML([...new Set(lista.map(f=>extDe(f.name)))].join(', '));
|
||
el.style.display='block';
|
||
el.innerHTML = ehFolha()
|
||
? '<b>'+exts+' não dá para enviar aqui.</b> A folha pronta aceita PNG, JPG, TIFF, '+
|
||
'PDF, PSD, AI e CDR.'
|
||
: '<b>'+exts+' não dá para enviar aqui.</b> Artes avulsas precisam de PNG ou JPG com '+
|
||
'fundo transparente — é o que a montagem enxerga para encaixar. '+
|
||
'Se o seu arquivo é CDR, AI ou PSD, exporte em PNG ou use <b>Arquivo por metro</b>.';
|
||
}
|
||
const Z=$('zona'), I=$('inp');
|
||
Z.addEventListener('click',()=>I.click());
|
||
Z.addEventListener('keydown',e=>{if(e.key==='Enter'||e.key===' '){I.click();e.preventDefault();}});
|
||
['dragover','dragenter'].forEach(ev=>Z.addEventListener(ev,e=>{e.preventDefault();Z.classList.add('sobre')}));
|
||
['dragleave','drop'].forEach(ev=>Z.addEventListener(ev,e=>{
|
||
e.preventDefault(); Z.classList.remove('sobre');
|
||
if(ev==='drop') sel([...e.dataTransfer.files]);
|
||
}));
|
||
I.addEventListener('change',()=>sel([...I.files]));
|
||
function sel(fs){
|
||
if(!fs.length) return;
|
||
// Pixels cannot tell a loose artwork from a finished sheet. Images default
|
||
// to the artwork model unless the customer explicitly declares a ready sheet.
|
||
// Update this same editor in place; do not reopen it or discard uploaded files.
|
||
if(ehFolha() && !$('imagemComoFolha').checked && fs.some(f=>ACEITA.avulsa.test(f.name))){
|
||
if(fs.some(f=>!ACEITA.avulsa.test(f.name))){
|
||
$('recusa').style.display='block';
|
||
$('recusa').textContent='Envie artes avulsas e folhas prontas separadamente. Para uma imagem já montada, marque a opção de folha pronta.';
|
||
return;
|
||
}
|
||
modo=modo==='uvfile'?'uv':'avulsa';
|
||
pintaModo(); pintaCaminhos();
|
||
}
|
||
const regra = ehFolha() ? ACEITA.folha : ACEITA.avulsa;
|
||
const fora = fs.filter(f=>!regra.test(f.name));
|
||
fs = fs.filter(f=>regra.test(f.name));
|
||
recusa(fora);
|
||
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('<b>Trocamos o caminho para você.</b> 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('<b>Boa notícia.</b> 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}));
|
||
$('imagemComoFolha').checked=true;
|
||
folhas=folhas.concat(novas); // soma, não substitui
|
||
pintaFolha();
|
||
novas.forEach(x=>{
|
||
x.pct=5; pintaFolha();
|
||
medirFolha(x.f).then(md=>{
|
||
x.med=md; if(md) x.m=md.alt/100; x.pct=55; pintaFolha();
|
||
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'; }
|
||
catch(e){} }
|
||
x.pct=null; pintaFolha();
|
||
});
|
||
}else if(md && /\.pdf$/i.test(x.f.name)){
|
||
x.pct=70; pintaFolha();
|
||
rasterizarPdf(x.f, md.larg, md.alt).then(r=>{
|
||
if(r && r.erro){
|
||
x.semAnalise = r.erro + (r.semWorker
|
||
? ' · este navegador não deixa o leitor rodar em segundo plano'
|
||
: '');
|
||
}
|
||
if(r && r.tela){
|
||
try{
|
||
x.an=analisarFolha(r.tela, md.larg);
|
||
// vetor puro não tem resolução · nota máxima, e está certo
|
||
x.an.dpi = r.dpi==null ? DPI_AVISA : r.dpi;
|
||
x.an.vetor = r.dpi==null;
|
||
x.an.fonteDpi = r.dpi==null ? 'vetor' : 'imagens';
|
||
x.an.res = r.res || null;
|
||
}catch(e){}
|
||
}
|
||
x.pct=null; pintaFolha();
|
||
});
|
||
}else{ x.pct=null; pintaFolha(); }
|
||
});
|
||
});
|
||
return;
|
||
}
|
||
const novos=fs.map(f=>({f,px:px(f),cm:0,q:1,prop:1,giro:0,esp:false}));
|
||
artes=novos.concat(artes); // a mais recente fica no topo da fila
|
||
recemChegada=novos[0];
|
||
pintaArtes();
|
||
$('lista').scrollIntoView({behavior:'smooth',block:'nearest'});
|
||
Promise.all(novos.map(medir)).then(pintaArtes);
|
||
}
|
||
function medir(a){
|
||
return carregarImagem(a.f).then(img=>{
|
||
if(img){ a.prop=img.height/img.width; a.px=img.width; a.src=img.src; } else a.prop=a.prop||1;
|
||
return a;
|
||
});
|
||
}
|
||
// A metragem sai do arquivo, nunca do peso em bytes.
|
||
// imagem → proporção da imagem aplicada à largura do filme
|
||
// PDF → MediaBox da primeira página, em pontos (1 pt = 1/72 pol)
|
||
// TIFF, PSD, AI, CDR → o navegador não abre; o cliente informa o comprimento
|
||
// ── Análise real da folha: lê o canal alfa, separa cada ilha de arte e mede.
|
||
// Grade de 1 mm. Só roda em arquivo que o navegador abre; PDF precisa do servidor.
|
||
const MM=0.1; // grade fina: 1 mm
|
||
const CELULAS_MAX=1200000; // teto de custo da análise
|
||
// Folha grande vira grade mais grossa. Sem isso, 57 x 480 cm dá 2,7 milhões de
|
||
// células e o navegador congela antes de terminar.
|
||
function passoDe(larguraCm, alturaCm){
|
||
const fino=(larguraCm/MM)*(alturaCm/MM);
|
||
return fino<=CELULAS_MAX ? MM : MM*Math.sqrt(fino/CELULAS_MAX);
|
||
}
|
||
|
||
// Dilata a máscara em r células · usada para agrupar por distância real, não por caixa
|
||
function inchar(bits,cw,ch,r){
|
||
const a=new Uint8Array(cw*ch), b=new Uint8Array(cw*ch);
|
||
for(let y=0;y<ch;y++){ const o=y*cw;
|
||
for(let x=0;x<cw;x++){ if(!bits[o+x]) continue;
|
||
const x0=Math.max(0,x-r), x1=Math.min(cw-1,x+r);
|
||
for(let k=x0;k<=x1;k++) a[o+k]=1; } }
|
||
for(let x=0;x<cw;x++)
|
||
for(let y=0;y<ch;y++){ if(!a[y*cw+x]) continue;
|
||
const y0=Math.max(0,y-r), y1=Math.min(ch-1,y+r);
|
||
for(let k=y0;k<=y1;k++) b[k*cw+x]=1; }
|
||
return b;
|
||
}
|
||
// Componentes conexos de 8 vizinhos · devolve o mapa de rótulos e quantos grupos
|
||
function grupos(bits,cw,ch){
|
||
const marca=new Int32Array(cw*ch).fill(-1), fila=new Int32Array(cw*ch);
|
||
let n=0;
|
||
for(let p0=0;p0<bits.length;p0++){
|
||
if(!bits[p0]||marca[p0]>=0) continue;
|
||
const id=n++; let ini=0,fim=0; fila[fim++]=p0; marca[p0]=id;
|
||
while(ini<fim){
|
||
const p=fila[ini++], x=p%cw, y=(p/cw)|0;
|
||
for(let dy=-1;dy<=1;dy++) for(let dx=-1;dx<=1;dx++){
|
||
const nx=x+dx, ny=y+dy;
|
||
if(nx<0||ny<0||nx>=cw||ny>=ch) continue;
|
||
const q=ny*cw+nx;
|
||
if(bits[q]&&marca[q]<0){ marca[q]=id; fila[fim++]=q; }
|
||
}
|
||
}
|
||
}
|
||
return {marca,n};
|
||
}
|
||
|
||
// ── O que a folha permite medir, e só isso.
|
||
// Peça = pixels a menos de 2 mm entre si · letras de uma palavra ficam juntas.
|
||
// Encostadas = peças que só se unem quando a folga chega a 6 mm.
|
||
const R_PECA=1, R_PERTO=2; // peça: 2 mm · aviso de encostadas: 4 mm
|
||
function analisarFolha(img, larguraCm){
|
||
const alturaCmEst=larguraCm*img.height/img.width;
|
||
const passo=passoDe(larguraCm, alturaCmEst);
|
||
const cw=Math.max(8,Math.round(larguraCm/passo));
|
||
const ch=Math.max(8,Math.round(cw*img.height/img.width));
|
||
const cv=document.createElement('canvas'); cv.width=cw; cv.height=ch;
|
||
const ctx=cv.getContext('2d',{willReadFrequently:true});
|
||
ctx.clearRect(0,0,cw,ch); ctx.drawImage(img,0,0,cw,ch);
|
||
const d=ctx.getImageData(0,0,cw,ch).data;
|
||
|
||
const bits=new Uint8Array(cw*ch);
|
||
let opacos=0;
|
||
for(let i=0,j=3;i<bits.length;i++,j+=4) if(d[j]>10){ bits[i]=1; opacos++; }
|
||
|
||
// peças: agrupa pela distância real entre pixels
|
||
const gp=grupos(inchar(bits,cw,ch,R_PECA), cw, ch);
|
||
const caixas=[];
|
||
for(let p=0;p<bits.length;p++){
|
||
if(!bits[p]) continue;
|
||
const id=gp.marca[p]; if(id<0) continue;
|
||
const x=p%cw, y=(p/cw)|0;
|
||
const c=caixas[id] || (caixas[id]={x0:x,x1:x,y0:y,y1:y,area:0,id});
|
||
if(x<c.x0)c.x0=x; if(x>c.x1)c.x1=x; if(y<c.y0)c.y0=y; if(y>c.y1)c.y1=y;
|
||
c.area++;
|
||
}
|
||
const pecasTodas=caixas.filter(Boolean);
|
||
const limRes=Math.max(1, Math.round(0.2/passo)); // 2 mm na grade em uso
|
||
const residuos=pecasTodas.filter(o=>(o.x1-o.x0)<limRes && (o.y1-o.y0)<limRes);
|
||
const artes=pecasTodas.filter(o=>!((o.x1-o.x0)<limRes && (o.y1-o.y0)<limRes));
|
||
|
||
// encostadas: peças diferentes que se unem quando a folga chega a 6 mm
|
||
const gper=grupos(inchar(bits,cw,ch,R_PERTO), cw, ch);
|
||
const porPerto=new Map();
|
||
for(let p=0;p<bits.length;p++){
|
||
if(!bits[p]) continue;
|
||
const a=gp.marca[p], b=gper.marca[p];
|
||
if(a<0||b<0) continue;
|
||
if(!porPerto.has(b)) porPerto.set(b,new Set());
|
||
porPerto.get(b).add(a);
|
||
}
|
||
let encostadas=0;
|
||
porPerto.forEach(set=>{ if(set.size>1) encostadas+=set.size; });
|
||
|
||
return {
|
||
dpi: Math.round(img.width/(larguraCm/2.54)),
|
||
artes: artes.length,
|
||
residuos: residuos.length,
|
||
encostadas,
|
||
fundoChapado: opacos/(cw*ch) > 0.985,
|
||
aproveitamento: Math.max(1,Math.min(100,Math.round(opacos/(cw*ch)*100))),
|
||
alturaCm: ch*passo,
|
||
grade: +(passo*10).toFixed(1) // mm por célula analisada
|
||
};
|
||
}
|
||
|
||
// ── PDF também é conferido: rasteriza a página e mede o DPI das imagens de dentro.
|
||
// Arte vetorial não tem resolução — nesses casos a nota é máxima, e isso é correto.
|
||
const PDFJS_URL='https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js';
|
||
const PDFJS_WORKER='https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
|
||
let pdfLibP=null, temWorker=null;
|
||
// Alguns navegadores e iframes bloqueiam Worker de blob. Descobrimos antes de
|
||
// tentar, porque sem worker o PDF é lido na thread principal e precisa de outra
|
||
// estratégia: grade mais grossa e mais tempo.
|
||
function testaWorker(url){
|
||
try{ const w=new Worker(url); w.terminate(); return true; }catch(e){ return false; }
|
||
}
|
||
function carregarPdfJs(){
|
||
if(typeof window==='undefined') return Promise.resolve(null);
|
||
if(window.pdfjsLib) return Promise.resolve(window.pdfjsLib);
|
||
if(pdfLibP) return pdfLibP;
|
||
pdfLibP=new Promise(res=>{
|
||
const sc=document.createElement('script');
|
||
sc.src=PDFJS_URL;
|
||
sc.onload=()=>{
|
||
try{
|
||
const codigo='importScripts("'+PDFJS_WORKER+'");';
|
||
const url=URL.createObjectURL(new Blob([codigo],{type:'application/javascript'}));
|
||
temWorker=testaWorker(url);
|
||
window.pdfjsLib.GlobalWorkerOptions.workerSrc = temWorker? url : PDFJS_WORKER;
|
||
}catch(e){
|
||
temWorker=false;
|
||
try{ window.pdfjsLib.GlobalWorkerOptions.workerSrc=PDFJS_WORKER; }catch(e2){}
|
||
}
|
||
res(window.pdfjsLib||null);
|
||
};
|
||
sc.onerror=()=>res(null);
|
||
document.head.appendChild(sc);
|
||
});
|
||
return pdfLibP;
|
||
}
|
||
|
||
// DPI real de cada imagem embutida: acompanha a matriz de transformação e compara
|
||
// o tamanho em que a imagem foi colocada com quantos pixels ela tem.
|
||
function dpiDasImagens(page, ops){
|
||
const mul=(a,b)=>[a[0]*b[0]+a[2]*b[1], a[1]*b[0]+a[3]*b[1],
|
||
a[0]*b[2]+a[2]*b[3], a[1]*b[2]+a[3]*b[3],
|
||
a[0]*b[4]+a[2]*b[5]+a[4], a[1]*b[4]+a[3]*b[5]+a[5]];
|
||
const O=window.pdfjsLib.OPS;
|
||
let ctm=[1,0,0,1,0,0]; const pilha=[]; const dpis=[];
|
||
for(let i=0;i<ops.fnArray.length;i++){
|
||
const fn=ops.fnArray[i], ar=ops.argsArray[i];
|
||
if(fn===O.save) pilha.push(ctm.slice());
|
||
else if(fn===O.restore) ctm=pilha.pop()||[1,0,0,1,0,0];
|
||
else if(fn===O.transform) ctm=mul(ctm,ar);
|
||
else if(fn===O.paintImageXObject||fn===O.paintJpegXObject||fn===O.paintImageXObjectRepeat){
|
||
let im=null;
|
||
try{ im=page.objs.get(ar[0]); }catch(e){}
|
||
if(!im||!im.width) continue;
|
||
const larguraPt=Math.hypot(ctm[0],ctm[1]);
|
||
if(larguraPt<1) continue;
|
||
const areaPt=Math.abs(ctm[0]*ctm[3]-ctm[1]*ctm[2]);
|
||
dpis.push({dpi: im.width/(larguraPt/72), area: areaPt});
|
||
}
|
||
}
|
||
return dpis;
|
||
}
|
||
|
||
// A régua de 96 DPI vale por arte, não pela folha inteira. Numa folha de 250 peças,
|
||
// um selo pequeno em 65 DPI não pode barrar o pedido: o que decide é quanto da
|
||
// área impressa está abaixo do limite.
|
||
function resumoDpi(lista){
|
||
if(!lista.length) return null;
|
||
const total=lista.reduce((t,x)=>t+x.area,0) || 1;
|
||
const abaixoPiso=lista.filter(x=>x.dpi<DPI_RECUSA);
|
||
const abaixoAviso=lista.filter(x=>x.dpi<DPI_AVISA);
|
||
const pond=lista.reduce((t,x)=>t+x.dpi*x.area,0)/total;
|
||
return {
|
||
pior: Math.round(Math.min(...lista.map(x=>x.dpi))),
|
||
ponderado: Math.round(pond),
|
||
fracBaixa: abaixoPiso.reduce((t,x)=>t+x.area,0)/total,
|
||
fracAviso: abaixoAviso.reduce((t,x)=>t+x.area,0)/total,
|
||
quantasBaixas: abaixoPiso.length,
|
||
quantasAviso: abaixoAviso.length,
|
||
total: lista.length
|
||
};
|
||
}
|
||
|
||
// Rasteriza a primeira página a 1 mm por pixel e devolve a tela para a análise
|
||
function rasterizarPdf(file, larguraCm, alturaCm){
|
||
let motivo=null;
|
||
const trabalho=carregarPdfJs().then(lib=>{
|
||
if(!lib){ motivo='não foi possível carregar o leitor de PDF'; return null; }
|
||
// sem worker tudo roda na thread principal · grade mais grossa para caber
|
||
const folga = temWorker===false ? 2.2 : 1;
|
||
return file.arrayBuffer().then(buf=>lib.getDocument({
|
||
data:buf, disableFontFace:true, isEvalSupported:false, useSystemFonts:false,
|
||
verbosity:0 // sem worker é fallback, não erro
|
||
}).promise).then(doc=>
|
||
doc.getPage(1).then(page=>{
|
||
const vp1=page.getViewport({scale:1});
|
||
const passo=passoDe(larguraCm, alturaCm||larguraCm)*folga;
|
||
const alvo=Math.max(8, Math.round(larguraCm/passo));
|
||
const esc=alvo/vp1.width;
|
||
const vp=page.getViewport({scale:esc});
|
||
const cv=document.createElement('canvas');
|
||
cv.width=Math.max(8,Math.round(vp.width)); cv.height=Math.max(8,Math.round(vp.height));
|
||
const ctx=cv.getContext('2d',{willReadFrequently:true});
|
||
return page.render({canvasContext:ctx, viewport:vp, background:'rgba(0,0,0,0)'})
|
||
.promise.then(()=>page.getOperatorList()).then(ops=>{
|
||
let dpis=[];
|
||
try{ dpis=dpiDasImagens(page,ops); }catch(e){}
|
||
const r=resumoDpi(dpis);
|
||
return {tela:cv, dpi: r? r.ponderado : null, res:r};
|
||
});
|
||
})
|
||
);
|
||
}).catch(e=>{ motivo=(e&&e.message)? e.message : 'erro ao abrir o PDF'; return null; });
|
||
// sem worker o processo é lento: damos mais tempo antes de desistir
|
||
const espera = temWorker===false ? 90000 : 30000;
|
||
const tarde=new Promise(r=>setTimeout(()=>{ motivo='demorou demais neste navegador'; r('tempo'); }, espera));
|
||
return Promise.race([trabalho, tarde]).then(r=>{
|
||
const saida = r==='tempo'? null : r;
|
||
if(!saida) return {erro: motivo||'não deu para conferir', semWorker: temWorker===false};
|
||
return saida;
|
||
});
|
||
}
|
||
|
||
function medirFolha(file){
|
||
return new Promise(res=>{
|
||
const nome=(file.name||'').toLowerCase();
|
||
if(RENDERIZA.test(nome)){
|
||
carregarImagem(file).then(img=>{
|
||
if(!img || !img.width) return res(null);
|
||
const L=larguraFilme();
|
||
res({larg:L, alt:+(img.height/img.width*L).toFixed(1), fonte:'proporção da imagem'});
|
||
});
|
||
return;
|
||
}
|
||
if(/\.pdf$/.test(nome)){
|
||
const pedaco=(inicio,fim)=>new Promise(r=>{
|
||
const fr=new FileReader();
|
||
fr.onload=()=>r(new TextDecoder('latin1').decode(new Uint8Array(fr.result)));
|
||
fr.onerror=()=>r('');
|
||
fr.readAsArrayBuffer(file.slice(inicio,fim));
|
||
});
|
||
const M=4*1048576;
|
||
Promise.all([pedaco(0,M), pedaco(Math.max(0,file.size-M), file.size)]).then(([a,b])=>{
|
||
const txt=a+b;
|
||
const re=/\/MediaBox\s*\[\s*(-?[\d.]+)\s+(-?[\d.]+)\s+(-?[\d.]+)\s+(-?[\d.]+)/;
|
||
const m=txt.match(re);
|
||
if(!m) return res(null);
|
||
// UserUnit escala a página inteira · sem ele, 1 unidade = 1/72 pol
|
||
const uu=txt.match(/\/UserUnit\s+([\d.]+)/);
|
||
const esc=uu? Math.max(1,Math.min(75000,+uu[1])) : 1;
|
||
const ptW=Math.abs(+m[3]-+m[1]), ptH=Math.abs(+m[4]-+m[2]);
|
||
if(!(ptW>0&&ptH>0)) return res(null);
|
||
const w=ptW*PT_CM*esc, h=ptH*PT_CM*esc;
|
||
// acima de 14.400 unidades sem UserUnit o arquivo está fora da especificação
|
||
const foraDoPadrao = !uu && (ptW>PDF_MAX_PT || ptH>PDF_MAX_PT);
|
||
res({larg:+w.toFixed(1), alt:+h.toFixed(1),
|
||
fonte:'página do PDF'+(uu? ' · UserUnit '+esc : ''), foraDoPadrao});
|
||
});
|
||
return;
|
||
}
|
||
res(null);
|
||
});
|
||
}
|
||
|
||
function pintaFolha(){
|
||
const L=larguraFilme();
|
||
$('imagemComoFolha').disabled=folhas.length>0;
|
||
if(!folhas.length) $('imagemComoFolha').checked=false;
|
||
if(!folhas.length){ $('lista').innerHTML=''; agendaAvaliacao(); previaAoVivo(); return; }
|
||
|
||
$('lista').innerHTML = folhas.map((x,i)=>{
|
||
const lido=!!x.med, larga=lido && x.med.larg>L+0.5, suspeito=lido && x.med.foraDoPadrao;
|
||
const sub=(x.m||0)*(x.rep||1);
|
||
let medida='';
|
||
if(lido){
|
||
const a=x.an;
|
||
const conferido = a
|
||
? '<div class="conf"><b>Conferido de verdade</b>'+
|
||
'<span>'+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')+'</span>'+
|
||
'<span>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</span></div>'
|
||
: '';
|
||
medida='<div class="med'+(larga||suspeito?' alerta':'')+'">'+
|
||
'<b>'+n1(x.med.larg)+' × '+n1(x.med.alt)+' cm</b>'+
|
||
'<span>'+x.med.fonte+' · '+fmtM(x.m)+' m de folha</span>'+
|
||
conferido+
|
||
(suspeito? '<em><b>Este PDF passa do tamanho que o formato comporta.</b> '+
|
||
'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 <b>PNG ou TIFF</b>, ou divide em partes de até 5 m, que sai na hora.</em>':'')+
|
||
(larga? '<em><b>Esta folha não roda neste filme.</b> 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 <b>DTF têxtil de 57 cm</b> — troque de produto ali em cima.'
|
||
: ' Remonte a folha em '+n1(L)+' cm e suba de novo.')+'</em>':'')+
|
||
'</div>';
|
||
}else{
|
||
const teto=TABELA[modo], piso=pisoEscada();
|
||
const dif=(x.m>0)? (teto-piso)*cobrar(x.m*(x.rep||1)) : 0;
|
||
medida='<div class="med pede">'+
|
||
'<b>'+escapeHTML(extDe(x.f.name))+' não abre no navegador</b>'+
|
||
'<span>Sem conseguir conferir o arquivo, não temos como dar nota — e sem nota '+
|
||
'o metro sai pela tabela, <b>'+rs(teto)+'</b>. Alguém vai abrir esse arquivo na mão '+
|
||
'antes de imprimir.</span>'+
|
||
'<div class="troca">Exportando a mesma folha em <b>PNG ou PDF</b>, a conferência é '+
|
||
'automática e o metro pode cair até <b>'+rs(piso)+'</b>'+
|
||
(dif>0.5? ' — <b>'+rs(dif)+' a menos</b> só nesta folha' : '')+'.</div>'+
|
||
'<span style="margin-top:9px">Informe o comprimento para seguir:</span>'+
|
||
'<input type="number" min="0.5" max="60" step="0.01" data-comp="'+i+'" '+
|
||
'placeholder="metros" value="'+(x.m? x.m.toFixed(2):'')+'">'+
|
||
'</div>';
|
||
}
|
||
const barra = x.pct!=null
|
||
? '<div class="prog"><i style="width:'+x.pct+'%"></i></div>'+
|
||
'<span class="progT">'+(x.pct<50?'lendo o arquivo…':
|
||
x.pct<70?'medindo a folha…':'conferindo a arte…')+'</span>'
|
||
: x.semAnalise
|
||
? '<div class="progF"><b>Não conseguimos conferir esta folha.</b> '+x.semAnalise+
|
||
'. Seguimos com o preço de tabela — se quiser a nota e o desconto, exporte a mesma '+
|
||
'folha em <b>PNG</b>, que a conferência é bem mais leve.</div>'
|
||
: '';
|
||
return '<div class="rep"><div class="l1"><b>'+
|
||
(folhas.length>1? (i+1)+'. ':'')+escapeHTML(x.f.name)+'</b>'+
|
||
'<span style="color:var(--fraco);font-size:10.5px">'+fmt(x.f.size)+'</span>'+
|
||
'<button data-rmf="'+i+'">×</button></div>'+
|
||
barra+medida+
|
||
(x.m>0 ?
|
||
'<div class="cps" style="margin-top:10px">'+
|
||
'<div><label>quantas vezes repetir</label>'+
|
||
'<input type="number" min="1" max="200" data-repf="'+i+'" value="'+x.rep+'"></div>'+
|
||
'<div class="conta"><b>'+fmtM(sub)+' m</b>'+
|
||
(x.rep>1? ' · '+x.rep+' × '+fmtM(x.m)+' m':'')+'</div>'+
|
||
'</div>' : '')+
|
||
'</div>';
|
||
}).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 += '<div class="somaF">'+
|
||
'<span>'+folhas.length+' folhas neste pedido</span>'+
|
||
'<b>'+fmtM(tot)+' m no total</b>'+
|
||
(partes>1? '<em>vai em '+partes+' partes de até 20 m</em>':'')+'</div>';
|
||
}else if(partes>1 && tot>0){
|
||
$('lista').innerHTML += '<div class="somaF"><span>folha longa</span>'+
|
||
'<b>'+fmtM(tot)+' m</b><em>vai em '+partes+' partes de até 20 m</em></div>';
|
||
}
|
||
|
||
$('lista').querySelectorAll('[data-rmf]').forEach(b=>b.addEventListener('click',()=>{
|
||
folhas.splice(+b.dataset.rmf,1); pintaFolha();
|
||
}));
|
||
$('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();
|
||
}));
|
||
$('lista').querySelectorAll('[data-comp]').forEach(el=>el.addEventListener('change',e=>{
|
||
folhas[+el.dataset.comp].m=Math.max(0,Math.min(60,+e.target.value||0)); pintaFolha();
|
||
}));
|
||
agendaAvaliacao(); previaAoVivo();
|
||
}
|
||
|
||
// sugestão de largura
|
||
const cabemNaLinha=w=>Math.max(1,Math.floor((larguraFilme()+GAP_CM)/(w+GAP_CM)));
|
||
const larguraPara=n=>(larguraFilme()-(n-1)*GAP_CM)/n;
|
||
// Só sugere se a folha realmente encolher. Caber mais um por fileira não adianta
|
||
// nada se a quantidade pedida continuar ocupando o mesmo número de fileiras.
|
||
function sugestao(a){
|
||
const w=a.cm, q=Math.max(1,a.q||1), prop=propDe(a);
|
||
const n=cabemNaLinha(w), alvo=Math.floor(larguraPara(n+1)*10)/10;
|
||
if(!(alvo>0) || alvo>=w) return null;
|
||
if((w-alvo)/w>0.12) return null; // não corta mais que 12% da peça
|
||
const fa=Math.ceil(q/n), fd=Math.ceil(q/(n+1));
|
||
if(fd>=fa) return null; // mesmo número de fileiras: não muda nada
|
||
const economiaCm=fa*w*prop - fd*alvo*prop;
|
||
if(economiaCm<0.5) return null; // menos de meio centímetro não é notícia
|
||
return {alvo, de:n, para:n+1, fileiras:fa-fd, cm:economiaCm};
|
||
}
|
||
// A cota em escala: o cliente ve a peca dentro da largura do filme, quantas cabem
|
||
// lado a lado e quanto sobra. Numero em texto ninguem le; retangulo todo mundo entende.
|
||
function vizPeca(a){
|
||
const BASE=300, L=larguraFilme();
|
||
const e0=BASE/L, alt0=a.cm*propDe(a)*e0;
|
||
const k = alt0>132 ? 132/alt0 : 1; // tira nunca fica alta demais
|
||
const e = e0*k;
|
||
const n=cabemNaLinha(a.cm), pw=a.cm*e, ph=a.cm*propDe(a)*e, gp=GAP_CM*e;
|
||
const sobra=L-(n*a.cm+(n-1)*GAP_CM);
|
||
const ext=escapeHTML(a.f.name.split('.').pop().toUpperCase());
|
||
let pecas='';
|
||
for(let i=0;i<n;i++) pecas+='<div class="pc" style="width:'+pw.toFixed(1)+'px;height:'+
|
||
ph.toFixed(1)+'px">'+(a.src?'<img src="'+a.src+'" alt="" style="transform:'+
|
||
(a.giro?'rotate(90deg) ':'')+(a.esp?'scaleX(-1)':'')+'">':'<span>'+ext+'</span>')+'</div>';
|
||
const Wt=(L*e+6).toFixed(1); // +6 = borda e respiro da tira
|
||
return '<div class="viz">'+
|
||
'<div class="vizRow">'+
|
||
'<div class="vizH" style="height:'+ph.toFixed(1)+'px"><span>'+n1(a.cm*propDe(a))+' cm</span></div>'+
|
||
'<div class="vizTira" style="width:'+Wt+'px">'+
|
||
'<div class="vizL"><i></i><b>'+n1(L)+' cm de filme</b><i></i></div>'+
|
||
'<div class="tira" style="height:'+ph.toFixed(1)+'px;gap:'+gp.toFixed(1)+'px">'+pecas+
|
||
(sobra>0.25?'<div class="folga"><span>sobra '+n1(sobra)+' cm</span></div>':'')+
|
||
'</div>'+
|
||
'</div>'+
|
||
'</div>'+
|
||
'<div class="vizPe"><b>'+n1(a.cm)+' cm</b> de largura · <b>'+n+
|
||
(n>1?' peças':' peça')+'</b> por fileira'+
|
||
(sobra>0.25?' · sobram <b>'+n1(sobra)+' cm</b>':' · largura toda aproveitada')+'</div>'+
|
||
'</div>';
|
||
}
|
||
const n1=v=>v.toFixed(1).replace('.',',');
|
||
|
||
function pintaArtes(){
|
||
$('lista').innerHTML=artes.map((a,i)=>{
|
||
let barra='', dica='', calc='<span>informe a largura para ver a qualidade</span>';
|
||
if(a.cm>0){
|
||
const dpi=Math.round(a.px/(a.cm/2.54)), n=Math.max(6,Math.min(100,Math.round(dpi/300*100)));
|
||
barra='<div class="qb2"><i class="'+cls(n)+'" style="width:'+n+'%"></i></div>';
|
||
calc='<span class="'+cls(n)+'"><b>'+n+'%</b> · '+dpi+' DPI</span><span>'+
|
||
a.q+' × '+n1(a.cm)+' × '+n1(a.cm*propDe(a))+' cm</span>';
|
||
const sug=sugestao(a);
|
||
dica = sug
|
||
? '<div class="dica"><b>Reduzindo para '+n1(sug.alvo)+' cm você economiza '+
|
||
n1(sug.cm)+' cm de folha</b>Passam de '+sug.de+' para '+sug.para+
|
||
' por fileira, e as suas '+a.q+' peças ocupam '+sug.fileiras+
|
||
' fileira'+(sug.fileiras>1?'s':'')+' a menos.<button data-usar="'+i+'" data-cm="'+
|
||
sug.alvo+'">Usar sugerido</button></div>'
|
||
: '';
|
||
dica = vizPeca(a) + dica;
|
||
}
|
||
return '<div class="art'+(a===recemChegada?' nova':'')+'"><div class="l1"><b>'+escapeHTML(a.f.name)+'</b>'+
|
||
'<span style="color:var(--fraco);font-size:10.5px">'+a.px+' px</span>'+
|
||
'<button data-rm="'+i+'">×</button></div><div class="cps">'+
|
||
'<div><label>largura na peça</label><input type="number" min="1" max="'+larguraFilme()+
|
||
'" placeholder="cm" data-cm="'+i+'" value="'+(a.cm||'')+'"></div>'+
|
||
'<div><label>quantas vezes</label><input type="number" min="1" placeholder="1" data-q="'+i+
|
||
'" value="'+a.q+'"></div></div>'+
|
||
'<div class="atalhos">'+
|
||
(TAMANHOS[larguraFilme()]||[]).map(t=>'<button class="tm'+
|
||
(Math.abs(a.cm-t)<0.05?' on':'')+'" data-tam="'+i+'" data-t="'+t+'">'+
|
||
n1(t)+' cm</button>').join('')+
|
||
'<span class="sep"></span>'+
|
||
'<button class="gr'+(a.giro?' on':'')+'" data-giro="'+i+'" title="Girar 90°">⟳</button>'+
|
||
'<button class="gr'+(a.esp?' on':'')+'" data-esp="'+i+'" title="Espelhar">⇋</button>'+
|
||
'</div>'+barra+'<div class="calc">'+calc+'</div>'+dica+'</div>';
|
||
}).join('');
|
||
$('lista').querySelectorAll('[data-rm]').forEach(b=>b.addEventListener('click',()=>{artes.splice(+b.dataset.rm,1);pintaArtes();}));
|
||
$('lista').querySelectorAll('[data-cm]').forEach(i=>i.addEventListener('change',()=>{artes[+i.dataset.cm].cm=+i.value||0;pintaArtes();}));
|
||
$('lista').querySelectorAll('[data-q]').forEach(i=>i.addEventListener('change',()=>{artes[+i.dataset.q].q=Math.max(1,Math.floor(+i.value||1));pintaArtes();}));
|
||
$('lista').querySelectorAll('[data-cm], [data-q]').forEach(i=>i.addEventListener('input',()=>{
|
||
const largura=i.hasAttribute('data-cm');
|
||
const a=artes[+(largura?i.dataset.cm:i.dataset.q)];
|
||
a[largura?'cm':'q']=largura?Math.max(0,+i.value||0):Math.max(1,Math.floor(+i.value||1));
|
||
previaAoVivo();
|
||
}));
|
||
$('lista').querySelectorAll('[data-usar]').forEach(b=>b.addEventListener('click',()=>{
|
||
artes[+b.dataset.usar].cm=+b.dataset.cm; pintaArtes();
|
||
}));
|
||
$('lista').querySelectorAll('[data-tam]').forEach(b=>b.addEventListener('click',()=>{
|
||
artes[+b.dataset.tam].cm=+b.dataset.t; pintaArtes();
|
||
}));
|
||
$('lista').querySelectorAll('[data-giro]').forEach(b=>b.addEventListener('click',()=>{
|
||
const a=artes[+b.dataset.giro]; a.giro=a.giro?0:90; pintaArtes();
|
||
}));
|
||
$('lista').querySelectorAll('[data-esp]').forEach(b=>b.addEventListener('click',()=>{
|
||
const a=artes[+b.dataset.esp]; a.esp=!a.esp; pintaArtes();
|
||
}));
|
||
resumoArtes();
|
||
previaAoVivo();
|
||
}
|
||
function resumoArtes(){
|
||
const r=$('rA'), prontas=artes.filter(a=>a.cm>0);
|
||
if(!prontas.length){ r.style.display='none'; return; }
|
||
const m=montagemCm/100; // a mesma folha que aparece ao lado
|
||
const notas=prontas.map(a=>Math.max(6,Math.min(100,Math.round((a.px/(a.cm/2.54))/300*100))));
|
||
const media=Math.round(notas.reduce((s,n)=>s+n,0)/notas.length), pior=Math.min(...notas);
|
||
const falta=artes.length-prontas.length;
|
||
r.style.display='block'; r.className='resumoA on';
|
||
r.innerHTML='<div class="r"><span>artes com tamanho</span><b>'+prontas.length+' de '+artes.length+'</b></div>'+
|
||
'<div class="r"><span>qualidade média</span><b style="color:'+
|
||
(media>=85?'var(--verde)':media>=50?'var(--laranja)':'var(--vermelho)')+'">'+media+'%</b></div>'+
|
||
(pior<media?'<div class="r"><span>a pior arte</span><b>'+pior+'%</b></div>':'')+
|
||
(m>0?'<div class="r"><span>folha montada</span><b>'+fmtM(m)+' m</b></div>'+
|
||
(cobrar(m)>m+0.001?'<div class="r"><span>cobrança</span><b>'+fmtM(cobrar(m))+
|
||
' m'+(cobrar(m)===MINIMO_M?' · mínimo':'')+'</b></div>':''):'')+
|
||
(falta?'<div class="r" style="color:var(--laranja)"><span>faltam informar</span><b>'+falta+'</b></div>':'');
|
||
}
|
||
|
||
// ── enviar
|
||
// Avalia sozinho conforme o cliente sobe e preenche. Devolve o que ainda falta,
|
||
// para a fila dizer em texto em vez de travar num botão.
|
||
function avaliar(){
|
||
if(ehFolha()){
|
||
if(!folhas.length) return {pronto:false, falta:'Arraste sua folha montada para começar.'};
|
||
const larga=folhas.find(x=>x.med && x.med.larg > larguraFilme()+0.5);
|
||
if(larga) return {pronto:false, falta:'A folha '+larga.f.name+' tem '+n1(larga.med.larg)+
|
||
' cm e não cabe no filme de '+n1(larguraFilme())+' cm.'};
|
||
const semMedida=folhas.filter(x=>!(x.m>0)).length;
|
||
if(semMedida) return {pronto:false, falta:'Informe o comprimento de '+semMedida+
|
||
' folha'+(semMedida>1?'s':'')+'.'};
|
||
metros=folhaTotalM();
|
||
reencaixado=false;
|
||
const ans=folhas.map(x=>x.an).filter(Boolean);
|
||
if(!ans.length){
|
||
// sem análise possível (PDF, CDR, PSD): não inventa nota
|
||
const exts=[...new Set(folhas.map(f=>extDe(f.f.name)))].join(', ');
|
||
mostraNota([
|
||
['av','Sem nota · '+exts+' não abre no navegador',
|
||
'não temos como conferir a arte antes de imprimir'],
|
||
['er','Metro pela tabela · '+rs(TABELA[modo]),
|
||
'exportando em PNG ou PDF, cai até '+rs(pisoEscada())],
|
||
['fix','Alguém abre seu arquivo','a conferência é feita na mão, na sala']
|
||
], 0, folhas.length>1? folhas.length+' folhas' : folhas[0].f.name,
|
||
larguraFilme()+' cm · '+fmtM(metros)+' m · preço de tabela');
|
||
return {pronto:true};
|
||
}
|
||
const dpi=Math.min(...ans.map(a=>a.dpi));
|
||
const n=Math.max(6,Math.min(100,Math.round(dpi/DPI_AVISA*100)));
|
||
const soma=(k)=>ans.reduce((t,a)=>t+a[k],0);
|
||
const itens=[
|
||
ans.every(a=>a.vetor)
|
||
? ['ok','Arte vetorial','sem imagem embutida · imprime em qualquer tamanho']
|
||
: [dpi>=DPI_AVISA?'ok':dpi>=DPI_RECUSA?'av':'er','Resolução '+dpi+' DPI',
|
||
ans.some(a=>a.fonteDpi==='imagens')
|
||
? 'média por área das imagens dentro do PDF · pior em '+
|
||
Math.min(...ans.map(a=>a.res? a.res.pior : a.dpi))+' DPI'
|
||
: 'resolução do arquivo · arte ampliada antes de exportar não aparece aqui'],
|
||
['ok', soma('artes')+' peças na folha',
|
||
Math.round(soma('aproveitamento')/ans.length)+'% da folha virou arte'],
|
||
soma('residuos') ? ['er','Resíduo de recorte',
|
||
soma('residuos')+' ponto'+(soma('residuos')>1?'s':'')+' abaixo de 2 mm · a impressora imprime']
|
||
: ['ok','Sem resíduo de recorte','nada solto na folha'],
|
||
soma('encostadas') ? ['fix', soma('encostadas')+' peças a menos de 5 mm',
|
||
'se forem artes diferentes, separamos com 5 mm sem custo']
|
||
: ['ok','Espaço entre peças','nenhuma abaixo de 6 mm'],
|
||
ans.some(a=>a.fundoChapado) ? ['er','Fundo chapado','a folha está sem transparência']
|
||
: ['ok','Fundo transparente','canal alfa conferido'],
|
||
null
|
||
].filter(Boolean);
|
||
mostraNota(itens, n, folhas.length>1? folhas.length+' folhas' : folhas[0].f.name,
|
||
larguraFilme()+' cm · '+fmtM(metros)+' m');
|
||
return {pronto:true};
|
||
}
|
||
if(!artes.length) return {pronto:false, falta:'Arraste suas artes para começar.'};
|
||
const sem=artes.filter(a=>!a.cm).length;
|
||
if(sem) return {pronto:false, falta:'Informe a largura de '+sem+' arte'+(sem>1?'s':'')+
|
||
' para ver a nota e o preço.'};
|
||
// metragem = altura da folha depois de montada, com os 5 mm entre peças
|
||
metros=+(montagemCm/100).toFixed(4);
|
||
if(!(metros>0)) return {pronto:false, falta:'Montando a folha…'};
|
||
const notas=artes.map(a=>Math.max(6,Math.min(100,Math.round((a.px/(a.cm/2.54))/300*100))));
|
||
const media=Math.round(notas.reduce((s,n)=>s+n,0)/notas.length), pior=Math.min(...notas);
|
||
mostraNota([
|
||
['ok','Montagem por nossa conta','5 mm garantidos'],
|
||
[cls(pior),'Pior arte em '+pior+'%',pior>=85?'todas em boa resolução':'reenviar maior sai mais barato']
|
||
],media,artes.length+' arte'+(artes.length>1?'s':''),
|
||
'folha montada por nós · '+fmtM(metros)+' m');
|
||
return {pronto:true};
|
||
}
|
||
|
||
// redesenha 220 ms depois da última mexida, para não avaliar a cada tecla
|
||
let tAval=null;
|
||
function agendaAvaliacao(){
|
||
clearTimeout(tAval);
|
||
tAval=setTimeout(()=>{
|
||
const r=avaliar();
|
||
const el=$('aoVivo');
|
||
if(!el) return;
|
||
if(r.pronto){
|
||
el.className='aoVivo pronto';
|
||
el.innerHTML='<span class="pt2"></span><span><b>Nota e preço calculados.</b> '+
|
||
'Confira abaixo e feche o pedido.</span>';
|
||
}else{
|
||
el.className='aoVivo';
|
||
el.innerHTML='<span class="pt2"></span><span>'+escapeHTML(r.falta)+'</span>';
|
||
limpaPaineis(); // o carrinho só some se o pedido estiver vazio
|
||
}
|
||
},220);
|
||
}
|
||
function mostraNota(itens,n,titulo,sub){
|
||
nota=n;
|
||
$('qual').classList.add('on');
|
||
$('qNome').textContent=titulo; $('qSub').textContent=sub;
|
||
const semNota = n===0;
|
||
$('pct').innerHTML = semNota? '—<small>/100</small>' : n+'<small>/100</small>';
|
||
const c = semNota? 'var(--fraco)' : n>=85?'var(--verde)':n>=50?'var(--laranja)':'var(--vermelho)';
|
||
$('pct').style.color=c;
|
||
$('qbi').style.width=(semNota?0:n)+'%'; $('qbi').style.background=c;
|
||
$('qitens').innerHTML=itens.map(i=>
|
||
'<div class="qi '+i[0]+'"><span class="c">'+
|
||
(i[0]==='ok'?'✓':i[0]==='av'?'!':i[0]==='fix'?'↻':'×')+'</span>'+
|
||
'<div><b>'+escapeHTML(i[1])+'</b><span>'+escapeHTML(i[2])+'</span></div></div>').join('');
|
||
$('qmsg').style.display='none';
|
||
ressalvaResolucao();
|
||
carrinho();
|
||
}
|
||
|
||
// A resolução do arquivo não é a das artes dentro dele: um PDF em 300 DPI
|
||
// pode ter uma imagem inserida em 180, e é essa que sai serrilhada.
|
||
function ressalvaResolucao(){
|
||
const box=$('ciente'), chk=$('cienteOk');
|
||
let baixas=[], geral=300, recusadas=[];
|
||
if(ehFolha()){
|
||
// Uma régua só: o número que precifica é o número que bloqueia.
|
||
// Recusa quando a média por área fica abaixo de 96 DPI — a folha inteira não
|
||
// vale o filme. Se a média passa mas há peças ruins, é ressalva com aceite.
|
||
folhas.forEach((x,k)=>{
|
||
if(!x.an) return;
|
||
const r=x.an.res, cm=x.med? x.med.larg : larguraFilme();
|
||
const nome=(folhas.length>1? (k+1)+'. ':'')+x.f.name;
|
||
const extra = r ? {pior:r.pior, de:r.total,
|
||
quantas:r.quantasBaixas, parte:Math.round(r.fracBaixa*100),
|
||
quantasAviso:r.quantasAviso, parteAviso:Math.round(r.fracAviso*100)} : {};
|
||
if(x.an.dpi<DPI_RECUSA) recusadas.push(Object.assign({nome, dpi:x.an.dpi, cm}, extra));
|
||
else if(x.an.dpi<DPI_AVISA || (r&&r.quantasAviso))
|
||
baixas.push(Object.assign({nome, dpi:x.an.dpi, cm}, extra));
|
||
});
|
||
geral = folhas.some(x=>x.an) ? Math.max(...folhas.filter(x=>x.an).map(x=>x.an.dpi)) : 300;
|
||
}else{
|
||
const comTamanho=artes.filter(a=>a.cm>0);
|
||
recusadas=comTamanho.filter(a=>dpiDe(a)<DPI_RECUSA)
|
||
.map(a=>({nome:a.f.name, dpi:Math.round(dpiDe(a)), cm:a.cm}));
|
||
baixas=comTamanho.filter(a=>dpiDe(a)>=DPI_RECUSA && dpiDe(a)<DPI_AVISA)
|
||
.map(a=>({nome:a.f.name, dpi:Math.round(dpiDe(a)), cm:a.cm}));
|
||
const todas=comTamanho.map(a=>dpiDe(a));
|
||
geral = todas.length? Math.round(Math.max(...todas)) : 300;
|
||
}
|
||
// Abaixo de 96 DPI a sala não imprime. Não é desconto, é recusa —
|
||
// e não existe aceite que destrave.
|
||
if(recusadas.length){
|
||
$('cienteTxt').innerHTML=
|
||
'<p><b>A média da folha ficou abaixo de '+DPI_RECUSA+' DPI.</b> Nesse ponto a peça '+
|
||
'sai serrilhada a ponto de não valer o filme. Reenvie maior ou reduza a largura.</p>'+
|
||
'<div class="lista">'+recusadas.map(b=>'<div><b>'+escapeHTML(b.nome)+'</b> — '+
|
||
(b.quantas
|
||
? 'média de '+b.dpi+' DPI · pior imagem em '+b.pior+' DPI · '+b.quantas+
|
||
' de '+b.de+' imagens abaixo de '+DPI_RECUSA+' DPI, cobrindo '+b.parte+'% da arte'
|
||
: b.dpi+' DPI em '+n1(b.cm)+' cm · precisa de '+
|
||
Math.ceil(DPI_AVISA*b.cm/2.54)+' px de largura')+'</div>')
|
||
.join('')+'</div>';
|
||
$('cienteTit').textContent='Resolução abaixo do que imprimimos';
|
||
box.className='ciente on recusa'; chk.checked=false; $('qOk').disabled=true;
|
||
return;
|
||
}
|
||
$('cienteTit').textContent='Ressalva de resolução';
|
||
box.className='ciente';
|
||
if(!baixas.length){
|
||
box.classList.remove('on'); chk.checked=false; $('qOk').disabled=false; return;
|
||
}
|
||
const menor=baixas.reduce((p,b)=>b.dpi<p.dpi?b:p);
|
||
const media=Math.round(baixas.reduce((s,b)=>s+b.dpi,0)/baixas.length);
|
||
$('cienteTxt').innerHTML=
|
||
'<p><b>Parte da arte está abaixo de '+DPI_AVISA+' DPI.</b> Essas peças podem sair '+
|
||
'com traço serrilhado, e isso não tem conserto depois de impresso. '+
|
||
'O resto da folha sai normal.</p>'+
|
||
'<div class="lista">'+baixas.map(b=>'<div><b>'+escapeHTML(b.nome)+'</b> — '+
|
||
(b.quantasAviso
|
||
? 'média de '+b.dpi+' DPI · '+b.quantasAviso+' de '+b.de+' imagens abaixo de '+
|
||
DPI_AVISA+' DPI, cobrindo '+b.parteAviso+'% da arte'+
|
||
(b.quantas? ' · dessas, '+b.quantas+' abaixo de '+DPI_RECUSA+' DPI ('+
|
||
b.parte+'% da arte)' : '')
|
||
: b.dpi+' DPI'+(b.cm? ' em '+n1(b.cm)+' cm':''))+
|
||
'</div>').join('')+'</div>';
|
||
box.className='ciente on'; chk.checked=false; $('qOk').disabled=true;
|
||
}
|
||
$('cienteOk').addEventListener('change',e=>{
|
||
if($('ciente').classList.contains('recusa')) return; // recusa não se aceita
|
||
$('qOk').disabled=!e.target.checked;
|
||
});
|
||
|
||
// ── imagens e prévia
|
||
function carregarImagem(file){
|
||
return new Promise(res=>{
|
||
if(!RENDERIZA.test(file.name)) return res(null);
|
||
const fr=new FileReader();
|
||
fr.onload=()=>{ const im=new Image(); im.onload=()=>res(im); im.onerror=()=>res(null); im.src=fr.result; };
|
||
fr.onerror=()=>res(null);
|
||
fr.readAsDataURL(file);
|
||
});
|
||
}
|
||
// A folha precisa parecer uma folha: borda, largura marcada e régua de metros.
|
||
// Sem isso o cliente não tem noção de escala e acha que está mal encaixado.
|
||
function molduraFolha(ctx,W,H,larguraCm,metrosReais){
|
||
const REG=34; // faixa da régua, à direita
|
||
ctx.save();
|
||
// fundo da régua
|
||
ctx.fillStyle='#FAFAF8'; ctx.fillRect(W,0,REG,H);
|
||
ctx.strokeStyle='#D5DAE3'; ctx.lineWidth=1;
|
||
ctx.beginPath(); ctx.moveTo(W+.5,0); ctx.lineTo(W+.5,H); ctx.stroke();
|
||
// marcas a cada 10 cm, número a cada metro
|
||
const pxPorM = H/Math.max(metrosReais,0.01);
|
||
ctx.font='9px "Roboto", sans-serif'; ctx.textAlign='left';
|
||
for(let cm=0; cm<=metrosReais*100; cm+=10){
|
||
const y=cm/100*pxPorM;
|
||
if(y>H) break;
|
||
const metro = cm%100===0;
|
||
ctx.strokeStyle = metro? '#B4BAC5' : '#E1E5EC';
|
||
ctx.beginPath(); ctx.moveTo(W+1,y+.5); ctx.lineTo(W+(metro?12:6),y+.5); ctx.stroke();
|
||
if(metro && cm>0){
|
||
ctx.fillStyle='#8A8F98';
|
||
ctx.fillText((cm/100)+' m', W+14, y+3);
|
||
}
|
||
}
|
||
// borda da folha
|
||
ctx.strokeStyle='#B4BAC5'; ctx.lineWidth=1;
|
||
ctx.strokeRect(.5,.5,W-1,H-1);
|
||
// cota da largura, no topo
|
||
ctx.fillStyle='#FFFFFFDD'; ctx.fillRect(0,0,W,18);
|
||
ctx.strokeStyle='#8A8F98'; ctx.lineWidth=1;
|
||
ctx.beginPath();
|
||
ctx.moveTo(8,9); ctx.lineTo(W-8,9);
|
||
ctx.moveTo(8,5); ctx.lineTo(8,13);
|
||
ctx.moveTo(W-8,5); ctx.lineTo(W-8,13);
|
||
ctx.stroke();
|
||
const t=String(larguraCm).replace('.',',')+' cm';
|
||
ctx.font='600 10px "Roboto", sans-serif'; ctx.textAlign='center';
|
||
const tw=ctx.measureText(t).width;
|
||
ctx.fillStyle='#FAFAF8'; ctx.fillRect(W/2-tw/2-6,2,tw+12,14);
|
||
ctx.fillStyle='#5A6570'; ctx.fillText(t,W/2,13);
|
||
ctx.restore();
|
||
}
|
||
|
||
const LOGO_URL='https://cdn.vnda.com.br/dropstar/2025/12/17/logo-header-15125700-16129080.png?v=1766009286';
|
||
const logoImg=new Image(); logoImg.crossOrigin='anonymous'; logoImg.src=LOGO_URL;
|
||
function marcaDagua(ctx,w,h){
|
||
ctx.save(); ctx.globalAlpha=.14;
|
||
const passo=Math.max(90,w/2.1);
|
||
ctx.translate(w/2,h/2); ctx.rotate(-Math.PI/7); ctx.translate(-w/2,-h/2);
|
||
if(logoImg.complete && logoImg.naturalWidth){
|
||
const lw=Math.max(70,w/3.4), lh=lw*(logoImg.naturalHeight/logoImg.naturalWidth);
|
||
for(let y=-h;y<h*2;y+=passo) for(let x=-w;x<w*2;x+=passo*1.7)
|
||
ctx.drawImage(logoImg,x,y,lw,lh);
|
||
}else{
|
||
ctx.fillStyle='#111';
|
||
ctx.font='700 '+Math.max(13,Math.round(w/13))+'px Inter, sans-serif'; ctx.textAlign='center';
|
||
for(let y=-h;y<h*2;y+=passo) for(let x=-w;x<w*2;x+=passo*1.5) ctx.fillText('PRÉVIA',x,y);
|
||
}
|
||
ctx.restore();
|
||
}
|
||
const CEL=GAP_CM; // célula da máscara, em cm = a folga de 5 mm
|
||
// Dilata 1 célula para a direita e para baixo. Como toda peça é dilatada igual,
|
||
// duas vizinhas ficam separadas por exatamente 1 célula — os 5 mm da regra.
|
||
function dilatar(bruto,cw,ch,cheias){
|
||
const cw2=cw+1, ch2=ch+1;
|
||
const out=new Uint8Array(cw2*ch2);
|
||
for(let y=0;y<ch;y++) for(let x=0;x<cw;x++){
|
||
if(!bruto[y*cw+x]) continue;
|
||
out[y*cw2+x]=1; out[y*cw2+x+1]=1; out[(y+1)*cw2+x]=1; out[(y+1)*cw2+x+1]=1;
|
||
}
|
||
return {cw:cw2,ch:ch2,bits:out,cheias}; // cheias = área de arte, sem a folga
|
||
}
|
||
function mascara(img,w,h,rot,esp=false){
|
||
const cw=Math.max(1,Math.ceil(w/CEL)), ch=Math.max(1,Math.ceil(h/CEL));
|
||
const cv=document.createElement('canvas');
|
||
cv.width=cw; cv.height=ch;
|
||
const ctx=cv.getContext('2d',{willReadFrequently:true});
|
||
let bruto, cheias;
|
||
if(!img){ // sem imagem: caixa cheia
|
||
bruto=new Uint8Array(cw*ch).fill(1); cheias=cw*ch;
|
||
return dilatar(bruto,cw,ch,cheias);
|
||
}
|
||
ctx.save();
|
||
ctx.translate(cw/2,ch/2);
|
||
ctx.rotate(rot*Math.PI/180);
|
||
if(esp) ctx.scale(-1,1);
|
||
const dw=rot%180===90?ch:cw, dh=rot%180===90?cw:ch;
|
||
ctx.drawImage(img,-dw/2,-dh/2,dw,dh);
|
||
ctx.restore();
|
||
const d=ctx.getImageData(0,0,cw,ch).data;
|
||
bruto=new Uint8Array(cw*ch); cheias=0;
|
||
for(let i=0,j=3;i<bruto.length;i++,j+=4){ bruto[i] = d[j]>16 ? 1 : 0; cheias+=bruto[i]; }
|
||
return dilatar(bruto,cw,ch,cheias);
|
||
}
|
||
|
||
// Encaixe pela forma, como o motor do servidor: mapa de ocupação real,
|
||
// máscara por arte e candidatos numa grade ao longo da largura.
|
||
// pecas em centímetros: {w,h,img}. W é a largura do filme em cm.
|
||
function encaixar(pecas,W){
|
||
const cols=Math.ceil(W/CEL)+1; // +1 = a coluna de folga da dilatação
|
||
let linhas=0; const mapa=[];
|
||
function garantir(ate){ while(linhas<ate){ mapa.push(new Uint8Array(cols)); linhas++; } }
|
||
|
||
function colide(m,cx,cy){
|
||
if(cx<0||cy<0||cx+m.cw>cols) return true;
|
||
for(let y=0;y<m.ch;y++){
|
||
const gy=cy+y;
|
||
if(gy>=linhas) continue; // vazio abaixo do que já existe
|
||
const L=mapa[gy], off=y*m.cw;
|
||
for(let x=0;x<m.cw;x++)
|
||
if(m.bits[off+x] && L[cx+x]) return true;
|
||
}
|
||
return false;
|
||
}
|
||
function ocupar(m,cx,cy){
|
||
garantir(cy+m.ch);
|
||
for(let y=0;y<m.ch;y++){
|
||
const L=mapa[cy+y], off=y*m.cw;
|
||
for(let x=0;x<m.cw;x++) if(m.bits[off+x]) L[cx+x]=1;
|
||
}
|
||
}
|
||
|
||
const postas=[];
|
||
const ordem=[...pecas].sort((a,b)=>(b.w*b.h)-(a.w*a.h));
|
||
|
||
ordem.forEach(p=>{
|
||
const oris=[{w:p.w,h:p.h,rot:0}];
|
||
if(!p.mPronta && !p.travado && Math.abs(p.w-p.h)>1 && p.h<=W) oris.push({w:p.h,h:p.w,rot:90});
|
||
|
||
let melhor=null;
|
||
oris.forEach(o=>{
|
||
if(o.w>W) return;
|
||
// a máscara segue a medida da orientação escolhida · girada, largura e altura trocam
|
||
const m = (p.mPronta && o.rot===0) ? p.mPronta : mascara(p.img, o.w, o.h,
|
||
o.rot+(p.a?.giro||0), p.a?.esp);
|
||
const xs=new Set([0]), ys=new Set([0]);
|
||
postas.forEach(q=>{ xs.add(q.cx+q.m.cw); xs.add(q.cx); ys.add(q.cy+q.m.ch); ys.add(q.cy); });
|
||
const passoX=Math.max(1,Math.round(cols/34));
|
||
for(let x=0;x+m.cw<=cols;x+=passoX) xs.add(x);
|
||
xs.add(cols-m.cw);
|
||
const passoY=Math.max(1,Math.round(Math.max(linhas,1)/50));
|
||
for(let y=0;y<=linhas;y+=passoY) ys.add(y);
|
||
const XS=[...xs].filter(x=>x>=0 && x+m.cw<=cols && x*CEL+o.w<=W+0.01).sort((a,b)=>a-b);
|
||
const YS=[...ys].filter(y=>y>=0).sort((a,b)=>a-b);
|
||
|
||
for(const cy of YS){
|
||
if(melhor && cy*CEL > melhor.y + CEL) break;
|
||
for(const cx of XS){
|
||
if(cx*CEL + o.w > W + 0.01) continue; // não deixa a peça sair do filme
|
||
if(colide(m,cx,cy)) continue;
|
||
const cand={cx,cy,m,x:cx*CEL,y:cy*CEL,w:o.w,h:o.h,rot:o.rot,ref:p};
|
||
// menor y, depois menor x · em empate, mantém a orientação original.
|
||
// Desempatar por largura gira tudo, e texto deitado na prévia parece erro.
|
||
const ganha = !melhor || cand.y<melhor.y ||
|
||
(cand.y===melhor.y && cand.x<melhor.x) ||
|
||
(cand.y===melhor.y && cand.x===melhor.x && cand.rot===0 && melhor.rot!==0);
|
||
if(ganha) melhor=cand;
|
||
break;
|
||
}
|
||
}
|
||
});
|
||
if(!melhor){
|
||
const k=Math.min(1, W/p.w); // cabe na largura, nem que seja reduzindo
|
||
const w=p.w*k, h=p.h*k;
|
||
const m=mascara(p.img,w,h,p.a?.giro||0,p.a?.esp);
|
||
melhor={cx:0,cy:linhas,m,x:0,y:linhas*CEL,w,h,rot:0,ref:p};
|
||
}
|
||
// a folga só existe entre peças, não é folha cobrada
|
||
ocupar(melhor.m,melhor.cx,melhor.cy);
|
||
postas.push(melhor);
|
||
});
|
||
|
||
const altura=Math.max(...postas.map(p=>p.y+p.h),1);
|
||
return {pos:postas, altura};
|
||
}
|
||
|
||
function desenhaMontagem(area,lista,mts,W,fora,aoTerminar){
|
||
const versao=area.montagemVersao=(area.montagemVersao||0)+1;
|
||
const filme=larguraFilme(), PX_CM=W/filme;
|
||
const itens=lista.map(a=>({...a}));
|
||
if(fora) fora.innerHTML='';
|
||
if(!itens.length){
|
||
area.innerHTML='<div class="semmont"><b>A montagem aparece aqui</b>'+
|
||
'<span>informe a largura de cada arte e a folha se desenha sozinha</span></div>';
|
||
if(aoTerminar) aoTerminar({alturaCm:0, uso:0, girou:0});
|
||
return;
|
||
}
|
||
|
||
Promise.all(itens.map(a=>carregarImagem(a.f).then(img=>({a,img})))).then(imagens=>{
|
||
if(area.montagemVersao!==versao) return;
|
||
const cargas=imagens.flatMap(c=>Array.from({length:c.a.q||1},()=>({...c})));
|
||
cargas.forEach(c=>{
|
||
c.w = c.a.cm; // o motor trabalha em centímetros
|
||
c.h = c.w * (c.img ? (c.a.giro? c.img.width/c.img.height : c.img.height/c.img.width) : 1);
|
||
c.travado = !!c.a.giro; // giro do cliente manda no encaixe
|
||
});
|
||
const enc=encaixar(cargas,filme);
|
||
const alturaCm=enc.altura;
|
||
const pos=enc.pos.map(p=>({...p, x:p.x*PX_CM, y:p.y*PX_CM, w:p.w*PX_CM, h:p.h*PX_CM}));
|
||
const altura=alturaCm*PX_CM;
|
||
const usado=Math.max(altura,10);
|
||
const REG=34;
|
||
const cv=document.createElement('canvas');
|
||
cv.width=W+REG; cv.height=Math.round(usado);
|
||
const ctx=cv.getContext('2d');
|
||
ctx.fillStyle='#fff'; ctx.fillRect(0,0,cv.width,cv.height);
|
||
const pal=['#C3CEDD','#B7A9C8','#A9B7C8','#A8BFA9','#C8C0A0','#CBB6B6'];
|
||
let girou=0;
|
||
pos.forEach((p,j)=>{
|
||
const c=p.ref;
|
||
if(p.rot===90) girou++;
|
||
ctx.save();
|
||
const giro = (p.rot===90?90:0) + (c.a && c.a.giro? 90:0);
|
||
ctx.translate(p.x+p.w/2, p.y+p.h/2);
|
||
ctx.rotate(giro*Math.PI/180);
|
||
if(c.a && c.a.esp) ctx.scale(-1,1);
|
||
const dw = giro%180===90 ? p.h : p.w, dh = giro%180===90 ? p.w : p.h;
|
||
if(c.img) ctx.drawImage(c.img,-dw/2,-dh/2,dw,dh);
|
||
else{ ctx.fillStyle=pal[j%pal.length]; ctx.fillRect(-dw/2,-dh/2,dw,dh); }
|
||
ctx.restore();
|
||
if(!c.img){
|
||
ctx.fillStyle='#5A6570'; ctx.font='11px "Roboto", sans-serif'; ctx.textAlign='center';
|
||
ctx.fillText(c.a.f.name.split('.').pop().toUpperCase(),p.x+p.w/2,p.y+p.h/2+4);
|
||
}
|
||
});
|
||
molduraFolha(ctx,W,usado,filme,alturaCm/100);
|
||
marcaDagua(ctx,W,cv.height);
|
||
area.innerHTML=''; area.appendChild(cv);
|
||
|
||
// O que virou arte é a área pintada, não a soma das caixas: com encaixe por forma
|
||
// as caixas se sobrepõem de propósito e a soma delas passa de 100%.
|
||
const areaArteCm=enc.pos.reduce((s,p)=>
|
||
s + (p.m && p.m.cheias!=null ? p.m.cheias*CEL*CEL : p.w*p.h), 0);
|
||
const uso=Math.max(1,Math.min(100,
|
||
Math.round(areaArteCm/(filme*Math.max(alturaCm,0.1))*100)));
|
||
const el=document.createElement('div');
|
||
el.className = uso>=70? 'usoBom' : 'usoRuim';
|
||
el.innerHTML = (uso>=70
|
||
? '<b>'+uso+'% da folha virou arte</b> bom aproveitamento'
|
||
: '<b>'+uso+'% da folha virou arte</b> dá para melhorar: artes de larguras parecidas '+
|
||
'se encaixam melhor lado a lado')
|
||
+ (girou? ' · <b style="display:inline">'+girou+
|
||
(girou>1?' artes giradas':' arte girada')+' 90°</b> para caber melhor':'');
|
||
(fora||area).appendChild(el);
|
||
if(aoTerminar) aoTerminar({alturaCm, uso, girou});
|
||
});
|
||
}
|
||
|
||
function previaArtes(){ desenhaMontagem($('pArea'), artes, metros, 560); }
|
||
|
||
// montagem ao vivo, ao lado da fila · redesenha 140 ms depois da ultima mexida
|
||
let tMont=null;
|
||
function previaAoVivo(){
|
||
clearTimeout(tMont);
|
||
$('vArea').montagemVersao=($('vArea').montagemVersao||0)+1;
|
||
if(ehFolha()){
|
||
$('vUso').innerHTML='';
|
||
const tot=folhaTotalM();
|
||
$('vMt').textContent = tot>0 ? fmtM(cobrar(tot))+' m' : '—';
|
||
const medidas=folhas.filter(x=>x.med);
|
||
const previews=folhas.filter(x=>x.previewSrc);
|
||
if(previews.length){
|
||
const painel=document.createElement('div'); painel.className='folhaPrevias';
|
||
previews.forEach((x,index)=>{
|
||
const figura=document.createElement('figure'); figura.className='folhaPrevia';
|
||
const imagem=new Image(); imagem.src=x.previewSrc; imagem.alt=x.f.name;
|
||
const legenda=document.createElement('figcaption');
|
||
legenda.textContent=(previews.length>1 ? (index+1)+'. ' : '')+x.f.name+
|
||
(x.med ? ' · '+n1(x.med.larg)+' × '+n1(x.med.alt)+' cm' : '');
|
||
figura.append(imagem,legenda); painel.append(figura);
|
||
});
|
||
$('vArea').replaceChildren(painel);
|
||
}else{
|
||
$('vArea').innerHTML = medidas.length
|
||
? '<div class="semmont"><b>'+(medidas.length>1
|
||
? medidas.length+' folhas · '+fmtM(tot)+' m'
|
||
: n1(medidas[0].med.larg)+' × '+n1(medidas[0].med.alt)+' cm')+'</b>'+
|
||
'<span>'+(medidas.length>1? 'medidas lidas de cada arquivo' : medidas[0].med.fonte)+
|
||
' · vão para a máquina do jeito que você montou</span></div>'
|
||
: '<div class="semmont"><b>Sua folha aparece aqui</b>'+
|
||
'<span>a medida é lida do próprio arquivo, não do peso dele</span></div>';
|
||
}
|
||
return;
|
||
}
|
||
tMont=setTimeout(()=>{
|
||
const prontas=artes.filter(a=>a.cm>0);
|
||
const W=Math.round(300*ZOOMS[zoomI]);
|
||
$('vArea').classList.toggle('ampliado', zoomI>0);
|
||
desenhaMontagem($('vArea'), prontas, 0, W, $('vUso'), r=>{
|
||
montagemCm = r.alturaCm; // altura real da folha montada
|
||
$('vMt').textContent = r.alturaCm? fmtM(cobrar(r.alturaCm/100))+' m' : '—';
|
||
resumoArtes(); // o resumo lê a mesma folha
|
||
agendaAvaliacao(); // a nota só sai com a metragem pronta
|
||
});
|
||
$('vArea').scrollTop=0;
|
||
},140);
|
||
}
|
||
|
||
function motivoNota(){
|
||
if(!nota) return 'sem nota ainda · a conferência roda na sala antes de imprimir';
|
||
if(!ehFolha()){
|
||
const ruins=artes.filter(a=>a.cm>0 && (a.px/(a.cm/2.54))<300);
|
||
if(!ruins.length) return 'nota '+nota+' · todas as artes em 300 DPI ou mais';
|
||
const pior=ruins.reduce((p,a)=>(a.px/(a.cm/2.54))<(p.px/(p.cm/2.54))?a:p);
|
||
return 'nota '+nota+' · '+ruins.length+(ruins.length>1?' artes abaixo':' arte abaixo')+
|
||
' de 300 DPI · a menor é "'+pior.f.name+'" com '+
|
||
Math.round(pior.px/(pior.cm/2.54))+' DPI em '+pior.cm.toFixed(1).replace('.',',')+' cm';
|
||
}
|
||
return nota>=90 ? 'nota '+nota+' · resolução ótima em toda a folha'
|
||
: 'nota '+nota+' · a resolução é o único ponto — o resto corrigimos por você';
|
||
}
|
||
function previa(){
|
||
// Na folha pronta o painel não tem o que mostrar: a folha vem fechada, ninguém
|
||
// olhou dentro dela. Largura e metragem — o que de fato medimos — já aparecem
|
||
// na coluna ao lado e no carrinho.
|
||
if(ehFolha()){ $('prev').classList.remove('on'); return; }
|
||
const cob=cobrar(metros), sobra=+(cob-metros).toFixed(2);
|
||
$('pMt').innerHTML=fmtM(cob)+'<small> m</small>';
|
||
$('pSub').textContent='folha montada por nós com as artes que você enviou';
|
||
const linhas=[
|
||
['var(--verde)','✓','Largura',larguraFilme()+' cm · dentro do padrão da máquina'],
|
||
['var(--verde)','✓','Espaço entre artes','5 mm garantidos'],
|
||
[nota>=75?'var(--verde)':'var(--laranja)', nota>=75?'✓':'!','Qualidade da folha',motivoNota()],
|
||
['var(--verde)','✓','Metragem proporcional',
|
||
'sua folha tem '+fmtM(metros)+' m e você paga '+fmtM(cob)+
|
||
' m · arredondamos só até os 10 cm mais próximos'],
|
||
];
|
||
linhas.push(['var(--verde)','+','Identificação do pedido',
|
||
'aplicamos seu nome e o número do pedido no fim da folha · por nossa conta']);
|
||
$('pInfo').innerHTML=linhas.map(l=>
|
||
'<div class="li"><span class="c" style="background:'+l[0]+
|
||
(l[0]==='var(--laranja)'?';color:#241703':'')+'">'+l[1]+'</span>'+
|
||
'<div><b>'+escapeHTML(l[2])+'</b><span>'+escapeHTML(l[3])+'</span></div></div>').join('');
|
||
$('prev').classList.add('on');
|
||
$('pArea').innerHTML='<div class="carregando">montando a prévia…</div>';
|
||
try{ previaArtes(); }
|
||
catch(e){ $('pArea').innerHTML='<div class="semprev"><b>Prévia indisponível</b>'+
|
||
'O arquivo será processado normalmente.</div>'; }
|
||
}
|
||
|
||
// ── carrinho
|
||
let itemAtual=null;
|
||
function limpaPaineis(){
|
||
['qual','prev'].forEach(id=>$(id).classList.remove('on'));
|
||
if(!pedido.length){ $('carr').classList.remove('on'); }
|
||
}
|
||
|
||
// O carrinho junta itens de produtos diferentes e cobra uma vez só.
|
||
function pintaPedido(){
|
||
$('itens').innerHTML = pedido.map((it,i)=>
|
||
'<div class="item"><div class="nm2"><b>'+escapeHTML(it.tit)+'</b><span>'+escapeHTML(it.desc)+'</span></div>'+
|
||
'<div class="vl2">'+rs(it.total)+'</div>'+
|
||
'<button class="x" data-rmi="'+i+'" aria-label="Remover">×</button></div>').join('');
|
||
$('itens').querySelectorAll('[data-rmi]').forEach(b=>b.addEventListener('click',()=>{
|
||
pedido.splice(+b.dataset.rmi,1); pintaPedido();
|
||
}));
|
||
const itens = pedido.reduce((t,it)=>t+it.total,0) + (itemAtual? itemAtual.total : 0);
|
||
const frete = entrega.tipo==='frete' && entrega.cotado ? entrega.valor : 0;
|
||
const soma = itens + frete;
|
||
const n = pedido.length + (itemAtual?1:0);
|
||
const eco = [...pedido, ...(itemAtual?[itemAtual]:[])]
|
||
.reduce((t,it)=>t+(TABELA[it.modo]-it.unit)*it.cob, 0);
|
||
$('resLin').innerHTML =
|
||
'<div class="l"><span>'+n+(n===1?' item':' itens')+'</span><b>'+rs(itens+eco)+'</b></div>'+
|
||
(eco>0.01? '<div class="l" style="color:var(--verde-ml)"><span>Desconto pela nota</span>'+
|
||
'<b style="color:var(--verde-ml)">− '+rs(eco)+'</b></div>' : '')+
|
||
'<div class="l"><span>Frete</span><b>'+
|
||
(entrega.tipo==='retira' ? '<span style="color:var(--verde-ml)">Grátis</span>'
|
||
: entrega.cotado ? rs(frete) : 'a cotar')+'</b></div>'+
|
||
'<div class="l"><span>Revisão e reencaixe</span>'+
|
||
'<b><span style="color:var(--verde-ml)">Grátis</span></b></div>';
|
||
$('carrTot').textContent=rs(soma);
|
||
$('bPagar').textContent = (pedido.length + (itemAtual?1:0))>1
|
||
? 'Pagar os '+(pedido.length+(itemAtual?1:0))+' itens de uma vez'
|
||
: 'Ir para o pagamento';
|
||
if(pedido.length || itemAtual) $('carr').classList.add('on');
|
||
if($('cartLink')) $('cartLink').textContent='Carrinho ('+n+')';
|
||
window.dispatchEvent(new Event('dtf-cart-changed'));
|
||
}
|
||
|
||
function carrinho(){
|
||
const base=precoBase(nota), cob=cobrar(metros);
|
||
const unit=base, tot=cob*unit, sobra=+(cob-metros).toFixed(2);
|
||
$('carr').classList.add('on');
|
||
let l='<div class="l"><span>'+MODOS[modo].tit+'</span><b>'+rs(base)+'/m</b></div>';
|
||
{
|
||
const teto=TABELA[modo], eco=(teto-base)*cob;
|
||
l = '<div class="l"><span>'+MODOS[modo].tit+' · tabela</span><b>'+rs(teto)+'/m</b></div>';
|
||
l += eco>0.01
|
||
? '<div class="l" style="color:#7FD4A0"><span>Desconto pela nota '+nota+'</span><b>−'+rs(eco)+'</b></div>'
|
||
: '<div class="l" style="color:#8D9AB0"><span>Nota '+nota+' · sem desconto</span><b>—</b></div>';
|
||
}
|
||
if(!ehFolha()) l += '<div class="l" style="color:#8D9AB0"><span>Montagem da folha</span>'+
|
||
'<b>inclusa · '+rs(MONTAGEM[modo])+'/m</b></div>';
|
||
l += '<div class="l"><span>Metragem'+(sobra>0.001?' · arredondada para 10 cm':'')+
|
||
'</span><b>'+fmtM(cob)+' m</b></div>';
|
||
l += '<div class="l"><span>Preço final do metro</span><b>'+rs(unit)+'</b></div>'+
|
||
'<div class="l" style="color:var(--laranja2)"><span>Revisão e reencaixe</span><b>grátis</b></div>';
|
||
$('carrLin').innerHTML=l;
|
||
$('atual').style.display='';
|
||
itemAtual={modo, tit:MODOS[modo].tit, nota, metros, cob, unit, total:tot,
|
||
localFiles:(ehFolha()?folhas:artes).map(x=>x.f),
|
||
desc:fmtM(cob)+' m · '+rs(unit)+'/m · nota '+nota};
|
||
pintaPedido();
|
||
previa();
|
||
if(nota<90){
|
||
const piso=pisoEscada(), ganho=(base-piso)*cob;
|
||
if(ganho>0.5) qm('<b>Dá para chegar ao melhor preço.</b> Corrigindo os pontos e chegando a 90, '+
|
||
'o metro cai para '+rs(piso)+' — são '+rs(ganho)+' a menos neste pedido.','var(--verde)');
|
||
}
|
||
}
|
||
function qm(t,c){ const m=$('qmsg'); m.style.display='block'; m.style.color=c||'var(--verde)'; m.innerHTML=t; }
|
||
|
||
// ── decisões
|
||
// Remanejar conserta encaixe, não resolução — e a nota mede só resolução.
|
||
// Por isso a nota NÃO muda aqui. E a metragem nova só existe depois que o motor
|
||
// roda na folha de verdade, no servidor: o navegador recebe a folha fechada,
|
||
// não as artes separadas, então não há como recalcular aqui sem inventar número.
|
||
$('qOk').addEventListener('click',()=>{
|
||
if($('qOk').disabled) return;
|
||
const ok=$('ciente').classList.contains('on');
|
||
qm(ok? '<b>Registrado.</b> Você confirmou que viu a ressalva de resolução.'
|
||
: '<b>Certo.</b> Seu pedido está montado abaixo.','var(--tx)');
|
||
$('carr').scrollIntoView({behavior:'smooth',block:'nearest'});
|
||
});
|
||
|
||
$('pOk').addEventListener('click',()=>$('carr').scrollIntoView({behavior:'smooth'}));
|
||
$('pMais').addEventListener('click',()=>$('foco').scrollIntoView({behavior:'smooth'}));
|
||
$('pVolta').addEventListener('click',()=>{
|
||
folhas=[]; artes=[]; reencaixado=false; pintaFolha(); pintaArtes();
|
||
limpaPaineis(); // o carrinho só some se o pedido estiver vazio
|
||
$('foco').scrollIntoView({behavior:'smooth'});
|
||
});
|
||
// carrossel
|
||
(function(){
|
||
const tr=$('trilho'); if(!tr) return;
|
||
const slides=[...tr.children], pontos=$('cPontos');
|
||
slides.forEach((_,i)=>{
|
||
const b=document.createElement('button');
|
||
b.className='pt'+(i?'':' on'); b.setAttribute('aria-label','Cartão '+(i+1));
|
||
b.addEventListener('click',()=>ir(i)); pontos.appendChild(b);
|
||
});
|
||
function ir(i){
|
||
i=Math.max(0,Math.min(slides.length-1,i));
|
||
tr.scrollTo({left:slides[i].offsetLeft-tr.offsetLeft,behavior:'smooth'});
|
||
}
|
||
function atual(){
|
||
const meio=tr.scrollLeft+tr.clientWidth/2;
|
||
let a=0,d=Infinity;
|
||
slides.forEach((s,i)=>{
|
||
const c=s.offsetLeft-tr.offsetLeft+s.offsetWidth/2;
|
||
if(Math.abs(c-meio)<d){ d=Math.abs(c-meio); a=i; }
|
||
});
|
||
return a;
|
||
}
|
||
tr.addEventListener('scroll',()=>{
|
||
const a=atual();
|
||
[...pontos.children].forEach((p,i)=>p.classList.toggle('on',i===a));
|
||
},{passive:true});
|
||
$('cAnt').addEventListener('click',()=>ir(atual()-1));
|
||
$('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('.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('.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));
|
||
$('cep').classList.toggle('on', entrega.tipo==='frete');
|
||
$('vFrete').textContent = entrega.tipo!=='frete' ? '—'
|
||
: entrega.cotado ? rs(entrega.valor) : 'a cotar';
|
||
$('avisoE').innerHTML = entrega.tipo==='retira'
|
||
? 'DTF é impresso depois que você paga. Avisamos no WhatsApp quando estiver '+
|
||
'<b>pronto para retirar</b> — não venha antes do aviso.'
|
||
: '';
|
||
$('bPagar').disabled = !entrega.cotado || !clienteOk();
|
||
pintaPedido();
|
||
}
|
||
|
||
// máscaras e conferência dos campos do cliente
|
||
function liga(id,fmt,val,chave,erro,msg){
|
||
const el=$(id), er=$(erro);
|
||
el.addEventListener('input',e=>{
|
||
e.target.value=fmt(e.target.value);
|
||
cliente[chave]=e.target.value;
|
||
el.classList.remove('ruim','bom'); er.textContent='';
|
||
if(val(e.target.value)) el.classList.add('bom');
|
||
pintaEntrega();
|
||
});
|
||
el.addEventListener('blur',()=>{
|
||
if(!el.value){ el.classList.remove('ruim','bom'); er.textContent=''; return; }
|
||
const ok=val(el.value);
|
||
el.classList.toggle('ruim',!ok); el.classList.toggle('bom',ok);
|
||
er.textContent = ok? '' : msg;
|
||
});
|
||
}
|
||
liga('fCnpj', v=>{
|
||
const d=v.replace(/\D/g,'').slice(0,14);
|
||
return d.replace(/^(\d{2})(\d)/,'$1.$2').replace(/^(\d{2})\.(\d{3})(\d)/,'$1.$2.$3')
|
||
.replace(/\.(\d{3})(\d)/,'.$1/$2').replace(/(\d{4})(\d)/,'$1-$2');
|
||
}, cnpjOk, 'cnpj', 'eCnpj', 'CNPJ inválido · confira os números');
|
||
liga('fZap', v=>{
|
||
const d=v.replace(/\D/g,'').slice(0,11);
|
||
return d.length>6 ? '('+d.slice(0,2)+') '+d.slice(2,d.length-4)+'-'+d.slice(-4)
|
||
: d.length>2 ? '('+d.slice(0,2)+') '+d.slice(2) : d;
|
||
}, zapOk, 'zap', 'eZap', 'Faltam dígitos no número');
|
||
liga('fMail', v=>v.trim(), mailOk, 'mail', 'eMail', 'E-mail inválido');
|
||
function pintaZoom(){
|
||
$('zTxt').textContent=Math.round(ZOOMS[zoomI]*100)+'%';
|
||
$('zMenos').disabled = zoomI===0;
|
||
$('zMais').disabled = zoomI===ZOOMS.length-1;
|
||
}
|
||
$('zMais').addEventListener('click',()=>{
|
||
if(zoomI<ZOOMS.length-1){ zoomI++; pintaZoom(); previaAoVivo(); }
|
||
});
|
||
$('zMenos').addEventListener('click',()=>{
|
||
if(zoomI>0){ zoomI--; pintaZoom(); previaAoVivo(); }
|
||
});
|
||
pintaZoom();
|
||
|
||
document.querySelectorAll('.opE').forEach(b=>b.addEventListener('click',()=>{
|
||
entrega.tipo=b.dataset.ent;
|
||
entrega.cotado = entrega.tipo==='retira';
|
||
entrega.valor=0;
|
||
if(entrega.tipo==='frete') $('cepMsg').innerHTML='';
|
||
pintaEntrega();
|
||
}));
|
||
$('cepIn').addEventListener('input',e=>{
|
||
const v=e.target.value.replace(/\D/g,'').slice(0,8);
|
||
e.target.value = v.length>5 ? v.slice(0,5)+'-'+v.slice(5) : v;
|
||
entrega.cep=v; entrega.cotado=false; entrega.valor=0; pintaEntrega();
|
||
});
|
||
$('bCep').addEventListener('click',async()=>{
|
||
if(entrega.cep.length!==8){ $('cepMsg').innerHTML='CEP incompleto.'; return; }
|
||
if(window.dtfFreight){ await window.dtfFreight(); return; }
|
||
// A cotação vem da transportadora. Enquanto a integração não existir, o pedido não
|
||
// fecha por frete: o valor precisa estar fechado antes do Mercado Pago.
|
||
$('cepMsg').innerHTML='<b style="color:#FFB63D">Cotação de frete ainda não integrada.</b><br>'+
|
||
'O valor precisa vir da transportadora antes do pagamento — senão você pagaria um '+
|
||
'total que não é o final. Por enquanto, retire em Franca ou fale conosco no WhatsApp.';
|
||
pintaEntrega();
|
||
});
|
||
|
||
$('bMais').addEventListener('click',()=>{
|
||
if(itemAtual){ pedido.push(itemAtual); itemAtual=null; }
|
||
$('atual').style.display='none'; $('carrLin').innerHTML='';
|
||
$('foco').classList.remove('on'); $('cards').style.display='';
|
||
['qual','prev'].forEach(id=>$(id).classList.remove('on'));
|
||
modo=null; artes=[]; folhas=[]; metros=0; nota=0; montagemCm=0;
|
||
pintaPedido();
|
||
document.getElementById('envio').scrollIntoView({behavior:'smooth'});
|
||
});
|
||
|
||
$('bPagar').addEventListener('click',()=>{
|
||
if(window.dtfCheckout) window.dtfCheckout();
|
||
else alert('O pedido online está indisponível no momento. Tente novamente em instantes.');
|
||
});
|
||
pintaEntrega();
|
||
</script>
|
||
<script src="/privacy.js"></script>
|
||
<script src="/upload.js"></script>
|
||
<script src="/checkout.js"></script>
|
||
<script src="/cart.js"></script>
|
||
|
||
</body>
|
||
</html>
|