:root{
  --ink:#0B0A08;
  --ink-2:#131110;
  --ink-3:#1F1C18;
  --bone:#F5F1EA;
  /* O degrau entre o texto principal e o cinza de apoio. Estava escrito à mão em
     14 lugares antes de ter nome, e é o mesmo tom do INFO da marca. Ganhou token
     porque é um dos que precisa de valor diferente quando existir tema claro. */
  --bone-2:#C9C3B8;
  --gold:#FFB020;
  --gold-hi:#FFC85C;
  --gold-dim:#A86F12;
  /* O ÂMBAR QUANDO ELE É PALAVRA, e não preenchimento.
     No escuro é o mesmo --gold e por isso nada muda hoje. Existe porque medimos:
     #FFB020 sobre fundo claro dá 1,62 de contraste, contra o mínimo de 4,5. Em
     tema claro o âmbar continua servindo para botão cheio, borda, filete e ícone,
     mas não pode ser texto: ali ele precisa escurecer para perto de #906109, que
     mede 4,78. Separar os dois papéis ANTES de existir tema claro é o que evita a
     varredura de 66 usos no meio do trabalho de cor. */
  --gold-txt:#FFB020;
  /* o mesmo raciocinio para o ambar apagado: hoje vale --gold-dim, e no
     tema claro os dois papeis de texto convergem para um tom legivel. */
  --gold-txt-2:#A86F12;
  --gray:#928C82;
  --line:rgba(245,241,234,.13);
  --line-2:rgba(245,241,234,.22);
  --sans:'Archivo',sans-serif;
  --mono:'IBM Plex Mono',monospace;
  --ease:cubic-bezier(.16,1,.3,1);

  /* ESCALA DOS MIÚDOS. Antes existiam dez tamanhos em mono (8,5 · 9 · 9,5 · 10 ·
     10,5 · 11 · 11,5 · 12 · 12,5 · 13) fazendo o mesmo trabalho de rótulo. Perto
     demais para ler como decisão e diferente demais para ler como igual: é o que
     dava a sensação de bagunça. Três degraus, com distância suficiente entre eles
     para cada um significar uma coisa.
       m1  legenda, o que é assinatura e não se lê de longe
       m2  rótulo, o degrau padrão: eyebrow, menu, tags, numeração
       m3  texto em mono e botão, o único que se lê como frase
     Em sans, o mesmo problema em menor escala (13 · 13,5 · 14 · 14,5): dois degraus. */
  --wm-op:.58;   /* opacidade final da marca de sangria do rodapé */
  /* --m1 nasceu 9.5px nesta mesma sessão e foi longe demais: virou o degrau de
     6 textos que se espera ler, não só de assinatura. 11px é o piso razoável e
     mantém distância clara do m2. */
  --m1:11px;   --m1-ls:.12em;
  --m2:11.5px; --m2-ls:.12em;
  --m3:13px;   --m3-ls:.03em;
  --s1:13.5px;
  --s2:14.5px;
  --s3:16px;
}

*{margin:0;padding:0;box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  background:var(--ink);color:var(--bone);
  font-family:var(--sans);font-size:17px;line-height:1.55;font-weight:400;
  overflow-x:hidden;-webkit-font-smoothing:antialiased;
}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer}
::selection{background:var(--gold);color:var(--ink)}
:focus-visible{outline:2px solid var(--gold);outline-offset:3px}

/* UM container para tudo. antes a nav usava 5vw, as seções 1360px e o grid do hero
   1180px: três larguras competindo na mesma tela, e o olho lia como desalinhado. */
:root{--container:min(1240px,90vw)}
.wrap{width:var(--container);margin-inline:auto}
.sec{padding:clamp(76px,10vw,150px) 0;position:relative}
/* a nav é fixa: sem isso o título da seção aterrissa atrás dela ao clicar numa âncora */
section[id],header[id]{scroll-margin-top:clamp(76px,9vh,104px)}
.tint{background:var(--ink-2)}

/* ---------------- tipografia ---------------- */
.h1,.h2,.h3{font-family:var(--sans);font-weight:700;font-stretch:118%;letter-spacing:-.03em;line-height:.94}
.h1{font-size:clamp(40px,7.2vw,112px);letter-spacing:-.042em}
/* text-wrap:balance mata as órfãs. Duas medidas antes: "Quanto custa, com a IA
   junto." e "No ar hoje, sem instalar nada." terminavam com uma linha de 200px
   contra 840px da anterior, uma palavra sozinha embaixo. O navegador reequilibra
   as linhas sozinho, sem <br> na mão que quebra em outra largura. */
.h2{font-size:clamp(31px,4.7vw,68px);letter-spacing:-.035em;text-wrap:balance}
.h3{font-size:clamp(20px,2.2vw,30px);line-height:1.1;letter-spacing:-.025em}
.lead{font-size:clamp(16.5px,1.45vw,21px);line-height:1.5;max-width:58ch}
.dim{color:var(--gray)}
.mono{font-family:var(--mono);font-size:var(--m3);letter-spacing:var(--m3-ls)}
.gold{color:var(--gold-txt)}
/* O eyebrow nasceu no degrau m2 (11,5px), o mesmo de tag e numeração. Ele disse,
   com razão, que "tão muito pequenos e são coisas importantes": esta linha é o que
   nomeia a seção, e quem passa os olhos lê ela antes do título. Subiu para o m3,
   13px, que a escala define como "o único que se lê como frase". Tracking de .12em
   para .1em, porque corpo maior com o mesmo tracking esparrama, e o filete de 24
   para 28px para acompanhar a linha. */
.eyebrow{
  font-family:var(--mono);font-size:var(--m3);letter-spacing:.1em;text-transform:uppercase;
  color:var(--gray);display:inline-flex;align-items:center;gap:11px;
}
.eyebrow::before{content:"";width:28px;height:1px;background:var(--gold);flex:none}
/* no celular o eyebrow mais longo da home ("o que acontece quando alguém te
   chama") mede 337px de texto e com o filete e o gap passa de 376px numa caixa de
   370px, entao quebra em duas linhas. 12px resolve a quebra; e quando ainda
   quebrar, o filete alinha com a PRIMEIRA linha em vez de flutuar no meio. */
@media(max-width:560px){
  .eyebrow{font-size:12px;letter-spacing:.08em;align-items:flex-start}
  .eyebrow::before{margin-top:.78em}
}

/* ---------------- chrome ---------------- */
.pre{display:none}
.js .pre{position:fixed;inset:0;z-index:1000;background:var(--ink);flex-direction:column;justify-content:flex-end;padding:0 5vw 5vh;display:flex;
  /* rede de segurança: se o JS que remove o preloader não rodar (CDN bloqueado,
     erro em runtime), o CSS o dispensa sozinho aos 6s. ninguém fica preso na tela preta. */
  animation:preFail 0s linear 6s forwards}
@keyframes preFail{to{opacity:0;visibility:hidden;pointer-events:none}}
.pre-row{display:flex;align-items:baseline;justify-content:space-between;gap:20px;border-top:1px solid var(--line);padding-top:16px}
/* Mesma marca do cabeçalho, em corpo grande. Os três pedaços existem para a
   abertura: começa lendo IHUB e o miolo é revelado da esquerda para a direita
   enquanto o HUB desliza para o lugar dele.
   O estado inicial é montado em JS, nunca em CSS: sem JavaScript, ou com o
   preloader dispensado, a palavra nasce inteira em vez de nascer capenga. */
.pre-mark{font-weight:400;font-stretch:112%;font-size:clamp(26px,6vw,74px);letter-spacing:-.045em;
  line-height:1;color:var(--bone-2);white-space:nowrap}
.pre-mark span{display:inline-block}
.pm-hub{font-weight:800;font-stretch:118%;color:var(--gold-txt)}
/* O contador saiu da IBM Plex Mono. A 74px os algarismos dela ficam mecânicos e
   pesados do lado da Archivo do wordmark: eram duas tipografias disputando a
   mesma linha. Agora é a mesma família, em peso leve para não competir com a
   marca, que é quem tem que ganhar a tela.
   font-variant-numeric:tabular-nums é o que substitui a mono aqui. Sem isso a
   largura muda a cada algarismo e o número treme enquanto conta. Medido: 000,
   111, 062 e 100 saem todos com a mesma largura.
   Peso 300 e largura 125%: leve e aberto, para o número existir sem disputar
   com a marca do lado. */
.pre-num{font-family:var(--sans);font-weight:300;font-stretch:125%;
  font-size:clamp(26px,6vw,74px);line-height:1;color:var(--gold-txt);
  letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.pre-bar{position:absolute;left:0;bottom:0;height:2px;width:0;background:var(--gold)}

.nav{
  position:fixed;top:0;left:0;right:0;z-index:800;
  padding:20px 0;transition:transform .5s var(--ease);
}
.nav.up{transform:translateY(-140%)}
/* A nav é fixa e nascia sem fundo: rolando a página, o texto dela montava em
   cima do título da seção (o "INFOHUB" caiu dentro do "Duas soluções"). Em cima
   do hero ela continua limpa, porque ali a foto é o fundo; passando do hero,
   entra o vidro. */
.nav::before{content:"";position:absolute;inset:0;z-index:-1;
  background:rgba(11,10,8,.82);border-bottom:1px solid var(--line);
  -webkit-backdrop-filter:blur(14px) saturate(1.2);backdrop-filter:blur(14px) saturate(1.2);
  opacity:0;transition:opacity .45s var(--ease)}
.nav.solid::before{opacity:1}
.nav-in{display:flex;align-items:center;justify-content:space-between;gap:20px}
.nav-mark{display:inline-flex;flex-direction:column;gap:3px;line-height:1}
/* Marca em dois pesos: INFO leve e claro, HUB pesado e âmbar. O contraste faz o
   trabalho que antes era só de cor, e a palavra passa a ter hierarquia interna
   em vez de ser um bloco chapado pintado pela metade. */
.nav-mark b{font-weight:400;font-stretch:112%;font-size:25px;letter-spacing:-.035em;color:var(--bone-2)}
.nav-mark b i{font-weight:800;font-stretch:118%}
/* inline-block porque transform não pega em elemento inline, e a abertura da
   marca desloca o HUB. O estado inicial é montado em JS: sem ele, a palavra
   nasce inteira, que é o que tem que acontecer sem JavaScript. */
.nav-mark b > span,.nav-mark b > i{display:inline-block}
.nav-mark i{font-style:normal;color:var(--gold-txt)}
/* descritor sob a marca. as três palavras são distribuídas com space-between na
   largura da logo, então as pontas casam com o "I" e o "B" de INFOHUB em vez de
   o texto vazar à direita. o corpo é menor que a largura disponível de propósito:
   é a sobra que o space-between usa para alinhar. */
.nav-mark small{display:flex;justify-content:space-between;
  font-family:var(--mono);font-size:var(--m1);letter-spacing:var(--m1-ls);text-transform:uppercase;
  color:var(--gold-txt-2);transition:color .35s}
.nav-mark:hover small{color:var(--gold-txt)}
@media(max-width:420px){.nav-mark small{display:none}}
.nav-links{display:flex;align-items:center;gap:26px;font-family:var(--mono);font-size:var(--m2);letter-spacing:var(--m2-ls);text-transform:uppercase}
.nav-links a{position:relative;padding-bottom:3px;color:var(--bone)}
/* 220ms: o menu é o elemento que se atravessa mais vezes na página, e a 450ms o
   filete ainda estava crescendo quando o cursor já tinha ido para o próximo. */
.nav-links a::after{content:"";position:absolute;left:0;bottom:0;width:100%;height:1px;background:var(--gold);transform:scaleX(0);transform-origin:right;transition:transform 220ms var(--ease)}
.nav-links a{transition:color 160ms ease}
@media(hover:hover) and (pointer:fine){
  .nav-links a:hover::after{transform:scaleX(1);transform-origin:left}
  .nav-links a:hover{color:var(--gold-txt)}
}
@media(max-width:900px){.nav-links{display:none}}
.sm-toggle{
  display:none;align-items:center;gap:10px;cursor:pointer;
  font-family:var(--mono);font-size:var(--m2);letter-spacing:var(--m2-ls);text-transform:uppercase;
  color:var(--bone);background:none;border:none;padding:4px 2px;
}
@media(max-width:900px){.sm-toggle{display:inline-flex}}
.sm-tw{position:relative;display:inline-block;height:1em;overflow:hidden;white-space:nowrap;min-width:52px}
.sm-ti{display:flex;flex-direction:column;line-height:1}
.sm-tl{display:block;height:1em;line-height:1}
.sm-icon{position:relative;width:14px;height:14px;flex:none;display:inline-flex}
.sm-il{position:absolute;left:50%;top:50%;width:100%;height:1.5px;background:currentColor;transform:translate(-50%,-50%);border-radius:2px}
.sm-il.v{transform:translate(-50%,-50%) rotate(90deg)}

.sm{position:fixed;inset:0;z-index:850;pointer-events:none;overflow:hidden;visibility:hidden}
.sm.live{visibility:visible}
.sm-pre,.sm-panel{position:absolute;top:0;right:0;height:100%;width:clamp(290px,64vw,440px)}
.sm-prelayer{position:absolute;inset:0;transform:translateX(100%)}
.sm-panel{
  background:var(--bone);color:var(--ink);pointer-events:auto;transform:translateX(100%);
  display:flex;flex-direction:column;padding:104px 34px 36px;overflow-y:auto;
}
@media(max-width:560px){.sm-pre,.sm-panel{width:100%}}
.sm-list{list-style:none;display:flex;flex-direction:column;gap:6px;counter-reset:smi}
.sm-wrap{position:relative;overflow:hidden;line-height:1}
.sm-item{
  position:relative;display:inline-block;text-decoration:none;color:var(--ink);
  font-weight:800;font-stretch:118%;font-size:clamp(32px,9vw,46px);
  letter-spacing:-.035em;line-height:1.06;padding:6px 2.2em 6px 0;
  transition:color .25s;
}
.sm-item:hover{color:var(--gold-txt-2)}
.sm-item::after{
  counter-increment:smi;content:counter(smi,decimal-leading-zero);
  position:absolute;top:.5em;right:.4em;
  font-family:var(--mono);font-size:var(--m3);font-weight:400;color:var(--gold-txt-2);
  opacity:var(--n-op,0);
}
.sm-label{display:inline-block;will-change:transform;transform-origin:50% 100%}
.sm-socials{margin-top:auto;padding-top:34px;border-top:1px solid rgba(11,10,8,.16)}
.sm-socials-title{font-family:var(--mono);font-size:var(--m2);font-weight:400;letter-spacing:var(--m2-ls);text-transform:uppercase;color:var(--gold-txt-2);margin-bottom:14px;opacity:0}
.sm-socials-list{list-style:none;display:flex;gap:20px;flex-wrap:wrap}
.sm-socials-link{font-size:var(--s3);color:var(--ink);transition:color .25s,opacity .25s}
.sm-socials-list:hover .sm-socials-link{opacity:.34}
.sm-socials-list:hover .sm-socials-link:hover{opacity:1;color:var(--gold-txt-2)}

/* ---------------- botão ----------------
   Histórico, para não voltar atrás: aqui já teve preenchimento subindo de baixo
   (500ms, com a cor do rótulo interpolando em 400ms: medido, o contraste caía a
   1,15:1 aos 50ms e o texto apagava por três frames a cada entrada e a cada
   saída) e depois um recorte lateral entrando pelo lado com o rótulo duplicado.
   O recorte era tecnicamente correto, 10,82:1 em qualquer fatia e em qualquer
   estado, e ele reprovou as duas versões, com razão: qualquer efeito que COBRE o
   rótulo depende de duas camadas concordarem em cor, e quando uma delas erra o
   texto desaparece. O defeito era a categoria de efeito, não o ajuste.
   Agora nada cobre o texto. A borda acende, o rótulo clareia e entra um véu de
   âmbar a 10%, em 160ms. Não existe camada, não existe rótulo duplicado, não
   existe quadro intermediário: por construção não dá para ficar ilegível.
   É o registro do Linear e do Vercel, e é o que menos parece template. */
.btn{
  display:inline-flex;align-items:center;gap:11px;
  font-family:var(--mono);font-size:var(--m3);letter-spacing:.08em;text-transform:uppercase;
  padding:15px 26px;border-radius:2px;border:1px solid var(--gold-dim);color:var(--gold-txt);
  position:relative;border-radius:2px;
  transition:border-color 160ms ease,color 160ms ease,background-color 160ms ease,scale 110ms ease-out;
}
.btn s{text-decoration:none}
.btn-fill{background:var(--gold);border-color:var(--gold);color:var(--ink)}
/* hover só onde existe cursor de verdade: no toque ele dispara no tap e fica
   aceso depois que o dedo sai. */
@media(hover:hover) and (pointer:fine){
  .btn:hover{border-color:var(--gold);color:var(--gold-txt);background-color:rgba(255,176,32,.1)}
  /* o primário clareia, nunca escurece: o CTA mais forte da página não pode
     enfraquecer no instante em que a pessoa aponta para clicar. */
  .btn-fill:hover{background-color:var(--gold-hi);color:var(--ink)}
}
/* o site não tinha uma única regra :active. Nenhum dos oito botões respondia ao
   clique, e no celular não existe hover para fazer esse trabalho. */
.btn:active{scale:.985}

/* ---------------- hero ---------------- */
/* o hero era flex-end com margin-bottom:auto no topo, o que abria um vazio morto
   de ~330px no meio da primeira tela. agora é um grid de duas colunas centrado:
   argumento à esquerda, produto rodando à direita. */
/* min-height com teto: 100svh numa tela alta deixa o hero maior que o conteúdo e
   abre um vazio, não importa se em cima (centralizado) ou embaixo (faixa no fim).
   O teto de 960px é a altura que o próprio conteúdo pede, então não sobra. */
/* o padding de cima é a folga da nav, e só. Ele entra inteiro no vazio superior,
   enquanto o de baixo é só a margem automática: com 150px o topo abria 374px e a
   base 224px numa janela de 1270, e a diferença lia como desalinho. Encostado na
   altura real da nav (80px), os dois vazios ficam perto um do outro. */
.hero{min-height:100svh;display:flex;flex-direction:column;padding:clamp(88px,9vh,116px) 0 0;position:relative;overflow:hidden;isolation:isolate}
/* A conversa é a única fonte de luz da cena: o brilho nasce atrás do card e vaza
   para o ambiente, e as bordas caem para a tinta. É o que dá profundidade sem
   imagem de fundo, e é temático, porque é a conversa que ilumina o negócio. */
.hero::before{content:"";position:absolute;z-index:0;pointer-events:none;
  top:-8%;right:-14%;width:74%;height:96%;
  background:radial-gradient(48% 46% at 62% 46%,rgba(255,176,32,.16),rgba(255,176,32,.05) 46%,transparent 72%);
  filter:blur(34px)}
.hero::after{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:radial-gradient(122% 88% at 66% 44%,transparent 34%,rgba(10,9,7,.5) 78%,rgba(8,7,5,.82) 100%)}
/* margin auto no bloco central: o conteúdo centraliza no espaço que sobra e a faixa
   fica colada na base do hero, dentro da primeira tela */
/* conteúdo no topo e faixa logo depois, com margem fixa. nada de margin auto aqui:
   é o que empurrava a faixa para a base e abria o vazio no meio. */
.hero > .wrap{position:relative;z-index:3}
/* o bloco de conteúdo flutua no espaço que sobra e a faixa encosta na base:
   é o que transforma o vão entre o botão e a próxima seção em composição */
.hero > .wrap:not(.marq-lab){margin-block:auto}
.hero .marq-lab{position:relative;z-index:3}
/* Este rótulo não é rótulo: é a legenda que explica o que são as palavras gigantes
   que passam embaixo. Estava no degrau m2, 11,5px, contra letra de 62px na faixa,
   razão de 5,4 para 1: ninguém lia, e sem ele o marquee é só palavra correndo sem
   dizer que aquilo é a lista de canais que o CRM conecta.
   Passou por 15px e voltou para o degrau m3, que é exatamente o que a escala
   define: "texto em mono que se lê como frase". Sem inventar um tamanho novo fora
   dos tokens. Tracking .08em, porque o .12em do rótulo esparrama uma linha longa,
   e cor --bone-2, o mesmo do INFO da marca, um tom acima do cinza de apoio. */
.hero .marq-lab p{padding-bottom:13px;font-size:var(--m3);letter-spacing:.08em;
  text-transform:uppercase;color:var(--bone-2)}
/* Folga mínima acima da legenda. O bloco do hero flutua com margin-block:auto e a
   faixa encosta na base, então a distância entre o texto do botão e esta legenda
   é o que sobrar: medido, ia de 131px numa janela de 1100 de altura a 1px numa de
   768, onde a legenda encostava na linha de cima. Era isso que lia como torto.
   O auto continua distribuindo a sobra; o que este mínimo faz é impedir o encosto. */
.hero .marq-lab{margin-top:clamp(24px,3vh,46px)}
.hero .marq{position:relative;z-index:3}

/* no hero o eyebrow perde o tracinho: ele empurrava o TEXTO 34px para dentro,
   e o olho lia o texto (não o traço) como o início da coluna, contra o título,
   o parágrafo e o botão que começam na margem. nas outras seções o traço fica. */
.hero-top .eyebrow::before{display:none}
.hero-top{display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap;margin-bottom:clamp(30px,5vh,56px)}
.hero h1{margin-top:0}
/* o card tem largura fixa (428px), então não precisa de metade do grid.
   coluna do texto pega todo o resto, e o título ganha espaço para respirar. */
/* coluna do texto domina e o card sai da margem do wrap, indo para perto da borda.
   duas colunas de peso igual eram o que deixava a composição chapada. */
/* uma coluna só: a foto ocupa a direita, e nada passa de 52% porque a partir daí
   a luz da imagem derruba o contraste abaixo do legível */
.hero-grid{display:block;max-width:min(640px,49%)}
.hero-grid > div > .h1,.hero-grid > div > .lead{max-width:46ch}
@media(max-width:900px){.hero-grid{max-width:100%}.hero-chat{margin-top:30px}}
.hero-chat{display:flex;justify-content:flex-end}

/* a coluna tem ~45% da largura. a linha mais longa do título ("Sua empresa atendendo",
   21 caracteres) só cabe até ~3.9vw; 3.6vw dá folga para o eixo de largura da Archivo. */
.hero-grid .h1{font-size:clamp(32px,4.1vw,58px);line-height:1}
@media(max-width:1000px){
  .hero-grid{grid-template-columns:1fr;gap:40px}
  .hero-grid .h1{font-size:clamp(27px,7.4vw,76px)}
  .hero-chat{justify-content:flex-start;margin-right:0}
  .hero{min-height:0}
}
.hero h1 .ln{display:block;overflow:hidden}
.hero h1 .ln>span{display:block}
/* O título só nasce escondido quando a abertura completa vai rodar. A decisão
   é tomada por um script síncrono no topo do index, antes do primeiro quadro.
   Sem esta condição, quem chega por anúncio (ou com o GSAP lento, bloqueado por
   extensão ou fora do ar) via o hero sem título nenhum. Regra da casa: estado
   final por padrão, animação como bônus. */
[data-abertura="completa"].js .hero h1 .ln>span{transform:translateY(106%)}
@keyframes blip{0%,100%{opacity:1}50%{opacity:.2}}
.hero-cta{margin-top:clamp(30px,4vw,44px)}
.hero-btns{display:flex;gap:12px;flex-wrap:wrap}
.hero-btns .btn{justify-content:center}
.hero-cta p{font-size:var(--s2);color:var(--gray);line-height:1.5;margin-top:16px}
@media(max-width:520px){.hero-btns{flex-direction:column}.hero-btns .btn{width:100%}}

/* ---------------- fundo do hero ----------------
   Vídeo a 18% de opacidade: medi o pico de luz dele em 0,85 e, acima de 20%,
   o texto cai abaixo de contraste 7. Nessa faixa ele existe como atmosfera
   sem disputar leitura. Pôster carrega sempre; o vídeo só entra depois do load. */
.hero-bg video.on{opacity:.18}
/* funde topo e base com a página e alivia o lado do texto */
@media(max-width:900px){.hero-bg img,.hero-bg video,.hero-bg video.on{opacity:.12}}

/* ---------------- foto do hero ----------------
   A metade esquerda da imagem tem luminância 0,0014, mais escura que o próprio
   fundo do site: por isso ela entra em opacidade cheia, sem tarja escurecedora.
   O texto fica limitado a 52% da largura porque, a partir de 55%, a luz da foto
   derruba o contraste abaixo do mínimo legível. */
.hero-foto{position:absolute;inset:0;z-index:0;overflow:hidden;pointer-events:none}
.hero-foto img{width:100%;height:100%;object-fit:cover;object-position:center}
.hero-foto::after{content:"";position:absolute;inset:0;background:
  linear-gradient(180deg,var(--ink) 0%,rgba(11,10,8,.3) 14%,rgba(11,10,8,.18) 52%,rgba(11,10,8,.7) 84%,var(--ink) 100%),
  linear-gradient(90deg,rgba(11,10,8,.55) 0%,rgba(11,10,8,.18) 36%,transparent 54%)}
@media(max-width:900px){
  .hero-foto img{object-position:62% center}
  .hero-foto::after{background:linear-gradient(180deg,var(--ink) 0%,rgba(11,10,8,.55) 22%,rgba(11,10,8,.6) 60%,var(--ink) 100%)}
}

/* ---------------- balão ancorado no celular da foto ----------------
   Fica no vão entre o rosto e o texto, onde a foto é quase sete vezes mais escura
   (pico 0,04 contra 0,44 sobre o aparelho): o balão é translúcido, então fundo
   escuro e uniforme deixa o texto interno legível. A animação sobe de baixo, na
   direção do celular, para manter a leitura de que é o que ele está lendo.
   Vidro de verdade: só funciona porque existe foto atrás.

   POSIÇÃO É CALCULADA EM JS, contra a foto, não contra a tela. Medido na imagem:
   a tela do aparelho ocupa x 56,9-61,7% e y 58,2-70,9%; o rosto começa em x 68%.
   Como a foto é object-fit:cover, esses pontos andam na tela conforme a proporção
   da janela, e nenhuma porcentagem de CSS acompanha isso. Preso no CSS, o balão
   cobria 31% da cabeça dele em 1280x720 e 25% em 1366x768.
   O que está aqui embaixo é o retrato falado para quem estiver sem JavaScript. */
.balao{position:absolute;left:52%;bottom:46%;z-index:2;width:min(310px,25vw);
  transform:none;transform-origin:70% 130%;
  border-radius:15px;padding:13px 14px;overflow:hidden;isolation:isolate;
  background:rgba(245,241,234,.07);
  -webkit-backdrop-filter:blur(16px) saturate(1.25);backdrop-filter:blur(16px) saturate(1.25);
  box-shadow:0 26px 60px -18px rgba(0,0,0,.8),inset 0 1px 0 rgba(255,255,255,.16);
  opacity:0}
/* borda de vidro: gradiente recortado por máscara, só no contorno */
.balao::before{content:"";position:absolute;inset:0;border-radius:inherit;padding:1.2px;pointer-events:none;
  background:linear-gradient(170deg,rgba(255,255,255,.42) 0%,rgba(255,255,255,.1) 34%,transparent 62%,rgba(255,255,255,.22) 100%);
  -webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;
  mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);mask-composite:exclude}
.balao.on{animation:balaoEntra .62s var(--ease) forwards}
@keyframes balaoEntra{
  from{opacity:0;transform:translateY(22px) scale(.86)}
  to{opacity:1;transform:none}
}
.balao-t{display:flex;align-items:center;gap:6px;font-family:var(--mono);font-size:var(--m1);letter-spacing:var(--m1-ls);
  text-transform:uppercase;color:var(--gold-txt);margin-bottom:9px}
.balao-t svg{width:11px;height:11px}
.balao-m{font-size:var(--s1);line-height:1.42;border-radius:11px;padding:8px 10px;margin-bottom:7px;
  background:rgba(11,10,8,.5);color:var(--bone);box-shadow:inset 0 0 0 1px rgba(245,241,234,.1)}
.balao-r{font-size:var(--s1);line-height:1.42;border-radius:11px;padding:8px 10px;
  background:rgba(255,176,32,.17);color:var(--bone);box-shadow:inset 0 0 0 1px rgba(255,176,32,.32)}
.balao-h{display:block;font-family:var(--mono);font-size:var(--m1);color:var(--gray);margin-top:5px}
/* em tela estreita o recorte da foto muda e a âncora deixa de bater */
@media(max-width:1000px){.balao{display:none}}
@media (prefers-reduced-motion:reduce){.balao,.balao.on{opacity:1;transform:none;animation:none}}

/* ---------------- janela de atendimento (portada do projeto da Ubli) ----------------
   Demonstra o produto em vez de descrever: cliente pergunta, IA digita, IA responde,
   e o ciclo passa pelos 5 canais na mesma caixa de entrada. Cores da paleta INFOHUB;
   só os logos dos canais mantêm a cor original de cada marca. */
.chat{
  width:100%;max-width:428px;border:1px solid var(--line-2);border-radius:14px;
  background:var(--ink-2);overflow:hidden;position:relative;isolation:isolate;
  /* sombra tingida de âmbar, não preta: a luz da cena vem da própria conversa.
     a borda superior clara simula o reflexo de uma tela acesa. */
  box-shadow:
    0 42px 90px -22px rgba(0,0,0,.78),
    0 18px 44px -18px rgba(255,176,32,.22),
    0 1px 0 rgba(245,241,234,.07) inset;
}
.chat::before{
  content:"";position:absolute;inset:-30% -18% auto;height:62%;z-index:-1;
  background:radial-gradient(60% 60% at 50% 50%,rgba(255,176,32,.16),transparent 70%);
  filter:blur(26px);pointer-events:none;
}
.chat-h{display:flex;align-items:center;gap:12px;padding:13px 15px;border-bottom:1px solid var(--line);background:rgba(31,28,24,.55)}
.chat-av{position:relative;width:38px;height:38px;border-radius:50%;flex:none;display:grid;place-items:center;background:var(--ink-3);box-shadow:inset 0 0 0 1px var(--line-2)}
.chat-av svg{width:19px;height:19px}
.chat-av::after{content:"";position:absolute;right:-1px;bottom:-1px;width:11px;height:11px;border-radius:50%;background:#25D366;border:2px solid var(--ink-2)}
.chat-id{min-width:0;line-height:1.25}
.chat-id b{display:block;font-size:13.5px;font-weight:600;color:var(--bone);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chat-id span{display:block;font-family:var(--mono);font-size:10.5px;color:var(--gray);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chat-tag{margin-left:auto;flex:none;display:inline-flex;align-items:center;gap:5px;border-radius:100px;padding:4px 9px;font-size:10.5px;font-weight:500}
.chat-tag svg{width:12px;height:12px}
.chat-ch{display:flex;align-items:center;gap:4px;padding:8px 12px;border-bottom:1px solid var(--line);background:rgba(31,28,24,.3)}
/* 11.5px, e só aqui dentro do mock. Os chips não são textura: são a prova visual
   dos seis canais numa caixa só, que é o argumento da seção. Os outros miúdos do
   mock (handle, divisor de dia, hora da bolha) continuam pequenos de propósito,
   porque são ambientação e app de mensagem é assim mesmo.
   Medido: cabe até 12px sem vazar, já que só o canal ativo mostra o nome. */
.chat-chip{display:inline-flex;align-items:center;gap:6px;border-radius:100px;padding:4px 6px;font-size:11.5px;font-weight:500;color:var(--gray);transition:background .35s var(--ease),padding .35s var(--ease),color .35s}
.chat-chip svg{width:14px;height:14px;flex:none;opacity:.8;transition:opacity .35s}
.chat-chip.on{background:rgba(255,176,32,.14);padding:4px 10px;color:var(--bone);box-shadow:inset 0 0 0 1px rgba(255,176,32,.38)}
.chat-chip.on svg{opacity:1}
.chat-chip b{display:none;font-weight:500}
.chat-chip.on b{display:inline}
.chat-b{
  /* ALTURA FIXA, e nao min-height. Medido pelo Lighthouse em 06/08/2026: a pagina
     do CRM tinha CLS de 0,243, quase tres vezes o limite de 0,1, e a causa era
     "web font loaded". Com a fonte do sistema o texto ocupa mais linhas e a caixa
     estica; quando a Archivo chega, ela encolhe de uma vez e empurra meia pagina.
     Com altura fixa a caixa nunca muda, venha a fonte quando vier. O que passar
     sai por cima, que e o comportamento certo aqui: justify-content e flex-end e
     app de mensagem esconde mensagem antiga, nao a nova. */
  height:286px;display:flex;flex-direction:column;justify-content:flex-end;gap:9px;padding:18px 15px;
  background-image:radial-gradient(rgba(245,241,234,.055) 1px,transparent 1px);background-size:17px 17px;
}
.chat-day{align-self:center;background:var(--ink-3);color:var(--gray);font-size:10.5px;border-radius:100px;padding:3px 11px;margin-bottom:2px}
.chat-msg{max-width:84%;font-size:13px;line-height:1.42;border-radius:14px;padding:9px 12px;opacity:0;transform:translateY(9px) scale(.985)}
.chat-msg.vis{opacity:1;transform:none;transition:opacity .42s var(--ease),transform .42s var(--ease)}
.chat-in{align-self:flex-start;border-bottom-left-radius:4px;background:var(--ink-3);color:var(--bone);box-shadow:inset 0 0 0 1px var(--line)}
.chat-out{align-self:flex-end;border-bottom-right-radius:4px;background:rgba(255,176,32,.13);color:var(--bone);box-shadow:inset 0 0 0 1px rgba(255,176,32,.28)}
.chat-msg .hr{margin-left:7px;font-family:var(--mono);font-size:9.5px;color:var(--gray);white-space:nowrap}
.chat-out .hr{color:var(--gold-txt)}
.chat-ia{align-self:flex-end;display:flex;align-items:center;gap:5px;margin-bottom:-3px;font-family:var(--mono);font-size:9.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--gray);opacity:0;transition:opacity .4s var(--ease)}
.chat-ia.vis{opacity:1}
.chat-ia svg{width:11px;height:11px;color:var(--gold-txt)}
.chat-typ{align-self:flex-end;display:none;align-items:center;gap:5px;border-radius:14px;border-bottom-right-radius:4px;padding:11px 14px;background:rgba(255,176,32,.13);box-shadow:inset 0 0 0 1px rgba(255,176,32,.24)}
.chat-typ.vis{display:inline-flex}
.chat-typ i{width:5px;height:5px;border-radius:50%;background:var(--gold);animation:typ .9s infinite ease-in-out}
.chat-typ i:nth-child(2){animation-delay:.15s}
.chat-typ i:nth-child(3){animation-delay:.3s}
@keyframes typ{0%,100%{opacity:.3;transform:translateY(0)}50%{opacity:1;transform:translateY(-2px)}}
.chat-f{display:flex;align-items:center;gap:9px;padding:12px 15px;border-top:1px solid var(--line);background:rgba(31,28,24,.55);font-size:11.5px;color:var(--gray)}
.chat-live{width:7px;height:7px;border-radius:50%;background:#25D366;flex:none;animation:blip 1.9s infinite}
@media (prefers-reduced-motion:reduce){
  .chat-msg{opacity:1;transform:none}
  .chat-ia{opacity:1}
}
/* faixa da marca. proporções presas ao tamanho da letra (em), então a altura da
   faixa e o respiro entre palavras acompanham a fonte em qualquer viewport. */
.marq{border-block:1px solid var(--line);overflow:hidden;white-space:nowrap;position:relative}
/* 62px era a coisa mais forte da primeira tela, mais forte que o próprio h1 em
   presença, e empurrava a legenda para o irrelevante. 44px continua sendo faixa
   de marca e devolve 30px de altura para o hero. Razão com a legenda: 2,9 para 1. */
.marq-in{display:inline-flex;align-items:center;will-change:transform;
  font-weight:800;font-stretch:118%;font-size:clamp(26px,3.2vw,44px);letter-spacing:-.035em;line-height:1}
.marq-in span{padding:.34em .58em;display:inline-block}
.marq-in span:nth-child(even){color:transparent;-webkit-text-stroke:1px var(--gold-dim)}

/* ---------------- faixa de plataformas ---------------- */
@keyframes loopRun{from{transform:translate3d(0,0,0)}to{transform:translate3d(-50%,0,0)}}

/* ---------------- serviços ---------------- */
.svc{border-top:1px solid var(--line)}
.svc-item{border-bottom:1px solid var(--line);transition:background 200ms ease}
.svc-btn{width:100%;display:grid;grid-template-columns:86px 1fr auto auto;align-items:center;gap:22px;text-align:left;padding:28px 6px}
/* o hover empurrava a linha inteira animando padding-left, que é propriedade de
   layout: 20px em 500ms, com reflow a cada frame, e o "+" da direita andava
   junto. Agora só o número e a pergunta deslizam, 10px em 220ms, por translate.
   O "+" fica onde está, que é o certo: ele é o indicador de estado, não parte do
   gesto de hover. */
.svc-code,.svc-btn .h3{transition:translate 220ms var(--ease)}
@media(hover:hover) and (pointer:fine){
  .svc-item:hover{background:var(--ink-2)}
  .svc-item:hover .svc-code,.svc-item:hover .svc-btn .h3{translate:10px}
}
/* aqui não entra press de escala: o retorno do clique é a linha abrindo, que já
   é imediata. Escala numa faixa de largura inteira só chamaria atenção. */
.svc-code{font-family:var(--mono);font-size:var(--m2);letter-spacing:var(--m2-ls);color:var(--gold-txt)}
@media(max-width:800px){.svc-btn{grid-template-columns:56px 1fr auto;gap:14px}}
.plus{width:15px;height:15px;position:relative;flex:none;color:var(--gold-txt)}
/* 260ms, não 450: é resposta a clique, e resposta a clique tem que ser rápida */
.plus::before,.plus::after{content:"";position:absolute;background:currentColor;transition:transform 260ms var(--ease)}
.plus::before{left:0;top:7px;width:15px;height:1px}
.plus::after{top:0;left:7px;height:15px;width:1px}
.open .plus::after{transform:rotate(90deg)}
.body{height:0;overflow:hidden}
.body-in{padding:0 6px 32px;display:grid;grid-template-columns:1.3fr 1fr;gap:34px;align-items:start}
@media(max-width:800px){.body-in{grid-template-columns:1fr;gap:20px}}
.body-in ul{list-style:none;display:grid;gap:9px;font-family:var(--mono);font-size:var(--m3)}
.body-in ul li{display:flex;gap:11px;color:var(--gray)}
.body-in ul li::before{content:"·";color:var(--gold-txt-2);flex:none}

/* ---------------- comparativo dos dois produtos ----------------
   Portado do Solutions/Compare do projeto da Ubli. O CRM é o card destacado
   porque é o que serve para a maioria; a API fica ao lado, secundária. */
.sol{display:grid;grid-template-columns:1fr 1.12fr;gap:clamp(18px,2vw,26px);align-items:start}
@media(max-width:900px){.sol{grid-template-columns:1fr}}
/* height:100% de volta: soltar a altura deixou os dois cartões terminando em
   pontos diferentes e ele achou desalinhado. Com a ficha da API preenchendo o
   cartão, o vão interno que sobra é ~200px, contra os 428px do começo. */
.sol-c{border:1px solid var(--line-2);border-radius:14px;padding:clamp(24px,2.4vw,34px);background:var(--ink);display:flex;flex-direction:column;height:100%}
.sol{align-items:stretch}
.sol-c.destaque{background:linear-gradient(168deg,rgba(255,176,32,.13),rgba(255,176,32,.04) 46%,transparent);border-color:rgba(255,176,32,.4);position:relative}
.sol-tag{font-family:var(--mono);font-size:var(--m2);letter-spacing:var(--m2-ls);text-transform:uppercase;color:var(--gold-txt-2);display:block;margin-bottom:12px}
.sol-c.destaque .sol-tag{color:var(--gold-txt)}
.sol-c h3{font-weight:700;font-stretch:118%;font-size:clamp(23px,2.3vw,30px);letter-spacing:-.025em;line-height:1.08;margin-bottom:12px}
.sol-c > p{font-size:var(--s2);color:var(--gray);line-height:1.55;margin-bottom:22px;max-width:46ch}
/* ficha da API: mesmo tratamento do bloco de limites dos planos, para os dois
   cartões desta seção terem o mesmo tipo de "painel de especificação" */
.sol-api{background:rgba(245,241,234,.045);border-radius:10px;padding:16px 18px;margin-bottom:22px}
.sol-api-t{font-family:var(--mono);font-size:var(--m2);letter-spacing:var(--m2-ls);
  text-transform:uppercase;color:var(--gray);margin-bottom:13px}
.sol-api-l{list-style:none;display:grid;grid-template-columns:repeat(3,1fr);gap:10px 14px;
  font-family:var(--mono);font-size:var(--m2);color:var(--bone);letter-spacing:.03em;margin-bottom:15px}
@media(max-width:420px){.sol-api-l{grid-template-columns:repeat(2,1fr)}}
.sol-api-w{font-size:var(--s1);color:var(--gray);line-height:1.5;
  border-top:1px solid var(--line);padding-top:13px}
.sol-shot{border:1px solid var(--line-2);border-radius:8px;overflow:hidden;margin-bottom:22px;background:var(--ink-2);line-height:0}
.sol-shot img{width:100%;height:auto;display:block}
.sol-l{list-style:none;display:grid;grid-template-columns:1fr 1fr;gap:9px 18px;margin-bottom:26px}
@media(max-width:560px){.sol-l{grid-template-columns:1fr}}
.sol-l li{display:flex;gap:9px;font-size:var(--s2);color:var(--bone-2);line-height:1.4}
.sol-l li::before{content:"";width:5px;height:5px;border-radius:50%;background:var(--gold-dim);flex:none;margin-top:7px}
.sol-c.destaque .sol-l li::before{background:var(--gold)}
.sol-pe{display:flex;align-items:flex-end;justify-content:space-between;gap:18px;flex-wrap:wrap;margin-top:auto;padding-top:22px;border-top:1px solid var(--line)}
.sol-pe span{font-family:var(--mono);font-size:var(--m2);color:var(--gray);display:block;margin-bottom:4px}
.sol-pe b{font-weight:800;font-stretch:118%;font-size:clamp(26px,2.7vw,36px);letter-spacing:-.035em;line-height:1}
.sol-pe b i{font-style:normal;font-size:.45em;font-weight:500;color:var(--gray);letter-spacing:0}
.sol-c.destaque .sol-pe b{color:var(--gold-txt)}
/* qual serve para você */
.qual{margin-top:clamp(30px,3.5vw,48px);border:1px solid var(--line);border-radius:14px;padding:clamp(26px,3vw,40px);background:var(--ink-2)}
.qual h3{font-weight:700;font-stretch:118%;font-size:clamp(19px,2vw,25px);letter-spacing:-.02em;margin-bottom:clamp(22px,2.5vw,32px)}
.qual-g{display:grid;grid-template-columns:1fr 1fr;gap:clamp(24px,3vw,52px)}
@media(max-width:760px){.qual-g{grid-template-columns:1fr;gap:30px}}
.qual-g h4{font-family:var(--mono);font-size:var(--m2);letter-spacing:var(--m2-ls);text-transform:uppercase;color:var(--gold-txt);margin-bottom:16px;font-weight:400}
.qual-g ul{list-style:none;display:grid;gap:11px}
.qual-g li{display:flex;gap:11px;font-size:var(--s2);color:var(--bone-2);line-height:1.45}
.qual-g li::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--gold-dim);flex:none;margin-top:8px}

/* ---------------- resultados ---------------- */

/* ---------------- planos ----------------
   Três níveis reais do CRM. O add-on de IA aparece separado e em destaque porque
   é a informação que o cliente descobre tarde se a gente não contar aqui. */
.pl{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.6vw,20px);align-items:stretch}
@media(max-width:900px){.pl{grid-template-columns:1fr}}
.pl-c{border:1px solid var(--line-2);border-radius:14px;padding:clamp(22px,2.2vw,30px);background:var(--ink);display:flex;flex-direction:column}
.pl-c.pop{border-color:rgba(255,176,32,.45);background:linear-gradient(170deg,rgba(255,176,32,.1),transparent 55%);position:relative}
/* a etiqueta ficava montada em cima da borda (top:-1px com translate de -50%),
   meio dentro meio fora, e lia como coisa solta. Agora mora dentro do cartão. */
.pl-sel{position:absolute;top:14px;right:14px;background:var(--gold);color:var(--ink);font-family:var(--mono);font-size:var(--m2);letter-spacing:var(--m2-ls);text-transform:uppercase;padding:4px 10px;border-radius:2px}
.pl-n{font-weight:700;font-stretch:118%;font-size:20px;letter-spacing:-.02em}
.pl-d{font-size:var(--s1);color:var(--gray);margin-top:4px;margin-bottom:18px}
/* flex-wrap porque o sufixo do preço pode ser longo ("/mês o primeiro", na página
   da API) e num cartão de 345px ele não cabe ao lado do valor. Sem a quebra, ele
   empurrava a página: medido, 6px de rolagem horizontal em 360px. */
.pl-v{display:flex;align-items:flex-end;gap:3px;flex-wrap:wrap;padding-bottom:18px;border-bottom:1px solid var(--line);margin-bottom:18px}
.pl-v b{font-weight:800;font-stretch:118%;font-size:clamp(30px,3vw,40px);letter-spacing:-.04em;line-height:1}
.pl-c.pop .pl-v b{color:var(--gold-txt)}
.pl-v i{font-style:normal;font-size:var(--s2);color:var(--gray);padding-bottom:3px}
/* os limites são a ficha técnica do plano, o que o cliente compara de fato.
   Em gold-dim solto na coluna liam como enfeite; num bloco próprio, viram tabela. */
.pl-lim{list-style:none;display:grid;gap:7px;margin-bottom:18px;font-family:var(--mono);font-size:var(--m2);
  color:var(--bone);letter-spacing:.03em;background:rgba(245,241,234,.045);border-radius:8px;padding:13px 15px}
.pl-f{list-style:none;display:grid;gap:9px;margin-bottom:24px}
.pl-f li{display:flex;gap:9px;font-size:var(--s2);color:var(--bone-2);line-height:1.4}
.pl-f li::before{content:"";width:5px;height:5px;border-radius:50%;background:var(--gold-dim);flex:none;margin-top:7px}
.pl-c .btn{justify-content:center}
/* aviso do add-on: o dado que muda a conta do cliente */
.addon{margin-top:clamp(26px,3vw,40px);border:1px solid var(--gold-dim);border-left:3px solid var(--gold);border-radius:4px;padding:clamp(22px,2.4vw,30px);background:rgba(255,176,32,.05)}
.addon h3{font-weight:700;font-stretch:118%;font-size:19px;letter-spacing:-.02em;margin-bottom:8px}
.addon > p{font-size:var(--s2);color:var(--bone-2);line-height:1.55;max-width:70ch;margin-bottom:20px}
.addon-g{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-bottom:18px}
@media(max-width:700px){.addon-g{grid-template-columns:1fr}}
.addon-i{border:1px solid var(--line);border-radius:8px;padding:14px 16px;background:var(--ink)}
.addon-i b{display:block;font-weight:700;font-stretch:118%;font-size:20px;letter-spacing:-.03em;color:var(--gold-txt)}
.addon-i span{display:block;font-size:var(--s1);color:var(--gray);margin-top:3px}
.addon-nota{font-size:var(--s2);color:var(--bone-2);line-height:1.55;border-top:1px solid var(--line);padding-top:16px}
.pl-desc{display:flex;gap:22px;flex-wrap:wrap;margin-top:22px;font-family:var(--mono);font-size:var(--m2);color:var(--gray)}
.pl-desc b{color:var(--gold-txt);font-weight:500}

/* aviso da IA dentro de cada plano, não numa caixa solta lá embaixo: é onde o
   número está sendo lido, e é ali que a ressalva precisa aparecer */
/* margin-top:auto vive aqui, e não no botão: as listas de recurso têm tamanhos
   diferentes, então empurrar só o botão deixava o aviso boiando em três alturas */
.pl-ia{font-size:var(--s1);color:var(--gold-txt-2);line-height:1.5;
  border-top:1px solid var(--line);padding-top:14px;margin-top:auto;margin-bottom:18px}

.pl-extra{display:grid;grid-template-columns:1fr 1fr;gap:clamp(16px,2vw,24px);margin-top:clamp(22px,2.6vw,34px)}
@media(max-width:820px){.pl-extra{grid-template-columns:1fr}}
.pl-extra > div{border:1px solid var(--line);border-radius:12px;padding:clamp(20px,2.2vw,26px);background:var(--ink-2)}
.pl-extra h3{font-weight:700;font-stretch:118%;font-size:19px;letter-spacing:-.02em;margin-bottom:9px}
.pl-extra p{font-size:var(--s2);color:var(--bone-2);line-height:1.55}
.pl-gb{display:flex;flex-wrap:wrap;gap:9px;margin-top:16px}
.pl-gb span{border:1px solid var(--line-2);border-radius:2px;padding:8px 13px;
  font-family:var(--mono);font-size:var(--m2);letter-spacing:var(--m2-ls);color:var(--gray)}
.pl-gb b{color:var(--gold-txt);font-weight:500}
.pl-nota{font-size:var(--s1);color:var(--gray);line-height:1.55;border-top:1px solid var(--line);margin-top:18px;padding-top:14px}

/* ---------------- processo ---------------- */
.ubli-grid{display:grid;grid-template-columns:1fr 1.05fr;gap:clamp(34px,6vw,84px);align-items:start}
/* O h2 desta seção vive numa coluna de 564px num monitor de 1440, e estava com o
   mesmo corpo dos títulos que ocupam a largura inteira: 67,7px. Medido, qualquer
   frase quebrava em 5 linhas e 318px de altura, e o título anterior já sofria
   disso em 4. Não é o texto que era comprido, é a proporção que estava errada. */
.ubli-grid .h2{font-size:clamp(29px,3.4vw,50px)}

@media(max-width:900px){.ubli-grid{grid-template-columns:1fr}}
.ubli-tag{
  display:inline-flex;align-items:center;gap:9px;font-family:var(--mono);font-size:var(--m2);
  letter-spacing:var(--m2-ls);text-transform:uppercase;color:var(--gold-txt);
  border:1px solid var(--gold-dim);border-radius:100px;padding:7px 15px;margin-bottom:22px;
}
.ubli-tag i{width:6px;height:6px;border-radius:50%;background:var(--gold);font-style:normal;animation:blip 1.9s infinite}
.flow-list{border-top:1px solid var(--line);counter-reset:fl}
.flow-item{display:grid;grid-template-columns:44px 1fr;gap:18px;align-items:start;padding:22px 4px;border-bottom:1px solid var(--line)}
.flow-item::before{
  counter-increment:fl;content:counter(fl,decimal-leading-zero);
  font-family:var(--mono);font-size:var(--m2);color:var(--gold-txt-2);letter-spacing:var(--m2-ls);padding-top:3px;
}
.flow-item b{display:block;font-weight:700;font-stretch:118%;font-size:19px;letter-spacing:-.02em;margin-bottom:5px}
.flow-item p{font-size:var(--s2);color:var(--gray);line-height:1.5}
/* ---------------- linha do tempo do atendimento ----------------
   O caminho da mensagem até a venda. Horizontal no desktop (não repete o SVG
   circular do ciclo), vertical no celular. */
.tl{position:relative;display:grid;grid-template-columns:repeat(5,1fr);gap:0;margin-top:clamp(34px,4vw,52px)}
.tl::before{content:"";position:absolute;top:46px;left:8%;right:8%;height:1px;
  background:linear-gradient(90deg,transparent,var(--gold-dim) 12%,var(--gold-dim) 88%,transparent)}
.tl-s{position:relative;padding:0 10px;text-align:center}
.tl-t{font-family:var(--mono);font-size:var(--m2);letter-spacing:var(--m2-ls);text-transform:uppercase;color:var(--gold-txt);display:block;margin-bottom:16px;min-height:2.4em}
.tl-d{position:relative;width:15px;height:15px;margin:0 auto 18px;border-radius:50%;background:var(--ink);
  box-shadow:inset 0 0 0 1px var(--gold-dim);display:grid;place-items:center}
.tl-d::after{content:"";width:6px;height:6px;border-radius:50%;background:var(--gold)}
.tl-s.on .tl-d{box-shadow:inset 0 0 0 1px var(--gold),0 0 18px rgba(255,176,32,.55)}
.tl-s b{display:block;font-weight:700;font-stretch:118%;font-size:16px;letter-spacing:-.02em;margin-bottom:6px}
.tl-s p{font-size:var(--s1);color:var(--gray);line-height:1.45}
@media(max-width:900px){
  .tl{grid-template-columns:1fr;gap:0}
  .tl::before{top:8px;bottom:8px;left:7px;right:auto;width:1px;height:auto;
    background:linear-gradient(180deg,transparent,var(--gold-dim) 8%,var(--gold-dim) 92%,transparent)}
  .tl-s{display:grid;grid-template-columns:15px 1fr;gap:0 18px;text-align:left;padding:0 0 26px}
  .tl-d{margin:5px 0 0}
  .tl-t{grid-column:2;min-height:0;margin-bottom:5px}
  .tl-s b,.tl-s p{grid-column:2}
}
/* números do setor, com fonte declarada. não são resultados da INFOHUB. */
.bm{display:grid;grid-template-columns:repeat(3,1fr);gap:26px;margin-top:clamp(40px,5vw,64px);
  border-top:1px solid var(--line);padding-top:28px}
@media(max-width:760px){.bm{grid-template-columns:1fr;gap:22px}}

/* recursos do Ubli: 2 colunas com hairline, sem card e sem ícone, para não repetir
   nem o grid de 4 do processo nem a lista de linhas dos preços */
.rec{display:grid;grid-template-columns:1fr 1fr;gap:0 clamp(34px,5vw,72px);border-top:1px solid var(--line)}
@media(max-width:820px){.rec{grid-template-columns:1fr}}
.rec-i{padding:26px 0;border-bottom:1px solid var(--line);display:grid;grid-template-columns:38px 1fr;gap:16px;align-items:start}
/* #B7801B em vez do --gold-dim: a numeração media 4,44 de contraste contra o
   mínimo de 4,5. Passava raspando por baixo, agora passa por cima. */
.rec-i span{font-family:var(--mono);font-size:var(--m2);color:#B7801B;letter-spacing:var(--m2-ls);padding-top:4px}
.rec-i b{display:block;font-weight:700;font-stretch:118%;font-size:19px;letter-spacing:-.02em;margin-bottom:6px}
.rec-i p{font-size:var(--s2);color:var(--gray);line-height:1.5}

.proc{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--line);border-block:1px solid var(--line)}
@media(max-width:820px){.proc{grid-template-columns:repeat(2,1fr)}}
.step{background:var(--ink);padding:30px 24px 38px}
.step-n{font-family:var(--mono);font-size:var(--m2);color:var(--gold-txt);margin-bottom:24px;letter-spacing:var(--m2-ls)}
.step h3{font-weight:700;font-stretch:118%;font-size:20px;letter-spacing:-.025em;margin-bottom:8px}
.step p{font-size:var(--s2);color:var(--gray);line-height:1.5}

/* ---------------- números ---------------- */
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:40px 26px}
@media(max-width:820px){.stats{grid-template-columns:repeat(2,1fr)}}
.stat{border-top:1px solid var(--line-2);padding-top:18px}
.odo{display:flex;align-items:flex-end;font-weight:800;font-stretch:118%;font-size:clamp(40px,5.6vw,78px);letter-spacing:-.05em;line-height:.9}
.odo .col{height:1em;overflow:hidden;display:block}
.odo .col u{display:block;text-decoration:none;will-change:transform}
.odo .suf{color:var(--gold-txt);font-size:.4em;align-self:flex-end;padding-bottom:.32em;margin-left:.13em;letter-spacing:0}
.stat-l{font-family:var(--mono);font-size:var(--m3);margin-top:14px;letter-spacing:var(--m3-ls)}
.stat-s{font-size:var(--s2);color:var(--gray);margin-top:3px}

/* ---------------- faq ---------------- */
.faq-grid{display:grid;grid-template-columns:.75fr 1.45fr;gap:clamp(30px,6vw,80px);align-items:start}
@media(max-width:900px){.faq-grid{grid-template-columns:1fr}}
.faq .svc-btn{grid-template-columns:56px 1fr auto}
.faq .svc-item:hover .svc-btn{padding-left:6px}
.faq .svc-item:hover{background:none}
.faq .body-in{grid-template-columns:1fr;max-width:64ch}

/* FIM DA LISTA: dois destinos, no mesmo desenho das perguntas.
   Antes era um parágrafo com os dois links dentro do .faq-grid. Como o grid tem
   duas colunas e ele era o terceiro filho, caía sozinho na coluna da esquerda,
   uma linha abaixo: medido em 06/08/2026, 681px de vazio acima dele, começando
   114px DEPOIS do fim da lista, e 233px a mais de altura na seção só para
   acomodar um parágrafo perdido no meio da página. Ele viu e perguntou por que
   aquilo estava solto ali.
   Continuar a lista resolve porque é onde o olho está quando a leitura termina.
   O sinal muda de propósito: o "+" abre aqui, a seta leva embora. E no lugar do
   número entra CRM ou API, porque numerar seria mentir: não é a pergunta 08. */
.faq-ir{
  display:grid;grid-template-columns:56px 1fr auto;align-items:center;gap:22px;
  padding:28px 6px;border-bottom:1px solid var(--line);color:var(--bone);
}
.faq-ir-m{
  font-family:var(--mono);font-size:var(--m2);letter-spacing:var(--m2-ls);
  text-transform:uppercase;color:var(--gold-txt);
}
.faq-ir-s{color:var(--gold-txt);font-size:18px;line-height:1}
.faq-ir-m,.faq-ir .h3,.faq-ir-s{transition:translate 220ms var(--ease)}
@media(hover:hover) and (pointer:fine){
  .faq-ir:hover .faq-ir-m,.faq-ir:hover .h3{translate:10px}
  .faq-ir:hover .faq-ir-s{translate:6px}
}
@media(max-width:800px){.faq-ir{gap:14px}}

/* ---------------- cta + rodapé ---------------- */
.ct-grid{display:grid;grid-template-columns:1fr 1.15fr;gap:clamp(40px,7vw,100px);align-items:start;text-align:left}
@media(max-width:900px){.ct-grid{grid-template-columns:1fr;gap:44px}}
.ct-list{list-style:none;display:grid;gap:13px;margin:28px 0 30px}
.ct-list li{display:flex;gap:13px;font-size:var(--s3);color:var(--gray);line-height:1.45}
.ct-list li::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--gold-dim);flex:none;margin-top:9px}

.f-row{display:grid;grid-template-columns:1fr 1fr;gap:30px;margin-bottom:30px}
@media(max-width:560px){.f-row{grid-template-columns:1fr;gap:30px}}
.f-field{position:relative}
.f-lab{display:block;font-size:var(--s1);color:var(--gray);margin-bottom:8px;letter-spacing:.01em}
.f-in{
  width:100%;background:none;border:none;border-bottom:1px solid var(--line-2);
  color:var(--bone);font-family:var(--sans);font-size:17px;
  padding:7px 0 11px;border-radius:0;transition:border-color .4s var(--ease);
}
.f-in:focus{outline:none;border-bottom-color:var(--gold)}
.f-in::placeholder{color:#857F75}
textarea.f-in{resize:vertical;min-height:56px;line-height:1.5}

.f-chips{display:flex;flex-wrap:wrap;gap:9px;margin:10px 0 34px}
.f-chip{
  font-family:var(--sans);background:none;
  font-size:var(--s2);color:var(--gray);border:1px solid var(--line-2);
  border-radius:100px;padding:9px 18px;cursor:pointer;user-select:none;
  transition:color 160ms ease,border-color 160ms ease,background-color 160ms ease,scale 110ms ease-out;
}
@media(hover:hover) and (pointer:fine){
  .f-chip:hover{border-color:var(--gold-dim);color:var(--bone)}
}
.f-chip:active{scale:.97}
.f-chip.on{border-color:var(--gold);color:var(--gold-txt);background:rgba(255,176,32,.08)}

.f-foot{display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap;margin-top:38px}
.f-send{
  display:inline-flex;align-items:center;gap:10px;cursor:pointer;
  background:var(--gold);color:var(--ink);border:none;border-radius:2px;
  font-family:var(--sans);font-size:var(--s3);font-weight:500;letter-spacing:-.01em;
  /* o translateY(-1px) em 350ms saiu: 1px em mais de um terço de segundo não se
     vê, e ainda era o botão do formulário levitando sem motivo. Cor em 160ms e
     press de escala, que é retorno que se sente inclusive no celular. */
  padding:15px 30px;transition:background-color 160ms ease,scale 110ms ease-out;
}
@media(hover:hover) and (pointer:fine){
  .f-send:hover{background:var(--gold-hi)}
}
.f-send:active{scale:.985}
@media(max-width:560px){.f-send{width:100%;justify-content:center}.f-foot{flex-direction:column-reverse;align-items:stretch}}
.f-alt{font-size:var(--s2);color:var(--gray)}
.f-alt a{color:var(--bone);border-bottom:1px solid var(--gold-dim);padding-bottom:1px}
.f-alt a:hover{color:var(--gold-txt)}
.f-err{font-size:var(--s1);color:#E5645C;margin-top:14px;min-height:1em}
.foot{border-top:1px solid var(--line);padding:50px 0 26px}
.foot-grid{display:grid;grid-template-columns:1.5fr 1fr 1fr 1fr;gap:34px}
@media(max-width:820px){.foot-grid{grid-template-columns:1fr 1fr}}
.foot h3{font-family:var(--mono);font-size:var(--m2);font-weight:400;letter-spacing:var(--m2-ls);text-transform:uppercase;color:var(--gold-txt-2);margin-bottom:15px}
.foot ul{list-style:none;display:grid;gap:8px;font-size:var(--s2)}
.foot a:hover{color:var(--gold-txt)}
.foot-base a{color:var(--gray)}
.foot-base a:hover{color:var(--gold-txt)}
/* marcador de dado que ainda falta. gritante de propósito: publicar com isso na tela
   é pior do que perceber agora. remover a regra quando não houver mais nenhum. */
.falta{background:var(--gold);color:var(--ink);font-family:var(--mono);font-size:var(--m2);font-weight:500;padding:1px 6px;border-radius:2px;display:inline-block}
.wm-bleed{width:100%;padding:0 clamp(10px,1.4vw,22px);overflow:hidden;margin-top:clamp(48px,7vw,86px);text-align:center}
/* Mesma marca de dois pesos, em escala de sangria. A opacidade segurada é de
   propósito: a 23vw, no peso cheio, a palavra virava a coisa mais forte da
   página inteira e roubava a atenção do rodapé, que é onde estão os dados de
   contato. Aqui ela é fundo de marca, não manchete.
   O valor está no --wm-op porque o GSAP anima para ele na entrada; mudar em um
   lugar só deixaria a animação terminando num tom diferente do CSS. */
/* 23vw cortava a palavra: medido a 1440px, ela saia com 1686px contra 1425px de
   caixa, ou seja 261px para fora, e o B desaparecia inteiro. A sangria era
   intencional, mas ele disse que "bonito grande, mas ta demais", e ele esta certo:
   marca cortada no rodape parece erro de layout, nao decisao.
   19vw e o ponto em que a palavra INTEIRA ocupa a linha de borda a borda: 1392px
   de palavra em 1425px de caixa, 33px de folga. Continua sendo a coisa grande do
   rodape, e agora se le INFOHUB. Centralizada para a folga ficar simetrica. */
.wordmark{
  display:inline-block;white-space:nowrap;
  font-weight:400;font-stretch:112%;letter-spacing:-.05em;line-height:.8;
  font-size:11.5vw;color:var(--bone-2);opacity:var(--wm-op);
}
/* passou por 23vw (cortava 261px e comia o B), 19vw (inteira, borda a borda) e ele
   ainda achou grande nas duas. 11.5vw poe a palavra em ~59% da largura: le como
   assinatura de rodape, que e o papel dela, e nao como outdoor. A altura do bloco
   cai de 273px para 165px, que era metade do incomodo. */
.wordmark i{font-style:normal;font-weight:800;font-stretch:118%;color:var(--gold-txt)}
.foot-base{display:flex;justify-content:space-between;gap:14px;flex-wrap:wrap;border-top:1px solid var(--line);margin-top:30px;padding-top:18px;font-family:var(--mono);font-size:var(--m2);color:var(--gray)}

/* ---------------- alvo de toque no celular ----------------
   Medido em 390px: 16 links e botões com menos de 32px de altura, incluindo a
   logo da nav, o botão do menu e a lista inteira do rodapé, que tinha 16px.
   Isso não é estética, é dedo errando alvo em quem chega pelo WhatsApp.
   O aumento é por padding, não por corpo de fonte: a letra continua igual e só
   a área clicável cresce. No rodapé o gap cai de 8px para 2px na mesma conta,
   senão o espaçamento entre um item e outro dobrava sem motivo. */
@media(max-width:900px){
  .nav-mark{padding-block:8px}
  .sm-toggle{padding:12px 6px}
  .foot ul{gap:2px}
  .foot ul a,
  .foot-base a,
  .f-alt a,
  .foot p a,
  .sm-socials-link{display:inline-block;padding-block:11px}
  /* o rodapé legal tem dois links lado a lado separados por ponto: sem isto as
     duas áreas de toque encostam uma na outra */
  .foot-base span{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
}

.page{position:relative;z-index:1;background:var(--ink)}
.site-foot{position:fixed;left:0;right:0;bottom:0;z-index:0;background:var(--ink)}
@media(max-width:820px){.page{margin-bottom:0!important}.site-foot{position:static}}
/* A marca "INFOHUB" repetida no topo de cada seção foi removida em 05/08/2026:
   eram 8 delas, uma por seção, formando duas etiquetas empilhadas antes de todo
   título. O CSS dela saiu junto; o JS que a inseria também.
   Cheguei a pôr um filete correndo do eyebrow até a borda direita para ocupar o
   vazio (media de 265px a 845px por cabeçalho). Ele saiu: resolvia o problema de
   um cabeçalho alinhado à esquerda, e o padrão escolhido foi o centralizado. */

/* Cabeçalho de seção centralizado, o mesmo do "Como funciona". Os blocos internos
   têm max-width em ch, então precisam de margin-inline:auto para centralizar de
   fato: só text-align não move a caixa, alinha o texto dentro dela. */
.cab{text-align:center;margin-bottom:clamp(34px,4vw,52px)}
.cab .eyebrow{justify-content:center}
.cab .h2,.cab .lead,.cab > p{margin-inline:auto}
.cab .h2{margin-top:20px}
.cab .lead,.cab > .mono{margin-top:18px}
@media(max-width:560px){
  .h1{font-size:clamp(30px,8.6vw,112px)}
  .hero-foot .set{gap:14px}
}
/* O .rv era o estado escondido dos blocos que apareciam ao rolar. Saiu em
   05/08/2026: nada de conteúdo invisível esperando scroll, em nenhuma página.
   A classe continua no HTML de muitos blocos e não faz mais nada, o que é de
   propósito: se o assunto voltar, o gancho está lá. */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *{animation:none!important;transition-duration:.01ms!important}
  .js .rv{opacity:1;transform:none}
  .js .hero h1 .ln>span{transform:none}
  .js .pre{display:none}
}

/* ============================================================================
   PÁGINAS DE PRODUTO (api-whatsapp.html e crm-whatsapp.html)
   ----------------------------------------------------------------------------
   As páginas da Ubli usam cartão com gradiente colorido, uma cor por assunto:
   azul, verde, roxo, laranja, vermelho. Aqui não. Seis cores sem hierarquia é o
   que faz uma página parecer molde pronto, e brigaria com a paleta âmbar que já
   foi escolhida e validada. A densidade de informação é a mesma; a diferença é
   que quem separa um assunto do outro é o número, o ícone e o peso, não a cor.
   ========================================================================== */

/* --- submenu de produtos na nav --- */
.nav-drop{position:relative}
.nav-drop-t{display:inline-flex;align-items:center;gap:7px;font:inherit;color:var(--gold-txt);
  background:none;border:none;padding:0 0 3px;cursor:pointer;text-transform:inherit;letter-spacing:inherit}
.nav-drop-t svg{width:9px;height:9px;flex:none;transition:transform 220ms var(--ease)}
.nav-drop.on .nav-drop-t svg{transform:rotate(180deg)}
.nav-drop-m{position:absolute;top:calc(100% + 14px);left:-18px;min-width:292px;
  background:rgba(19,17,16,.97);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);
  border:1px solid var(--line-2);border-radius:12px;padding:8px;
  display:grid;gap:2px;opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity 180ms ease,transform 180ms var(--ease),visibility 180ms}
.nav-drop.on .nav-drop-m{opacity:1;visibility:visible;transform:none}
.nav-drop-m a{display:grid;gap:2px;padding:12px 14px;border-radius:8px;text-transform:none;
  transition:background-color 160ms ease}
.nav-drop-m a:hover{background:rgba(255,176,32,.09)}
.nav-drop-m b{font-family:var(--sans);font-weight:700;font-stretch:118%;font-size:15.5px;
  letter-spacing:-.02em;color:var(--bone)}
.nav-drop-m a:hover b{color:var(--gold-txt)}
.nav-drop-m span{font-family:var(--sans);font-size:var(--s1);letter-spacing:0;color:var(--gray);text-transform:none}
/* o item da página em que se está */
.nav-links a[aria-current="page"],.nav-drop-t[aria-current="page"]{color:var(--gold-txt)}

/* --- hero de página interna: menor que o da home, sem foto --- */
.hp{padding:clamp(120px,14vh,168px) 0 clamp(50px,6vw,74px);position:relative;overflow:hidden}
.hp::after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;background:var(--line)}
.hp-g{display:grid;grid-template-columns:1fr 1.02fr;gap:clamp(32px,4.4vw,64px);align-items:center}
@media(max-width:980px){.hp-g{grid-template-columns:1fr;gap:38px}}
/* MESMA escala do h1 da home, não uma escala própria. Medido a 1440px: a interna
   estava com 74px contra 58px da home, ou seja o título da página secundária era
   MAIOR que o da principal, e ao trocar de página tudo parecia mudar de tamanho.
   Agora as duas usam clamp(32px,4.1vw,58px).
   E o filete do eyebrow desaparece no hero, como já acontece no `.hero-top` da
   home: com ele, o texto do eyebrow começava 39px para dentro e não alinhava com
   o h1 nem com o botão. */
.hp .h1{font-size:clamp(32px,4.1vw,58px);line-height:1}
.hp .eyebrow::before{display:none}
.hp .lead{margin-top:22px;color:var(--bone-2)}
.bread{font-family:var(--mono);font-size:var(--m2);letter-spacing:var(--m2-ls);text-transform:uppercase;
  color:var(--gray);margin-bottom:26px;display:flex;gap:9px;flex-wrap:wrap}
.bread a{color:var(--gray)}
.bread a:hover{color:var(--gold-txt)}
.bread span{color:var(--gold-txt-2)}
.selos{display:flex;gap:9px;flex-wrap:wrap;margin-top:26px;
  font-family:var(--mono);font-size:var(--m2);letter-spacing:var(--m2-ls);text-transform:uppercase;color:var(--gray)}
.selos li{list-style:none;display:flex;align-items:center;gap:9px}
.selos li+li::before{content:"";width:3px;height:3px;border-radius:50%;background:var(--gold-dim);flex:none}

/* --- painel de código. Numa página de API isto é o retrato do produto: mostra o
       que a pessoa vai fazer de fato, e vale mais que qualquer ilustração. --- */
.code{border:1px solid var(--line-2);border-radius:12px;background:#0F0D0B;overflow:hidden}
.code-bar{display:flex;align-items:center;gap:12px;padding:12px 16px;border-bottom:1px solid var(--line);
  font-family:var(--mono);font-size:var(--m2);letter-spacing:.04em;color:var(--gray);background:rgba(245,241,234,.028)}
.code-verb{color:var(--gold-txt);font-weight:500}
.code pre{margin:0;padding:18px 16px;overflow-x:auto;font-family:var(--mono);font-size:12.5px;
  line-height:1.75;color:#D8D2C8}
.code pre b{font-weight:400;color:var(--gold-txt)}
.code pre i{font-style:normal;color:#9FD3AC}
.code pre u{text-decoration:none;color:var(--gray)}
.code+.code{margin-top:14px}
@media(max-width:520px){.code pre{font-size:11.5px}}

/* --- grade de recursos --- */
.prec{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.6vw,20px)}
@media(max-width:900px){.prec{grid-template-columns:repeat(2,1fr)}}
@media(max-width:620px){.prec{grid-template-columns:1fr}}
.prec-c{border:1px solid var(--line);border-radius:12px;padding:clamp(20px,2.1vw,26px);background:var(--ink);
  display:flex;flex-direction:column;transition:border-color 200ms ease,background-color 200ms ease}
@media(hover:hover) and (pointer:fine){
  .prec-c:hover{border-color:rgba(255,176,32,.34);background:var(--ink-2)}
}
.prec-i{width:26px;height:26px;color:var(--gold-txt);margin-bottom:15px}
.prec-i svg{width:100%;height:100%;display:block;stroke:currentColor;stroke-width:1.5;fill:none;
  stroke-linecap:round;stroke-linejoin:round}
.prec-c h3{font-family:var(--sans);font-weight:700;font-stretch:118%;font-size:18px;letter-spacing:-.02em;
  line-height:1.2;margin-bottom:9px}
.prec-c p{font-size:var(--s2);color:var(--gray);line-height:1.55;margin-bottom:16px}
.prec-t{list-style:none;display:flex;flex-wrap:wrap;gap:6px;margin-top:auto}
.prec-t li{font-family:var(--mono);font-size:var(--m1);letter-spacing:.06em;text-transform:uppercase;
  color:var(--gold-txt-2);border:1px solid rgba(168,111,18,.42);border-radius:100px;padding:4px 9px}

/* --- casos de uso: numeração no lugar da cor --- */
.seg{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.7vw,22px)}
@media(max-width:940px){.seg{grid-template-columns:repeat(2,1fr)}}
@media(max-width:640px){.seg{grid-template-columns:1fr}}
/* subgrid para as faixas coloridas da mesma linha terminarem na MESMA altura.
   Medido antes: o cartão com título de uma linha tinha cabeçalho de 163px contra
   185px dos vizinhos, e as faixas terminavam com 22px de diferença. Como o grid
   iguala a altura do cartão inteiro mas não a das partes, o corte da cor ficava
   torto. Com grid-row:span 2 e grid-template-rows:subgrid, cabeçalho e corpo de
   todos os cartões da linha compartilham as mesmas duas faixas de altura.
   O fallback é o flex de antes, para navegador sem subgrid: volta o desalinho,
   que é melhor do que o cartão desmontar. */
.seg-c{border:1px solid var(--line);border-radius:12px;overflow:hidden;background:var(--ink);
  display:flex;flex-direction:column}
@supports (grid-template-rows: subgrid){
  .seg{grid-auto-rows:auto}
  .seg-c{display:grid;grid-template-rows:subgrid;grid-row:span 2}
}
/* MEDIDO E CORRIGIDO: os pontos escuros dos gradientes 3, 4 e 5 (terracota, cobre
   e oliva) davam 3,8 a 3,9 de contraste com o texto escuro, abaixo do minimo 4,5.
   Clareados até passar com folga. Cor bonita que nao se le nao serve, e este site
   ja zerou contraste reprovado uma vez.
   Cabeçalho em gradiente cheio, uma cor por assunto. Escolhido por ele em
   05/08/2026 comparando três versões aplicadas (âmbar chapado, esta, e as seis
   cores independentes do site da Ubli).
   O que faz esta funcionar e a da Ubli não: as seis matizes saem todas do mesmo
   lado do círculo cromático do âmbar da marca (âmbar, laranja, terracota, cobre,
   oliva e mel), então há variedade sem a página trocar de identidade a cada
   cartão. O texto é escuro, como todo texto sobre âmbar neste site. */
.seg-h{padding:clamp(20px,2.1vw,26px);border-bottom:none;
  background:linear-gradient(150deg,var(--c1),var(--c2))}
.seg-c{border-color:transparent;background:var(--ink-2)}
.seg-c:nth-child(1){--c1:#FFB020;--c2:#E8930C}
.seg-c:nth-child(2){--c1:#F58A20;--c2:#DC6A09}
.seg-c:nth-child(3){--c1:#EE7448;--c2:#DC6338}
.seg-c:nth-child(4){--c1:#D89A38;--c2:#BC7A1E}
.seg-c:nth-child(5){--c1:#BFB03A;--c2:#A6981F}
.seg-c:nth-child(6){--c1:#DFA945;--c2:#C08820}
.seg-n{font-family:var(--mono);font-size:var(--m2);letter-spacing:.14em;display:block;margin-bottom:12px;
  color:#160F04}
/* sem opacidade: medido, a 0.8 os números dos cartões 2, 3 e 4 davam 4,29, 4,16 e
   4,17 contra o mínimo de 4,5. A hierarquia entre número e título já vem do corpo
   e do tracking, não precisa vir de transparência. */
.seg-h h3{font-family:var(--sans);font-weight:700;font-stretch:118%;font-size:clamp(19px,1.9vw,23px);
  letter-spacing:-.025em;line-height:1.14;margin-bottom:10px;color:#160F04}
.seg-h p{font-size:var(--s2);line-height:1.55;color:#160F04;opacity:.92}
.seg-b{padding:clamp(18px,2vw,24px);flex:1}
.seg-b>p{font-family:var(--mono);font-size:var(--m2);letter-spacing:var(--m2-ls);text-transform:uppercase;
  color:var(--gray);margin-bottom:13px}
.seg-b ul{list-style:none;display:grid;gap:10px}
.seg-b li{display:flex;gap:10px;font-size:var(--s2);color:var(--bone-2);line-height:1.4}
.seg-b li::before{content:"";width:14px;height:14px;flex:none;margin-top:3px;background-repeat:no-repeat;
  background-position:center;background-size:14px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FFB020' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E")}

/* --- FAQ sem JavaScript: <details> nativo, com o desenho do acordeão da home.
       Página nova não precisa de JS para abrir uma pergunta, e assim o texto
       está no HTML mesmo se o script falhar, o que também é melhor para busca. --- */
.faq-l{border-top:1px solid var(--line)}
.faq-i{border-bottom:1px solid var(--line);transition:background-color 200ms ease}
@media(hover:hover) and (pointer:fine){.faq-i:hover{background:var(--ink-2)}}
.faq-i summary{list-style:none;cursor:pointer;display:grid;grid-template-columns:66px 1fr auto;
  align-items:center;gap:20px;padding:26px 6px}
.faq-i summary::-webkit-details-marker{display:none}
.faq-i summary .n{font-family:var(--mono);font-size:var(--m2);letter-spacing:var(--m2-ls);color:var(--gold-txt)}
.faq-i summary .q{font-family:var(--sans);font-weight:700;font-stretch:118%;
  font-size:clamp(17px,1.75vw,21px);letter-spacing:-.022em;line-height:1.25;transition:translate 220ms var(--ease)}
@media(hover:hover) and (pointer:fine){.faq-i:hover summary .q{translate:8px}}
.faq-i .sinal{position:relative;width:15px;height:15px;flex:none;color:var(--gold-txt)}
.faq-i .sinal::before,.faq-i .sinal::after{content:"";position:absolute;background:currentColor;transition:transform 260ms var(--ease)}
.faq-i .sinal::before{left:0;top:7px;width:15px;height:1px}
.faq-i .sinal::after{top:0;left:7px;height:15px;width:1px}
.faq-i[open] .sinal::after{transform:rotate(90deg)}
.faq-i .a{padding:0 6px 30px;max-width:80ch}
.faq-i .a p{font-size:var(--s3);color:var(--gray);line-height:1.6}
.faq-i .a p+p{margin-top:12px}
@media(max-width:700px){.faq-i summary{grid-template-columns:1fr auto;gap:14px}.faq-i summary .n{display:none}}

/* --- nota: o aviso que muda a conta do cliente --- */
.nota{border:1px solid var(--gold-dim);border-left:3px solid var(--gold);border-radius:4px;
  padding:clamp(20px,2.2vw,28px);background:rgba(255,176,32,.05)}
.nota h3{font-family:var(--sans);font-weight:700;font-stretch:118%;font-size:19px;letter-spacing:-.02em;margin-bottom:8px}
.nota p{font-size:var(--s2);color:var(--bone-2);line-height:1.55;max-width:76ch}
.nota p+p{margin-top:10px}
.nota a{color:var(--gold-txt);border-bottom:1px solid var(--gold-dim)}

/* --- números da plataforma. Só entram com a fonte declarada: são da Ubli, não
       nossos, e número sem atribuição em site de parceiro é problema. --- */
.num-g{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(14px,1.8vw,24px)}
@media(max-width:760px){.num-g{grid-template-columns:repeat(2,1fr)}}
.num-c{border-top:1px solid var(--line);padding-top:16px}
.num-c b{display:block;font-weight:800;font-stretch:118%;font-size:clamp(26px,3vw,40px);
  letter-spacing:-.04em;line-height:1;color:var(--gold-txt)}
.num-c span{display:block;font-family:var(--mono);font-size:var(--m2);letter-spacing:var(--m2-ls);
  text-transform:uppercase;color:var(--gray);margin-top:7px}
.num-fonte{font-family:var(--mono);font-size:var(--m1);letter-spacing:.06em;color:var(--gray);margin-top:20px}

/* --- passos numerados (como a IA aprende, como conectar) --- */
.pas{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(18px,2.4vw,34px);counter-reset:pas}
@media(max-width:860px){.pas{grid-template-columns:1fr;gap:26px}}
.pas-i{counter-increment:pas;position:relative;padding-top:22px;border-top:1px solid var(--line-2)}
.pas-i::before{content:counter(pas,decimal-leading-zero);font-family:var(--mono);font-size:var(--m2);
  letter-spacing:.14em;color:var(--gold-txt);display:block;margin-bottom:14px}
.pas-i h3{font-family:var(--sans);font-weight:700;font-stretch:118%;font-size:clamp(18px,1.9vw,22px);
  letter-spacing:-.025em;line-height:1.16;margin-bottom:10px}
.pas-i p{font-size:var(--s2);color:var(--gray);line-height:1.6}

/* --- grade de canais do CRM. As cores de marca dos canais são preservadas de
       propósito: ali a cor não é enfeite, é identificação. --- */
.can{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}
@media(max-width:820px){.can{grid-template-columns:repeat(2,1fr)}}
@media(max-width:460px){.can{grid-template-columns:1fr}}
.can-c{display:flex;align-items:center;gap:13px;border:1px solid var(--line);border-radius:10px;
  padding:15px 17px;background:var(--ink);transition:border-color 200ms ease}
@media(hover:hover) and (pointer:fine){.can-c:hover{border-color:var(--line-2)}}
.can-c svg{width:21px;height:21px;flex:none}
.can-c b{display:block;font-family:var(--sans);font-weight:700;font-stretch:118%;font-size:15.5px;letter-spacing:-.02em}
.can-c span{display:block;font-family:var(--mono);font-size:var(--m1);letter-spacing:.06em;
  text-transform:uppercase;color:var(--gray);margin-top:3px}

/* --- entrada dos blocos nas páginas de produto ---
   Na home a entrada é feita pelo GSAP com ScrollTrigger. Aqui não, e o motivo é
   concreto: medido nesta sessão, 18 blocos (9 recursos, 6 casos de uso, 3 passos)
   ficaram com opacity 0 porque o ScrollTrigger não disparou, e a página inteira
   leu como vazia. Conteúdo não pode depender de animação para existir, e um
   buscador que renderiza a página vê exatamente o que o olho vê.
   Agora quem revela é o IntersectionObserver, que responde a layout e não a
   frames de animação, a transição é CSS (roda fora da thread principal) e o JS
   só aplica a classe que esconde SE o observador existir. Ainda há um seguro de
   1,5s no pagina.js: se havia bloco na tela e nenhum foi revelado, revela tudo.
   Animação perdida é irrelevante; conteúdo invisível não é. */
/* TÍTULO NUNCA ESCONDE. O recorte que abre da esquerda para a direita ficou
   bonito na home, mas aqui ele custou caro: dependia do IntersectionObserver
   disparar, e quando não disparou o usuario viu cinco secoes com o eyebrow
   sozinho e nenhum titulo, duas vezes. Medido: clip-path fechado em 5 de 5.
   Nenhuma animacao vale um titulo invisivel. O h2 e o texto entram estaticos, e
   o movimento da secao fica nos cartoes (que tem seguro) e no filete do eyebrow,
   cujo pior caso e um tracinho decorativo nao aparecer. */
.js .rvi,.js .h2.rvi{opacity:1;transform:none;clip-path:none}
/* REGRA DESTE PROJETO, aprendida errando várias vezes hoje: o estado FINAL é o
   padrão, e a animação é bônus. Nada nasce escondido esperando um observador.
   Antes o CSS punha o filete em width:0 e esperava a classe .vis; medido, rolando
   a página inteira só 2 de 4 filetes abriram na home e 0 de 5 na página da API,
   porque ScrollTrigger e IntersectionObserver falham de forma inconsistente
   dependendo de como o navegador está compondo frames. O resultado eram cabeçalhos
   sem o tracinho, que foi o que ele viu nos prints.
   Com @keyframes o pior caso inverte: se o .vis nunca chegar, o filete simplesmente
   está lá, do tamanho certo. Se chegar, ele cresce de zero. */
@keyframes filete{from{width:0}to{width:28px}}
/* O recorte que abre da esquerda para a direita, o mesmo gesto que abre a palavra
   INFOHUB no preloader. Ele gostou ("parece meio embaralhando as letras e depois
   fica legível") e pediu para usar nas outras páginas.
   Aqui ele volta pela via segura: o título está visível por padrão e o keyframe só
   entra quando o cabeçalho é avisado. Se o aviso não vier, o pior caso é um título
   aparecendo sem gesto, e nunca mais um título invisível. */
/* A folga negativa embaixo não é detalhe: clip-path corta na caixa do elemento, e
   o .h2 tem line-height .94, então a descendente do g, do p e do q fica FORA da
   caixa e era decepada. Ele viu no "Perguntas.". -0.3em embaixo, -0.15em em cima
   (acento) e -0.1em à direita (itálico e ponto final). */
/* TUDO EM PORCENTAGEM, e isso não é preferência: misturar 100% com -.1em fez o
   navegador virar a interpolação num salto discreto. Medido, o lado direito ficou
   seis amostras seguidas em 100% e pulou direto para 0%, ou seja o título ficava
   parado e aparecia de uma vez. Era o "parece que tá bugando".
   As folgas negativas continuam existindo pelo mesmo motivo de antes (o clip corta
   na caixa e o line-height .94 deixa a perna do g para fora), agora em % da caixa. */
@keyframes recorta{
  from{clip-path:inset(-14% 100% -26% 0)}
  to{clip-path:inset(-14% -2% -26% 0)}
}
/* O cabeçalho de seção é CENTRALIZADO, e num texto centralizado um recorte que
   abre da esquerda para a direita faz a palavra crescer para fora do eixo: lê como
   defeito, e foi o que ele apontou duas vezes. Aqui o recorte abre do centro para
   os dois lados, no mesmo eixo em que o texto está. O gesto continua sendo o mesmo
   vocabulário do logo, só na direção certa para este bloco.
   O `recorta` lateral fica guardado para título alinhado à esquerda, se um dia
   existir. */
@keyframes recortaCentro{
  from{clip-path:inset(-14% 50% -26% 50%)}
  to{clip-path:inset(-14% -2% -26% -2%)}
}
.js .cab.vis .h2{animation:recortaCentro 1.05s var(--ease) both}
.js .cab.vis .eyebrow::before{animation:filete 700ms var(--ease) 80ms both}
/* mesma inversão dos filetes: o cartão existe, e quem anima é o keyframe quando
   o observador avisa. Antes eram 18 blocos capazes de ficar invisíveis. */
/* A entrada animada dos cartões SAIU em 05/08/2026. Passou por transição, por
   keyframes, por 750ms, por 420ms, por gatilho antecipado, e ele reprovou todas:
   "aparecendo travando", "parece que tá bugando tudo". A medição fechou o caso:
   rolando a página, em 62 de 110 frames havia cartão dentro da tela ainda
   transparente (pico de 9 juntos), e desligando isso foi para zero em todos os
   frames, com o mesmo FPS de 60. Cartão aparece pronto.
   Se um dia voltar o assunto: o problema não é a duração, é a ideia de esconder
   conteúdo que a pessoa já está olhando. */
@media (prefers-reduced-motion:reduce){
  .js .rvi,.js .h2.rvi{opacity:1;transform:none;clip-path:none;animation:none}
  .js .cab.vis .eyebrow::before{animation:none;width:28px}
  .js .cab.vis .h2{animation:none;clip-path:none}
}

/* Alvo de toque nos links das páginas de produto. Medido em 390px: o "INFOHUB"
   da trilha, o link do CRM dentro da nota e o da documentação saíam com 17 e 18px
   de altura. Cresce por padding, não por corpo de fonte: a letra continua igual e
   só a área do dedo aumenta. Mesma conta que já foi feita no rodapé da home. */
@media(max-width:900px){
  .bread a,.nota a,.num-fonte a,.pl-ia a,.faq-i .a a,.addon-nota a,.seg-b a{display:inline-block;padding-block:8px}
  .faq-i summary{padding:22px 6px}
}

/* ============================================================================
   JANELA DE DEMONSTRAÇÃO, VERSÃO GRANDE
   ----------------------------------------------------------------------------
   O hero da API começou com dois painéis de código, depois código mais uma bolha,
   e ele reprovou as duas: "não sei porque você não fez parecido com o do willian
   e colocou um código". Estava certo. Numa página que precisa vender, a janela de
   conversa mostra o produto para qualquer pessoa; o código só fala com quem já
   decidiu integrar, e por isso desceu para uma seção própria embaixo.
   Esta versão é a janela da home crescida: avatar com cor de verdade, quatro
   mensagens, indicador de digitação e o selo flutuante fora da área de conversa,
   porque em cima dela ele cobria mensagem, que foi o "tá tudo quebrado".
   ========================================================================== */
/* o selo flutuante "Webhook de volta" existia aqui embaixo e saiu: ele achou
   enfeitado demais, e a janela já conta a história sozinha. Sem selo, sem padding. */
.demo{position:relative}
.demo .chat{max-width:none}
.demo .chat-b{height:340px;gap:10px}
@media(max-width:980px){.demo .chat-b{height:300px}}

/* avatar com cor. Era um ícone cinza em cima de cinza e lia como espaço vazio:
   "se for colocar cliente ao menos coloque uma foto ou algo colorido na fotinha".
   Gradiente âmbar com o monograma do negócio, que é o que um CRM mostra de fato. */
.av-cor{background:linear-gradient(145deg,#FFD07A,#E8973A 62%,#CF8022)!important;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.22),0 6px 16px -6px rgba(255,176,32,.5)!important;
  display:grid;place-items:center}
.av-cor b{font-family:var(--sans);font-weight:800;font-stretch:118%;font-size:15px;
  letter-spacing:-.03em;color:#25150A}
.chat-h .chat-av.av-cor::after{background:#25D366;box-shadow:0 0 0 2px var(--ink-2)}

/* etiqueta de origem da mensagem: diz que aquela bolha saiu do sistema, não de
   uma pessoa digitando. É o argumento da página dentro do mock. */
.chat-org{align-self:flex-end;display:flex;align-items:center;gap:6px;margin-bottom:-4px;
  font-family:var(--mono);font-size:9.5px;letter-spacing:.13em;text-transform:uppercase;
  color:var(--gray);opacity:0;transition:opacity 400ms var(--ease)}
.chat-org.vis{opacity:1}
.chat-org svg{width:11px;height:11px;color:var(--gold-txt);flex:none}

/* seção da chamada, onde o código foi morar */
/* min-width:0 nos filhos não é detalhe: item de grid tem min-width:auto por
   padrão e se recusa a encolher abaixo do próprio conteúdo. O <pre> do painel de
   código tem uma linha de curl bem mais larga que 360px, e mesmo com overflow-x
   no pre era o GRID que crescia e empurrava a página. Medido em 360px: a página da
   API rolava 17px na horizontal, e a home e a do CRM não rolavam nada. */
.chamada-g{display:grid;grid-template-columns:1fr 1.15fr;gap:clamp(28px,3.6vw,54px);align-items:center}
.chamada-g>*{min-width:0}
.code{min-width:0;max-width:100%}
@media(max-width:940px){.chamada-g{grid-template-columns:1fr;gap:30px}}
.code-l{display:block;border-radius:4px;margin:0 -6px;padding:0 6px;
  transition:background-color 260ms ease,box-shadow 260ms ease}
.code.run .code-l{background:rgba(255,176,32,.13);box-shadow:inset 0 0 0 1px rgba(255,176,32,.22)}
.code-st{margin-left:auto;display:inline-flex;align-items:center;gap:7px;flex:none;color:var(--gray);
  transition:color 200ms ease}
.code-st::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--gray);flex:none;
  transition:background-color 200ms ease}
.code.run .code-st{color:var(--gold-txt)}
.code.run .code-st::before{background:var(--gold);animation:pulsa 1s infinite}
.code.ok .code-st{color:#7FCB92}
.code.ok .code-st::before{background:#7FCB92;animation:none}
@keyframes pulsa{0%,100%{opacity:1}50%{opacity:.25}}

@media (prefers-reduced-motion:reduce){
  .chat-org{opacity:1;transform:none}
}

/* cliente digitando na esquerda (na home é a IA, na direita) */
.chat-typ.esq{align-self:flex-start;border-bottom-right-radius:14px;border-bottom-left-radius:4px;
  background:var(--ink-3);box-shadow:inset 0 0 0 1px var(--line)}
.chat-typ.esq i{background:var(--gray)}
/* seguro: a bolha nasce invisível no CSS e quem revela é o JS. Enquanto o JS não
   assumir (classe .pronto), tudo fica visível. */
.demo .chat:not(.pronto) .chat-msg,.demo .chat:not(.pronto) .chat-org{opacity:1;transform:none}

/* ============================================================================
   PÁGINA DO CRM
   ========================================================================== */

/* cinco nichos em grade de seis colunas: três na primeira linha (span 2) e dois
   na segunda ocupando metade cada (span 3). Sem cartão órfão sobrando. */
.seg-5{grid-template-columns:repeat(6,1fr)}
.seg-5>*{grid-column:span 2}
.seg-5>*:nth-child(4),.seg-5>*:nth-child(5){grid-column:span 3}
@media(max-width:940px){
  .seg-5{grid-template-columns:repeat(2,1fr)}
  .seg-5>*,.seg-5>*:nth-child(4),.seg-5>*:nth-child(5){grid-column:span 1}
}
@media(max-width:640px){.seg-5{grid-template-columns:1fr}}
/* as cores dos cinco nichos são as mesmas dos casos de uso da API e vêm das regras
   .seg-c:nth-child() lá de cima. Duplicar aqui só criaria dois lugares para mudar. */

/* amostra de conversa dentro do cartão do nicho. É o que prova o argumento do
   cartão em duas linhas, no lugar de mais um parágrafo dizendo a mesma coisa. */
.seg-ex{margin-top:18px;border-top:1px solid var(--line);padding-top:15px;display:grid;gap:8px}
.seg-ex-t{font-family:var(--mono);font-size:var(--m1);letter-spacing:.1em;text-transform:uppercase;
  color:var(--gray);display:flex;align-items:center;gap:7px;margin-bottom:2px}
.seg-ex-t svg{width:12px;height:12px;color:var(--gold-txt);flex:none}
.seg-ex p{font-size:13.5px;line-height:1.45;border-radius:11px;padding:9px 12px;max-width:92%}
.seg-ex .q{align-self:start;background:var(--ink-3);color:var(--bone-2);border-bottom-left-radius:3px;
  box-shadow:inset 0 0 0 1px var(--line)}
.seg-ex .a{align-self:end;background:rgba(255,176,32,.12);color:var(--bone);border-bottom-right-radius:3px;
  box-shadow:inset 0 0 0 1px rgba(255,176,32,.26)}

/* tabela de planos: o CRM tem três, e o que decide a compra é o limite, não a
   lista de recursos. O bloco de limites vem antes da lista, em mono. */
.pl-3{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.6vw,20px);align-items:stretch}
@media(max-width:980px){.pl-3{grid-template-columns:1fr;max-width:520px;margin-inline:auto}}

/* aviso de IA dentro do cartão do plano: é a armadilha que o cliente descobre
   tarde se a gente não contar aqui. */
.pl-ia{font-size:12.5px;line-height:1.45;color:var(--gold-txt);background:rgba(255,176,32,.08);
  border:1px solid rgba(255,176,32,.26);border-radius:7px;padding:9px 11px;margin-bottom:18px}
.pl-ia a{border-bottom:1px solid var(--gold-dim)}

/* período de pagamento com desconto */
.per{display:flex;gap:10px;flex-wrap:wrap;justify-content:center;margin-top:clamp(26px,3vw,38px)}
.per-i{border:1px solid var(--line-2);border-radius:100px;padding:9px 18px;
  font-family:var(--mono);font-size:var(--m2);letter-spacing:.06em;text-transform:uppercase;color:var(--gray)}
.per-i b{color:var(--gold-txt);font-weight:500}

/* --- abertura da logo do cabeçalho ---
   A palavra começa lendo IHUB e se abre em INFOHUB. É o gesto que marca a troca de
   página.

   DUAS COISAS QUE ERREI ANTES E ESTÃO RESOLVIDAS AQUI:

   1. Piscava. A logo nascia inteira no primeiro quadro e só depois o JS (esperando
      document.fonts.ready) aplicava a classe, que recolhia para IHUB e abria de
      novo: INFOHUB, IHUB, INFOHUB. Agora quem mede é um script síncrono logo
      depois da nav, que roda ANTES do primeiro quadro, então o estado inicial
      nunca aparece como um segundo passo.
   2. Dependia de tween. Com gsap.set o NFO nascia recortado e um tween que não
      completasse deixava "IHUB" para sempre. Aqui é @keyframes: sem a marcação do
      script, a palavra simplesmente está inteira.

   O deslize do HUB é consequência, não animação separada: o NFO cresce de max-width
   zero com overflow hidden, e o HUB, que está no fluxo depois dele, é empurrado.
   Uma propriedade só, e os dois pedaços ficam perfeitamente em sincronia, o que
   antes exigia duas animações com a mesma curva e a mesma duração.
   +2px na largura final é folga: o script mede com a fonte que estiver disponível
   no momento, e se a Archivo entrar depois a métrica muda um fio. */
@keyframes logoAbre{
  from{max-width:0}
  to{max-width:calc(var(--nfo-w,4ch) + 2px)}
}
.nav-mark[data-medido] [data-nfo]{display:inline-block;overflow:hidden;vertical-align:top}
.js .nav-mark[data-medido] [data-nfo]{
  animation:logoAbre .95s cubic-bezier(.25,.46,.45,.94) .12s both;
}
@media (prefers-reduced-motion:reduce){
  .js .nav-mark[data-medido] [data-nfo]{animation:none;max-width:none}
}

/* ============================================================================
   DIVISÃO DE RESPONSABILIDADE: o que é da Ubli e o que é da INFOHUB
   ----------------------------------------------------------------------------
   Entrou em 06/08/2026, pedido do Willian depois de ver o site: a Ubli aparecia
   uma vez só na home inteira, no descritor da logo, e quem assinasse ia dar de
   cara com a marca dela no painel sem nunca ter lido isso aqui.

   O problema não era quantidade de Ubli, era o LUGAR. Espalhar a marca pelo site
   faz o cliente ir comprar direto lá; esconder faz ele se sentir enganado na
   assinatura. Então a marca aparece uma vez, com calma, na seção que já se chama
   "a plataforma", e mais uma linha na hora de escolher o plano.

   E aparece enquadrada como divisão de trabalho, não como aviso legal: quem
   descobre sozinho pergunta "então por que não vou direto?" sem ninguém por
   perto para responder. Quem lê aqui já recebe a resposta junto da pergunta.

   Nenhum dos textos usa "parceria" nem "revenda": ele decidiu em 06/08 que a
   INFOHUB não se apresenta assim. Descrever o que cada empresa faz é fato, e
   não rótulo de relação comercial.
   ============================================================================ */
.quem{
  display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--line);
  border:1px solid var(--line);border-radius:3px;overflow:hidden;margin-top:clamp(30px,4vw,44px);
}
@media(max-width:820px){.quem{grid-template-columns:1fr}}
.quem-c{background:var(--ink);padding:clamp(24px,3vw,34px)}
.quem-c.nos{background:var(--ink-2)}
.quem-t{
  font-family:var(--mono);font-size:var(--m2);letter-spacing:var(--m2-ls);text-transform:uppercase;
  color:var(--gold-txt);display:flex;align-items:center;gap:9px;margin-bottom:14px;
}
.quem-t svg{width:15px;height:15px;flex:none;stroke:currentColor;stroke-width:1.6;fill:none;
  stroke-linecap:round;stroke-linejoin:round}
.quem-c h3{font-family:var(--sans);font-weight:700;font-stretch:118%;
  font-size:clamp(19px,2vw,23px);letter-spacing:-.02em;line-height:1.15;margin-bottom:12px}
.quem-c > p{font-size:var(--s2);color:var(--gray);line-height:1.55;margin-bottom:14px}
.quem-l{list-style:none;display:grid;gap:9px}
.quem-l li{display:flex;gap:10px;font-size:var(--s2);color:var(--bone-2);line-height:1.45}
.quem-l li::before{content:"";width:5px;height:5px;border-radius:50%;background:var(--gold-dim);
  flex:none;margin-top:8px}
.quem-nota{margin-top:26px;font-size:var(--s2);color:var(--bone-2);line-height:1.6;
  max-width:74ch;border-left:2px solid var(--gold-dim);padding-left:16px}
.quem-nota b{color:var(--bone);font-weight:600}

/* a mesma informação em uma linha, para o instante anterior à assinatura */
.selo-ubli{
  display:flex;align-items:flex-start;gap:12px;margin-top:26px;padding:14px 16px;
  border:1px solid var(--line);border-radius:3px;background:var(--ink-2);max-width:66ch;
}
.selo-ubli svg{width:18px;height:18px;color:var(--gold-txt);flex:none;margin-top:1px;
  stroke:currentColor;stroke-width:1.6;fill:none;stroke-linecap:round;stroke-linejoin:round}
.selo-ubli p{font-size:var(--s1);color:var(--bone-2);line-height:1.5;margin:0}
.selo-ubli b{color:var(--bone);font-weight:600}

/* Isenção de afiliação no rodapé das três páginas comerciais. Discreta de
   propósito: é declaração legal, não argumento de venda, e precisa estar
   legível sem competir com o resto. Medido: 5,93 de contraste, acima do mínimo
   de 4,5. */
.foot-isencao{
  font-size:var(--s1);color:var(--gray);line-height:1.5;max-width:78ch;
  margin:0 0 22px;padding-top:22px;border-top:1px solid var(--line);
}
