/* ── Tipografia ──────────────────────────────────────────────────────────
 *
 * As páginas capturadas pedem `"OFFCODE Sans", system-ui, sans-serif` em
 * milhares de regras — e essa família NUNCA foi servida. Medido no ar:
 * `"OFFCODE Sans"` sozinha renderiza com a largura EXATA de `serif` (603px
 * numa régua de 40px), ou seja, o navegador não a encontra e cai para o
 * próximo item da pilha. O front novo inteiro desenhava em `system-ui`.
 *
 * 🔑 Fonte declarada e não servida NÃO dá erro: cai calada para o padrão do
 * sistema. E isso não é "uma aparência" — são três: San Francisco no Mac,
 * Segoe no Windows, Roboto no Android. Nenhuma é decisão nossa, e nenhuma
 * aparece numa captura de tela feita numa máquina só.
 *
 * Em vez de renomear 17.997 referências, a família declarada passa a EXISTIR:
 * `OFFCODE Sans` é servida como Inter, a mesma do corpo do app, e os títulos
 * usam Geist, como no app.
 *
 * 🔴 25/08/2026: as duas davam **404 em produção**. Apontavam para
 * `/assets/fonts/`, que era rota do **front-go** — desligado em 22/08. Ali o
 * Caddy passou a servir `/var/lib/offcode/frontend/dist`, onde `fonts/` não
 * existe. Resultado medido no ar: 10 `@font-face` registradas, **0
 * carregadas**, e o site inteiro pintando em `system-ui`.
 *
 * 🔑 Fonte declarada e não servida NÃO dá erro — e "o mesmo domínio serve"
 * deixou de ser verdade sem ninguém tocar nesta folha. O arquivo agora mora
 * no ESPELHO (`_local/fonts/`), que é a árvore que o `build_deploy.py`
 * publica: o que serve a página e o que declara a fonte passaram a ser a
 * mesma coisa.
 *
 * ⚠️ Este bloco já foi apagado uma vez pelo `poda_fontes.py`, que resolvia
 * URL absoluta contra a raiz do sistema de arquivos e podava qualquer
 * `@font-face` com `url(/...)`. Com o arquivo em `_local/`, a conferência
 * dele passou a ser verdadeira em vez de dispensada.
 */
@font-face {
  font-family: "OFFCODE Sans";
  src: url("/_local/fonts/Inter.1dc044f4.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  /* `swap` e não `block`: com block o texto fica INVISÍVEL até a fonte
   * chegar, e numa tela de preço isso é o número sumindo da frente de quem
   * está decidindo uma ordem. */
  font-display: swap;
}

@font-face {
  font-family: "Geist";
  src: url("/_local/fonts/Geist.9d846db8.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* A única monoespaçada do site. Até aqui todo número, endereço e hash caía em
 * `ui-monospace, SFMono-Regular, Menlo, monospace` — que é uma família
 * DIFERENTE em cada sistema, e nenhuma delas alinha dígito com dígito do mesmo
 * jeito. Numa coluna de dinheiro isso se lê como desalinhamento do dado.
 *
 * Subconjunto LATIN só (31 KB): o que ela pinta é dígito, ticker, endereço e
 * hash — nada disso sai do ASCII. Um russo lendo a carteira em cirílico
 * continua com o texto em `OFFCODE Sans`, e só os números trocam de fonte.
 *
 * 🔑 Arquivo no disco do espelho, como as outras duas. Fonte declarada e não
 * servida não dá erro — cai calada para a próxima da pilha, e a pilha aqui
 * termina em `monospace`, que é o que havia antes. */
@font-face {
  font-family: "JetBrains Mono";
  src: url("/_local/fonts/JetBrainsMono.340e696a.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* Títulos em Geist, como no app. O resto herda `OFFCODE Sans` das regras que
 * já existem — nenhum markup muda. */
h1,
h2,
h3 {
  font-family: "Geist", "OFFCODE Sans", system-ui, sans-serif;
}

/* ── as outras três famílias que a captura pede e ninguém serve ──────────
 *
 * `OFFCODE Sans` não era o único caso. Contado nas 451 folhas do espelho:
 *
 *     112 regras  font-family: SF Pro          ← sem reserva nenhuma
 *      93 regras  font-family: Inter           ← sem reserva nenhuma
 *      32 regras  font-family: Rubik           ← sem reserva nenhuma
 *      21 regras  font-family: SF Pro, OFFCODESans, sans-serif
 *
 * 🔑 Pilha de UMA família só não cai para `sans-serif` — cai para o padrão
 * do documento, que é **serif**. Medido ao vivo na frase da dobra da
 * `/bot-trading`: 444px em `"SF Pro"` e 444px em `serif`, o mesmo pixel.
 * Metade do texto do site estava em Times sem ninguém ter escolhido isso.
 *
 * O conserto é o mesmo que já valia para `OFFCODE Sans`: em vez de reescrever
 * 258 regras espalhadas por folha minificada de terceiro, a família declarada
 * passa a EXISTIR.
 *
 * - `SF Pro` é a face da Apple, proprietária: não há como servi-la. Inter é
 *   o neo-grotesco desenhado para interface que o app já usa, e é o que a
 *   própria pilha de 21 regras pede logo em seguida (`OFFCODESans`).
 * - `Inter` é literalmente o arquivo que está aqui. Nada a decidir.
 * - `Rubik` é a face dos NÚMEROS (`.asset .amount`, `.number`, `.fiat`) —
 *   saldo de carteira em Times era o pior lugar para isso acontecer.
 *
 * ⚠️ Fora, de propósito: `HarmonyOS Sans SC` (face CJK — apontar um arquivo
 * só de latim como primária lá trocaria a decisão de quem escreveu o texto
 * chinês) e as de ícone (`VideoJS`, `swiper-icons`, `entypo`,
 * `copenhagen-icons`, `element-icons`), que não são texto: aliasá-las
 * trocaria glifo de ícone por letra.
 */
@font-face {
  font-family: "SF Pro";
  src: url("/_local/fonts/Inter.1dc044f4.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "OFFCODESans";
  src: url("/_local/fonts/Inter.1dc044f4.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Inter";
  src: url("/_local/fonts/Inter.1dc044f4.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Rubik";
  src: url("/_local/fonts/Inter.1dc044f4.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* OFFCODE brand layer.
 *
 * Loaded after the mirrored stylesheets. Everything here is either a brand
 * decision or the removal of somebody else's mark — no layout is redefined.
 */

/* --- third-party marks -------------------------------------------------
 * Chelsea FC, Ferrari, the brand ambassador and the partner logo wall belong
 * to their owners; on an OFFCODE page they would also be a claim we cannot
 * make. Hidden rather than cut out of the DOM: deleting these containers
 * meant balancing tags by hand and that took neighbouring sections with it.
 */
/* Slot de herói vazio não deixa buraco.
 *
 * A dobra ficou só com a frase (dono, 24/08/2026): eyebrow, subtítulo e a
 * linha de selos saem VAZIOS pelo `home_narrativa.py`, não cortados. O `<p>`
 * continua no DOM — cortar nó do herói por regex já levou o carrossel inteiro
 * junto uma vez — e some por aqui.
 *
 * 🔑 Esconder o vazio, e não remover o nó, é o padrão deste arquivo desde a
 * primeira linha: o HTML segue válido e nada vizinho desalinha.
 */
.oc-hero-eyebrow:empty,
.oc-hero-sub:empty,
.oc-hero-note:empty {
  display: none !important;
}

/* As setas do herói.
 *
 * `.hero-banner .bottom .nav` são os dois `‹ ›` no canto de baixo: a navegação
 * do carrossel de slides da ORIGEM. Aqueles slides eram banner de campanha e
 * o truthpass os esvaziou; o herói que aparece é o nosso, desenhado por cima,
 * e é um só. O Vue que movia o carrossel também não veio na captura.
 *
 * 🔑 Seta que não leva a slide nenhum é o mesmo caso do blob de IA e do globo
 * de moeda no cabeçalho: controle que não faz nada custa mais que controle
 * ausente — a pessoa clica, nada acontece, e passa a desconfiar dos outros.
 *
 * Escondido, não cortado: o par está dentro do `.bottom`, que é sobreposição
 * absoluta no herói. Sem os dois filhos ele colapsa e não deixa buraco.
 * Cortar nó do DOM neste arquivo já levou seção vizinha junto.
 */
.hero-banner .bottom .nav {
  display: none !important;
}

.partners,
.partner-strip,
.bx-nav-menu-ambassador,
.bx-nav-menu-base.bx-nav-menu-ambassador {
  display: none !important;
}

/* The hero slide built around the Chelsea partnership loses its subtitle with
   the sponsor copy removed; keep the block from collapsing oddly. */
.hero-banner .content .subtitle:empty {
  display: none;
}

/* --- brand accent ------------------------------------------------------
 * The mirrored stylesheets were recoloured in place, so this only covers
 * tokens that resolve at runtime rather than sitting in a stylesheet.
 */
:root {
  --offcode-brand: #f7931a;
  --offcode-brand-hover: #ffb255;
  --offcode-brand-pressed: #d87d10;
}

/* The sign-in page's left panel is the Chelsea partnership lockup plus the
   campaign artwork. Both are sponsor material, so the panel keeps its shape
   and loses its contents. */
.ship-logo,
.login-content-left .active-img,
.login-content-left .active-img-login {
  display: none !important;
}

/* --- produto que a OFFCODE não tem -------------------------------------
 * O truthpass marca com data-oc-hide o item de menu cujo produto não existe
 * nem está no roteiro: CFD de ouro/petróleo/câmbio (produto regulado),
 * empréstimo e dual investment (a rota /earn responde 410), P2P e depósito
 * fiat (apontam pra fiat.offcode.pro, que não resolve), leaderboard e
 * recrutamento de trader (expõem desempenho de gente de terceiro), conta
 * demo, proof of reserves sem página que sustente, e programa de embaixador.
 *
 * Some por CSS, não por corte de nó: balancear tag na mão já levou seções
 * vizinhas junto quando removi o bloco de patrocinadores deste mesmo espelho.
 * O item vira invisível; a linha continua no HTML e o layout não desmonta.
 */
[data-oc-hide] {
  display: none !important;
}
.sub-menus-cell:has(.name > [data-oc-hide]),
.sub-menus-cell:has(> .menu-info .name > [data-oc-hide]) {
  display: none !important;
}

/* --- selo de "em breve" ------------------------------------------------
 * Copy trading, futures grid, martingale, strategy lab, prediction e o cartão
 * são produtos do roteiro, não do presente. O front-go já marca /prediction
 * assim, então o padrão vem de lá em vez de ser inventado aqui.
 */
.oc-soon {
  font-style: normal;
  font-size: 10px;
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  vertical-align: middle;
  border-radius: 3px;
  color: var(--offcode-brand, #f7931a);
  white-space: nowrap;
}

/* 🔴 A caixa do selo NUNCA apareceu. `margin-left`, `padding` e `border`
 * estavam na regra acima, e a origem reseta as três num bloco de
 * especificidade maior:
 *
 *     [dir] em { margin: 0; padding: 0; border: 0 }   → (0,1,1)
 *
 * Classe sozinha é (0,1,0) e perde. O que se via era a palavra "SOON" em
 * laranja, colada no título, sem moldura — parecia escolha de design.
 * `[dir] .oc-soon` é (0,2,0) e devolve o desenho. */
[dir] .oc-soon {
  margin-left: 6px;
  padding: 2px 5px;
  border: 1px solid var(--offcode-brand, #f7931a);
}

/* Slide de carrossel e banner que só existiam para anunciar prêmio ficam sem
   texto depois do truthpass. Vazio, o nó vira uma faixa de altura morta —
   melhor sumir do que deixar buraco. */
.hero-banner .content .title:empty,
.hero-banner .content .desc:empty,
.banner-title:empty,
.banner-desc:empty {
  display: none !important;
}

/* --- resto de promessa de brinde ---------------------------------------
 * O truthpass tirou a frase ("Sign up now to claim a welcome gift worth"),
 * mas o valor mora num <strong> separado e sobrava sozinho na tela: um ícone
 * de presente e "7,800 USDT" soltos, que lidos assim prometem ainda mais do
 * que a frase inteira. O bloco de dica sai junto.
 */
/* 22/08/2026: o slot voltou a ter texto — agora e a frase de fechamento da
 * narrativa ("The exchange was the beginning..."). O icone de presente FICA
 * escondido: presente ao lado dessa frase e a promessa velha por outro meio.
 *
 * 🔑 Some quando VAZIO, aparece quando tem conteudo — mesma ideia do
 * `:empty` logo acima. Regra que escondia sempre transformava qualquer copy
 * futura naquele slot em texto invisivel, e ninguem descobriria: o texto
 * esta no HTML, no censo e no `textContent`. So nao esta na tela. */
.cta-gift-box,
img.hint-icon {
  display: none !important;
}

.cta-hint-text:empty,
.hint-text:empty,
.cta-hint-text:has(> .highlight:empty),
.hint-text:has(> .highlight:empty) {
  display: none !important;
}

/* O selo flutuante do canto é um GIF com "2,000,000 USDT" desenhado no pixel.
   Não há texto para reescrever — só sumir. */
img[src*="activity-entry"],
[class*="activity-entry"] {
  display: none !important;
}

/* Selo flutuante do canto: <img class="actve-img-icon"> com "2,000,000 USDT"
   desenhado no pixel. O seletor anterior mirava o nome do arquivo de origem;
   o arquivo servido tem hash, então o gancho é a classe. */
img.actve-img-icon,
.actve-img-icon {
  display: none !important;
}

/* Ícone órfão: o "🔥" e o selo de promo pertenciam a TradFi e a itens que
   sumiram. Sem o rótulo ao lado eles viram um símbolo solto na barra. */
.nav-item:has([data-oc-hide]) .ic-brand,
.name:has([data-oc-hide]) .ic-brand,
.nav-item > .ic-brand.hot,
.ic-brand.promo {
  display: none !important;
}

/* A categoria inteira some quando O RÓTULO DELA está marcado.
 *
 * A primeira versão usava `li.nav-item-wrap:has([data-oc-hide])`, que casa com
 * qualquer descendente — e como itens escondidos (CFD Futures, Loan, Dual
 * Investment) moram DENTRO do dropdown de Futures e de Buy Crypto, as duas
 * categorias inteiras sumiram da barra. O seletor agora exige que a marca
 * esteja no rótulo direto da categoria, não em qualquer lugar abaixo dela.
 */
li.nav-item-wrap > .nav-item > .nav-name[data-oc-hide],
li.nav-item-wrap > a.nav-item > .nav-name[data-oc-hide] {
  display: none !important;
}
li.nav-item-wrap:has(> .nav-item > .nav-name[data-oc-hide]),
li.nav-item-wrap:has(> a.nav-item > .nav-name[data-oc-hide]) {
  display: none !important;
}

/* --- herói ---------------------------------------------------------------
 * Os slides do carrossel eram campanha da origem: dois vídeos e uma arte,
 * 22 MB, anunciando promoção que a OFFCODE não faz. A mídia sai e a seção
 * fica com o fundo da marca; o texto vem do bloco que o truthpass injeta,
 * com a copy do próprio front-go.
 */
.hero-banner .bg-swiper .bg-slide > img,
.hero-banner .bg-swiper .bg-slide > video,
.hero-banner .bg-swiper .bg-slide > picture {
  display: none !important;
}

.hero-banner {
  background:
    radial-gradient(
      120% 90% at 78% 18%,
      rgba(247, 147, 26, 0.13) 0%,
      transparent 58%
    ),
    radial-gradient(
      90% 70% at 12% 82%,
      rgba(247, 147, 26, 0.06) 0%,
      transparent 60%
    ),
    #08080a;
}

/* A coluna do herói cresceu de 640 para 800px e o bloco subiu de 50% para
 * 43%. Motivo: a headline nova tem 74 caracteres contra 42 da anterior e
 * quatro linhas em vez de três. Em 640px ela quebrava em CINCO linhas e o
 * bloco descia por cima do botão "Sign Up" — 63px de sobreposição, texto em
 * cima de botão.
 *
 * 🔑 Preferi ALARGAR a coluna a diminuir o tipo. A headline é a tese da
 * página; encolher a tese para caber é resolver o layout no lugar errado.
 * Em 800px ela cabe nas quatro linhas do texto, no corpo cheio de 62px.
 *
 * 🔴 Centrado (`top: 50%` + `translateY(-50%)`) o bloco cresce para os DOIS
 * lados e desperdiça ~70px de faixa vazia acima enquanto encosta no botão
 * abaixo. Ancorado pelo rodapé (`bottom: 38%`), ele nasce logo acima do
 * botão — que fica a ~63% da altura do herói — e cresce para cima, para
 * dentro do espaço que estava sobrando. Percentual, então acompanha
 * qualquer altura de janela. */
.oc-hero {
  position: absolute;
  z-index: 3;
  left: max(24px, 5vw);
  /* 278px é onde o botão "Sign Up" da origem mora, contados do rodapé do
   * herói — medido, e constante em qualquer altura de janela (não é
   * percentual). O bloco encosta 22px acima dele e cresce para cima. */
  bottom: 300px;
  max-width: 800px;
  pointer-events: none; /* os botões do herói ficam abaixo e seguem clicáveis */
}
.oc-hero-eyebrow {
  margin: 0 0 18px;
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--offcode-brand, #f7931a);
}
/* `white-space: pre-line` honra as quebras que vêm no próprio texto e ainda
 * requebra linha longa quando a tela aperta — o `<br>` não faz a segunda
 * parte, e ainda seria elemento novo no DOM.
 *
 * 🔑 `text-wrap: balance` SAI: ele reequilibra as quatro linhas em cinco
 * mais parelhas, desfazendo exatamente o contraste que as quebras marcam. */
.oc-hero-title {
  margin: 0 0 26px;
  /* 🔑 O corpo responde à ALTURA, não só à largura. O herói ocupa a dobra
   * inteira, então numa janela de 900px ele tem 757px e o mesmo bloco que
   * sobrava numa tela de 27" encosta no botão. O termo em `vh` faz o tipo
   * ceder quando falta altura e devolve o corpo cheio quando há espaço.
   *
   * 🔑 O teto subiu de 62px para 120px em 24/08/2026 porque a headline virou
   * UMA linha curta (`NO KYC.`). Quatro linhas a 62px pediam 258px de altura;
   * uma linha a 120px pede 125px. O corpo dobrou e o bloco ENCOLHEU — é a
   * troca que a copy nova permite, e desperdiçá-la seria deixar a tese do
   * mesmo tamanho de quando ela dividia a dobra com outras três linhas.
   *
   * 🔴 O teto foi 120px enquanto a headline era UMA linha curta (`NO KYC.`).
   * Em 28/08/2026 ela virou duas — a frase da identidade subiu do rodízio — e
   * 120px poriam `OFFCODE WANTS YOUR ORDER.` em três linhas de 800px, com a
   * primeira metade em mais duas. Cinco linhas de headline não são headline.
   *
   * 🔑 O teto novo sai do texto mais LARGO em sete idiomas, não do inglês:
   * `SETIAP BURSA MENGINGINKAN IDENTITAS ANDA.` (indonésio, 40 caracteres) é
   * a linha de cima, e ela roda a `.42em` do corpo aqui. A 64px isso dá 27px
   * e cabe em duas linhas na coluna de 800px. */
  font-size: clamp(30px, min(5.4vw, 8.5vh), 64px);
  line-height: 1.04;
  letter-spacing: -0.02em;
  font-weight: 700;
  color: #f5f3ee;
  white-space: pre-line;
}

/* `pretty` em vez de `balance`: evita a última linha órfã de uma palavra sem
 * mexer no comprimento das outras. */
/* A primeira linha do título.
 *
 * 🔴 Ela valia `.42em` e cinza `#8f8b82` — desenho da frase ANTERIOR, em que
 * a linha de cima dizia o que as outras corretoras querem e existia para ser
 * derrubada pela de baixo. A frase de 29/08/2026 é outra figura: `PRIVACIDADE
 * É SUA. / TRANSPARÊNCIA É NOSSA.` é um PAR, e as duas metades valem o mesmo.
 * Com o desenho antigo, o benefício de quem lê saía em 42% do corpo e em
 * cinza, e o que a casa promete de si saía inteiro e branco.
 *
 * 🔑 O contraste passa a ser só de COR — laranja da marca em cima, branco em
 * baixo — e o corpo é o mesmo. Cor separa as duas posses sem hierarquizá-las,
 * e funciona nos sete idiomas: não depende de caixa, que não existe em híndi
 * nem em chinês.
 *
 * ⚠️ O `margin-bottom` cai para `.06em`: com o mesmo corpo, o respiro de
 * `.3em` abria um vão maior que a entrelinha e as duas linhas deixavam de se
 * ler como uma frase só.
 *
 * 🔴 O laranja SAIU (dono, 02/09/2026): as duas linhas ficam no MESMO branco
 * do título (`#f5f3ee`, herdado do `.oc-hero-title`). Sem cor própria aqui,
 * o par posse/posse se lê como uma frase só, e a quebra em duas linhas (o
 * `display: block`) continua sendo o que separa as metades. */
.oc-hero-antes {
  display: block;
  margin-bottom: 0.06em;
  line-height: 1.04;
}

.oc-hero-sub {
  margin: 0;
  font-size: clamp(15px, 1.2vw, 18px);
  line-height: 1.6;
  color: #b9b5aa;
  max-width: 34em;
  text-wrap: pretty;
}

/* --- ficha técnica da dobra ----------------------------------------------
 * A copy de 24/08/2026 é um gancho e uma ficha. `NO KYC.` é a tese e mora no
 * `h1`; as duas sentenças seguintes são especificação e moram aqui.
 *
 * 🔑 ESCOPO `.hero-banner`, e não `.oc-hero-sub` solto: essa mesma classe é o
 * corpo das páginas `Soon` que o `truthpass` monta (`.oc-soon-page`), e lá o
 * texto é frase corrida em caixa mista. Caixa alta escapando para elas
 * transformaria um aviso de "em breve" em manchete.
 *
 * 🔑 Caixa alta pede três coisas que a caixa mista não pede: entreletra (o
 * desenho da maiúscula fecha demais no corpo pequeno), entrelinha maior (não
 * há descendente separando as linhas) e mais contraste — #cfcabd no lugar do
 * #b9b5aa do parágrafo comum, porque branco sobre vídeo em movimento já é o
 * pior caso de legibilidade da página.
 *
 * 🔑 `600` e não `700`: no peso do título ela competiria com a tese em vez de
 * apoiá-la, e a hierarquia inteira existe para que `NO KYC.` chegue primeiro.
 *
 * 🔑 `pre-line` honra a quebra que vem no próprio texto, e essa quebra separa
 * as DUAS ofertas — negociar e ganhar. Sem ela, "40× LEVERAGE. EARN A SHARE"
 * cai na mesma linha e as duas viram uma frase só.
 *
 * 🔑 `40em` é medida, não gosto: a 19px a primeira sentença ocupa ~645px e a
 * segunda ~1046px. Em 760px de coluna isso fecha em 1 + 2 linhas. Numa coluna
 * mais estreita a primeira requebra e o paralelismo das duas sentenças some.
 */
.hero-banner .oc-hero-sub {
  margin: 0;
  max-width: 40em;
  font-size: clamp(15px, 1.35vw, 19px);
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: 0.045em;
  color: #cfcabd;
  white-space: pre-line;
  text-wrap: pretty;
}

/* --- as margens do herói, que nunca aplicaram --------------------------
 * 🔴 Medido em 24/08/2026: `margin-bottom` computava 0px em `.oc-hero-title`
 * e em `.oc-hero-note`, nas duas. A folha da origem traz um reset
 * `[dir] h1, [dir] p, [dir] div, … { margin: 0 }` — especificidade (0,1,1),
 * que VENCE `.oc-hero-title` (0,1,0). As margens estavam escritas, liam-se
 * como intenção no arquivo, e não existiam na tela: o espaço entre os
 * registros era só a entrelinha do tipo grande, por acaso.
 *
 * 🔑 `.hero-banner .oc-hero-*` dá (0,2,0), que vence (0,1,1) porque conta
 * duas classes contra uma classe. É a mesma correção do `[dir][dir]` mais
 * abaixo nesta folha, e não `!important`: `!important` esconde a disputa em
 * vez de resolvê-la, e a próxima pessoa não descobre que existe um reset.
 *
 * 🔑 Fica em regra SEPARADA da base de propósito. A base também veste as
 * páginas `Soon`, que não estão dentro de `.hero-banner`; se o escopo
 * entrasse nela, elas perderiam cor, peso e entrelinha de uma vez.
 */
.hero-banner .oc-hero-title {
  margin: 0 0 24px;
}
.hero-banner .oc-hero-sub {
  margin: 0;
}

/* --- a oferta, em evidência ----------------------------------------------
 * Pedido do dono em 24/08/2026: a segunda sentença tem de sair na frente da
 * primeira — "um pouco maior e mais branco". Ela desceu para o slot da proof
 * line no `home_narrativa.py`, que é o único jeito de dar corpo e cor só a
 * ela sem partir o nó de texto que o catálogo do i18n usa como chave.
 *
 * 🔑 A escada fica: 120px branco (a tese) → 19px #cfcabd (o que dá para
 * fazer) → 24px #f5f3ee (o que dá para ganhar). O terceiro degrau é maior
 * que o segundo DE PROPÓSITO: o meio é especificação e a base é a oferta.
 * Sem os dois eixos — corpo E cor — o degrau não se lê como degrau.
 *
 * 🔑 `#f5f3ee` é o mesmo branco do `h1`, não um branco novo: a linha entra
 * no nível de leitura da tese, e a folha não ganha um quinto cinza.
 *
 * 🔑 Entreletra CAI de .045em para .03em ao subir de 19px para 24px. Caixa
 * alta pede tracking porque a maiúscula fecha no corpo pequeno; no corpo
 * grande o mesmo tracking abre demais e a frase começa a soletrar.
 *
 * 🔑 `pretty` sobrescreve o `balance` da base: `balance` reparte as duas
 * linhas em duas metades parelhas e desmancha a linha cheia que dá peso à
 * frase. Aqui só é preciso evitar a órfã de uma palavra.
 */
/* 🔑 Uma palavra em negrito dentro da ficha. `800` e não `700` porque a
 * ficha já é `600`: a distância entre 600 e 700 é um degrau na maioria das
 * famílias e nenhum em algumas — e neste espelho as duas webfonts da marca
 * (`Geist`, `Inter`) respondem 404, então quem pinta é a fonte do sistema.
 * A cor entra junto pelo mesmo motivo: peso sozinho é uma aposta na métrica
 * de uma fonte que pode não ser a que vai carregar. */
.hero-banner .oc-hero-sub strong {
  /* 🔑 `1.18em` e não um valor em px: o corpo sai de 19px no desktop e 15px
   * no telefone, e a palavra sobe na mesma proporção nos dois sem uma segunda
   * escala para manter em sincronia à mão.
   *
   * 🔑 O teto é o irmão de baixo. A oferta (`.oc-hero-note`) vive a 24px, e
   * uma palavra da ficha empatando com ela desfaria a escada que o dono pediu
   * — 22,4px sobe o suficiente para marcar e para de subir antes disso.
   *
   * 🔑 `line-height: 1` porque a entrelinha herda como NÚMERO (1.5): sem isto
   * a palavra maior calcularia 22,4 × 1.5 = 33,6px e empurraria a caixa da
   * linha inteira, abrindo um degrau no meio de um parágrafo de uma linha só.
   *
   * 🔑 A entreletra CAI de .045em para .03em, como na oferta: caixa alta abre
   * demais no corpo maior e a palavra começa a soletrar. */
  font-size: 1.18em;
  line-height: 1;
  letter-spacing: 0.03em;
  font-weight: 800;
  color: #f5f3ee;
}

/* --- a entrada da oferta -------------------------------------------------
 * `EARN A SHARE OF TRADING FEES THROUGH THE` é a entrada; o que o dono pediu
 * em evidência é o que vem depois dela. Cai a METADE do corpo do irmão.
 *
 * 🔑 `.5em` e não `12px`: a medida é relativa ao `clamp` do `.oc-hero-note`,
 * então a entrada acompanha sozinha a janela larga (24px → 12px) e a janela
 * baixa (20px → 10px). Número absoluto aqui viraria uma segunda escala para
 * manter em sincronia com a primeira, à mão, em três media queries.
 *
 * 🔑 `display: block` para ela ocupar a própria linha. Em linha corrida, um
 * trecho de 12px emendado num de 24px deixa o meio da frase com dois corpos
 * e a leitura tropeça; em linha própria vira antetítulo, que é o que ela é.
 *
 * 🔑 A entreletra SOBE (.06em) ao cair para 12px, ao contrário da regra do
 * irmão, que desce ao subir para 24px. É a mesma lei: caixa alta fecha no
 * corpo pequeno e abre no grande. */
.hero-banner .oc-hero-note .oc-lead {
  display: block;
  margin-bottom: 6px;
  font-size: 0.5em;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: #cfcabd;
}

.hero-banner .oc-hero-note {
  margin: 14px 0 0;
  max-width: 30em;
  font-size: clamp(17px, 1.7vw, 24px);
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: 0.03em;
  color: #f5f3ee;
  text-wrap: pretty;
}

/* A proof line é outro registro: não é continuação do parágrafo, é a ficha
 * técnica. Ganha ar acima, corpo menor e entreletra maior para ler como
 * carimbo — antes vinha colada no texto, parecendo a quinta linha dele. */
.oc-hero-note {
  margin: 24px 0 0;
  font-size: 12px;
  line-height: 1.75;
  letter-spacing: 0.06em;
  color: #7e796e;
  /* lista de seis itens: `balance` reparte as duas linhas em vez de deixar
     "DAO GOVERNANCE" sozinha embaixo. */
  text-wrap: balance;
}

/* ── a ação da dobra: o botão e os três números (28/08/2026) ──────────────
 *
 * 🔑 `pointer-events: auto`. O `.oc-hero` inteiro é `none` de propósito — os
 * botões da ORIGEM ficam por baixo dele e precisavam seguir clicáveis. O
 * primeiro elemento nosso que existe para ser clicado tem de devolver o
 * evento, senão ele é um botão que não é botão.
 */
.oc-hero-acao {
  display: flex;
  flex-direction: column;
  gap: 26px;
  pointer-events: auto;
  max-width: 520px;
}

/* 🔴 `margin`, `padding` e `background` deste bloco inteiro moram do lado
 * `[dir]`. Escritos em classe sozinha (0,1,0) eles perdem para o reset da
 * origem (`[dir] div, [dir] p, [dir] a, … { border:0; margin:0; padding:0 }`,
 * 0,1,1) — e a regra chega ao navegador com METADE das declarações
 * aplicadas, sem erro nenhum.
 *
 * Medido na primeira versão: o botão saiu com `background: rgba(0,0,0,0)` e
 * `padding: 0px`. A cor, o raio e a fonte tinham entrado; só a caixa sumiu.
 * É o mesmo defeito descrito três vezes nesta folha, e eu o repeti. */
[dir] .oc-hero-acao {
  margin-top: 32px;
}

/* 30/08/2026: o CTA da dobra é o botão padrão do site (`botao.css`) — só que
 * a marcação já existia (`<a>` com `.oc-hero-cta-txt` e `.oc-hero-cta-seta`),
 * então o corte é feito AQUI sobre esses dois spans, sem reescrever a home:
 * o texto é a barra laranja cortada, a seta é o bloco escuro.
 *
 * `isolation: isolate` cria o contexto de empilhamento para os pseudo-
 * elementos em `z-index: -1` ficarem atrás do texto mas DENTRO do link — sem
 * ele, iriam parar atrás do vídeo da dobra. */
[dir] .oc-hero-cta {
  --h: 56px;
  --r: 16px;
  --raio: 16px;
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: stretch;
  gap: 0;
  height: var(--h);
  min-width: 300px;
  max-width: 100%;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  color: #0a0a0a;
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.2px;
  line-height: 1;
  text-decoration: none;
  transition: filter 0.15s ease;
}
[dir] .oc-hero-cta:hover {
  color: #0a0a0a;
  filter: brightness(1.07);
  box-shadow: none;
}
[dir] .oc-hero-cta:focus-visible {
  outline: 2px solid #ffb04d;
  outline-offset: 3px;
}

[dir] .oc-hero-cta-txt {
  position: relative;
  flex: 1;
  display: flex;
  align-items: center;
  min-width: 0;
  padding: 0 44px 0 22px;
}
[dir] .oc-hero-cta-txt::before,
[dir] .oc-hero-cta-txt::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  z-index: -1;
  background: var(--offcode-brand, #f7931a);
}
[dir] .oc-hero-cta-txt::before {
  left: 0;
  right: calc(var(--r) + var(--h) / 2);
  border-radius: var(--raio) 0 0 var(--raio);
}
[dir] .oc-hero-cta-txt::after {
  right: var(--r);
  width: var(--h);
  transform: skewX(-26.6deg);
}

[dir] .oc-hero-cta-seta {
  position: relative;
  flex: 0 0 calc(var(--h) + 20px);
  width: calc(var(--h) + 20px);
  height: var(--h);
  margin-left: calc(-1 * (var(--h) / 4 + 4px));
  display: flex;
  align-items: center;
  justify-content: center;
  padding-left: calc(var(--h) / 4 + 6px);
  border-radius: 0;
  background: transparent;
  color: var(--offcode-brand, #f7931a);
  font-size: 21px;
}
[dir] .oc-hero-cta-seta::before,
[dir] .oc-hero-cta-seta::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  z-index: -1;
  background: #171717;
}
[dir] .oc-hero-cta-seta::before {
  left: calc(var(--h) / 4);
  width: calc(var(--h) - 16px);
  transform: skewX(-26.6deg);
}
[dir] .oc-hero-cta-seta::after {
  left: calc(var(--h) / 4 + 16px);
  right: 0;
  border-radius: 0 var(--raio) var(--raio) 0;
  box-shadow: inset -1px -1px 0 rgba(255, 255, 255, 0.06);
}
[dir] .oc-hero-cta:hover .oc-hero-cta-seta {
  color: #ffb04d;
}

/* 🔑 O `Sign Up` da ORIGEM sai da dobra. Ele ficava exatamente onde a ação
 * nova entrou — medido: o dele em y=688, o nosso em y=702, um por cima do
 * outro — e mesmo sem colidir seriam DOIS botões primários na mesma dobra
 * dizendo coisas diferentes. O desenho do dono tem um.
 *
 * Escopo `.hero-banner`: o mesmo `.cta-btn` aparece de novo no fim da página,
 * onde ele é o convite legítimo e fica.
 *
 * 🔴 `.hero-banner .cta-btn` (0,2,0) NÃO bastou: a regra da origem que dá
 * `display: flex` ao botão empata em especificidade e vem depois na cascata.
 * Medido: o botão seguia com 134px de largura e `display: flex`, sobreposto ao
 * nosso. `[dir] .hero-banner .cta-actions .cta-btn` é (0,3,1) e ganha.
 *
 * 🔑 Especificidade se MEDE, não se conta de cabeça — mesma lição que o
 * `carteira.css` registra no nó da carteira. */
[dir] .hero-banner .cta-actions .cta-btn {
  display: none;
}

/* ⚠️ Os três números são fixos e não saem de fonte da casa — ver o comentário
   em `_tools/home_narrativa.py` (`ACAO`), que registra a decisão e onde
   conferir se um dia houver rota. */
.oc-hero-nums {
  display: flex;
  gap: 34px;
  flex-wrap: wrap;
}

.oc-hero-num {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.oc-hero-num-rot {
  font-size: 12px;
  letter-spacing: 0.04em;
  color: #7e796e;
}

.oc-hero-num-val {
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: clamp(22px, 2.2vw, 30px);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.02em;
  color: #f5f3ee;
}

/* As redes da casa, sob a ficha de números.
 *
 * 🔑 `pointer-events: auto` é obrigatório: o `.oc-hero` inteiro é
 * `pointer-events: none` (para os botões da captura, que ficam por baixo,
 * seguirem clicáveis). Sem devolver o evento aqui, os três ícones seriam
 * decoração — apareceriam, teriam cursor de link e não abririam nada.
 *
 * A área de toque é 34x34 com o desenho a 18px: o alvo confortável não é o
 * tamanho do ícone. */
.oc-hero-redes {
  display: flex;
  gap: 6px;
  margin-top: 26px;
  pointer-events: auto;
}

.oc-hero-rede {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 9px;
  color: #7e796e;
  transition:
    color 0.16s ease,
    background-color 0.16s ease;
}

[dir] .oc-hero-rede {
  border: 0;
  background: transparent;
}

.oc-hero-rede svg {
  width: 18px;
  height: 18px;
  display: block;
}

.oc-hero-rede:hover,
.oc-hero-rede:focus-visible {
  color: #f5f3ee;
  background: rgba(255, 255, 255, 0.07);
}

.oc-hero-rede:focus-visible {
  outline: 2px solid var(--offcode-brand, #f7931a);
  outline-offset: 2px;
}

/* 🔴 Ancorado pelo RODAPÉ, o bloco afunda em janela alta.
 *
 * `bottom: 150px` prende o bloco ao pé do herói: como o herói ocupa a tela
 * inteira, cada pixel a mais de altura de janela vira um pixel a mais de faixa
 * vazia ACIMA do texto. Medido em 1440×900: 385px sobrando em cima contra
 * 150px embaixo, com a headline começando na metade de baixo da dobra. Numa
 * janela de 1100 o texto começava a 585px — mais da metade da tela vazia antes
 * da primeira palavra.
 *
 * O comentário anterior justificava a âncora pelo botão "Sign Up" da origem,
 * que ficava logo abaixo. Ele não existe mais: conferido no ar, não há
 * NENHUM elemento visível entre o fim do bloco e o rodapé do herói. A razão
 * caducou junto com o botão.
 *
 * Agora o bloco é centrado no espaço ÚTIL — a tela menos a barra de 65px, daí
 * o `+32px` no centro. É estável em qualquer altura (medido em 700, 800, 900 e
 * 1080: a folga acima da barra vai de 135 a 325px e nunca encosta) e não
 * depende de saber a altura do bloco, que muda com o idioma: a headline em
 * alemão e russo é mais alta que a inglesa. */
.hero-banner .oc-hero {
  bottom: auto;
  top: calc(50% + 32px);
  transform: translateY(-50%);
}

/* No mobile o herói não é sticky nem centralizado: empilha no topo.
 *
 * 🔴 Este bloco vinha sem escopo e o `padding` NUNCA aplicou: o mesmo reset
 * da origem que zera as margens (`[dir] div, [dir] p, … { padding: 0 }`,
 * especificidade (0,1,1)) vence `.oc-hero` (0,1,0). Medido em 24/08/2026 num
 * viewport de 390px: a copy inteira encostava em x=0, sem calha nenhuma. O
 * defeito é antigo e só ficou visível quando o tipo cresceu — com quatro
 * linhas de 28px o texto encostado passava por decisão de layout.
 *
 * 🔑 `.hero-banner .oc-hero` dá (0,2,0) e vence. Os 20px são a calha do
 * próprio telefone da origem (a barra inferior de abas usa a mesma), não um
 * número novo — calha diferente da do resto do app leria como desalinho. */
@media (max-width: 780px) {
  .hero-banner .oc-hero {
    position: static;
    transform: none;
    max-width: none;
    padding: 72px 20px 24px;
  }
}

/* --- restos da campanha --------------------------------------------------
 * "View details" apontava pro regulamento da promoção que não existe mais.
 * O segundo botão do herói era "Download App", que o truthpass renomeou pra
 * "Create account" — e aí a dobra ficou com dois botões dizendo a mesma
 * coisa, um deles com ícone de QR code para baixar um app inexistente.
 * O ícone de download da barra e o QR do menu caem pelo mesmo motivo.
 */
.cta-actions .cta-btn.bx-btn-secondary,
.action-item:has(.ic-download),
.ic-download,
.qr-code-wrapper,
.download-tips {
  display: none !important;
}

/* O "x" solto no canto inferior direito, em 976 páginas.
 *
 * `.actve-icon` (o typo é da origem) é a peça flutuante de campanha: um GIF
 * promocional dentro de um `<a href= target="_blank">` — com o href VAZIO, que
 * recarrega a própria página — mais o botão de fechar. O GIF vinha de
 * `social_feed_pictures/` e não entrou no artefato, então o widget mediu 0x0 e
 * sobrou o "x" sozinho, boiando sobre o conteúdo sem nada para fechar.
 *
 * 🔑 Some a peça inteira, não só o "x": esconder o botão deixaria o link
 * invisível de 0x0 no ar, e um `<a>` que recarrega a página ao ser clicado por
 * acaso é pior que um ícone órfão. */
.actve-icon {
  display: none !important;
}

/* --- copy trading: estado de "em breve" ---------------------------------
 * O truthpass já esvaziou nome, seguidores e retorno dos cards — eram de
 * pessoas reais operando na plataforma de origem. Sobra a foto de perfil,
 * que é da mesma pessoa, e um card com três traços, que não informa nada.
 *
 * Copy trading está no roteiro da OFFCODE, então a seção fica e mostra que
 * está por vir, em vez de mostrar uma tabela vazia.
 */
.trader-info .avatar,
.card:has(.roi-value) .mini-chart {
  display: none !important;
}
.card:has(.roi-value) {
  display: none !important;
}

.copy-trading-list::after,
.copy-trading .cards::after {
  content: "In preparation";
  display: block;
  padding: 28px 0;
  font-size: 14px;
  letter-spacing: 0.04em;
  color: #7e796e;
}

/* --- ações, índices, metais, commodities e câmbio -------------------------
 * A seção "Stocks" pertence à família TradFi (CFD), que a OFFCODE não oferece
 * e cujo item de menu já saiu. Deixar a vitrine na home enquanto o menu não
 * leva a lugar nenhum é pior que não ter a seção.
 */
[class*="stock"]:not([class*="stockholm"]),
[class*="tradfi"] {
  display: none !important;
}

/* --- vitrine de ações, metais e câmbio ---------------------------------
 * Cards de "Stocks / MVLL", "TradFi / SILVER(XAG)" na home. A classe é
 * .cat-card, sem "stock" no nome — o seletor anterior mirava o rótulo e
 * não pegava nada. São ativos da família CFD, que a OFFCODE não oferece e
 * cujo item de menu já saiu; deixar a vitrine é anunciar o que não existe.
 */
.category-cards,
.cat-card {
  display: none !important;
}

/* Faixa do torneio "1v1 Season" no menu lateral das páginas de negociação. */
.label-text:empty,
[class*="activity-label"]:has(.label-text:empty) {
  display: none !important;
}

/* Aba de mercados que ficou sem rótulo: o conteúdo era TradFi (CFD), que a
   OFFCODE não oferece. Sem texto, a aba viraria um alvo de clique invisível. */
.tab-item-label:empty {
  display: none !important;
}
[class*="tab-item"]:has(> .tab-item-label:empty) {
  display: none !important;
}

/* --- /CopyTrading: produto que ainda não abriu ---------------------------
 * O truthpass injeta um bloco [data-oc-soon] logo depois da abertura do
 * <main>. Todo irmão dele é o mercado vivo da plataforma de origem — vitrine
 * de traders, ranking, busca, cards com patrimônio sob gestão e índice de
 * Sharpe de contas reais. O bloco fica, os irmãos somem.
 */
.oc-soon-page {
  max-width: 640px;
  margin: 0 auto;
  padding: clamp(80px, 14vh, 180px) 24px 120px;
}
.oc-soon-page .oc-hero-title {
  font-size: clamp(30px, 4vw, 48px);
}
.oc-soon-page .oc-hero-sub {
  margin-bottom: 18px;
}
.oc-soon-page a {
  color: var(--offcode-brand, #f7931a);
  text-decoration: none;
}
.oc-soon-page a:hover {
  text-decoration: underline;
}

/* A /bot-trading recebe o mesmo tratamento: era a vitrine viva de bots da
   origem, com contagem de usuários, patrimônio investido e APY de backtest
   por par. O CodeBot da OFFCODE é real, então a página aponta pra ele. */

/* O <main> do espelho não impõe largura, então margin:auto não centrava e o
   texto encostava na borda esquerda da janela. */
main.page-trading-hub,
main.trading-bots-page {
  display: block;
  width: 100%;
}
.oc-soon-page {
  padding-left: max(24px, 5vw);
  padding-right: max(24px, 5vw);
}

/* O bloco de "em breve" ficava colado na borda esquerda: alguma das 451
   folhas do espelho vence a margem e o preenchimento por especificidade.
   O resto desta sobreposição já convive com isso à base de !important —
   é o preço de escrever por cima de um CSS que não é nosso. */
.oc-soon-page {
  max-width: 640px !important;
  margin-left: auto !important;
  margin-right: auto !important;
  padding: clamp(80px, 14vh, 180px) max(24px, 5vw) 120px !important;
  box-sizing: border-box !important;
}

/* --- linha da barra lateral sem rótulo -----------------------------------
 * O truthpass esvaziou "CFD Account" e "Wealth Account" na /assets: CFD é
 * produto regulado que a OFFCODE não oferece, e Wealth agrupa empréstimo e
 * dual investment, que moram em /earn (410). Sem o texto sobra o ícone
 * sozinho, que continua clicável e não diz nada. A linha inteira some.
 */
.asset-menu-item:has(> .asset-menu-item-title[data-oc-hide]) {
  display: none !important;
}

/* --- card de alegação sem alegação ---------------------------------------
 * Os três cards da direita na /assets diziam "$117.29M financial safeguard",
 * "100% backed by reserves" e "Audited by Top Security Firms". Nenhuma das
 * três é publicada pela OFFCODE, então o texto saiu — e o que restou foi
 * ícone, seta e vazio. Card sem conteúdo vira ruído com área de clique.
 */
/* As TRÊS eram alegação falsa — cofre de $117,29M, lastro de 100% em
 * reservas e auditoria por "top security firms". Não sobra um card
 * legítimo para justificar o módulo, então ele sai inteiro em vez de
 * virar uma coluna de ícones sem texto. */
.safety-education-module {
  display: none !important;
}

/* Faixa do topo: era "Complete advanced verification to win up to 500 USDT".
   Sem a promessa sobra uma tarja com uma seta solta. */
.top-banner:has(> *:empty),
[class*="notice-bar"]:has(> *:empty) {
  display: none !important;
}

/* Card "New Users Exclusive": o conteúdo era "Subscribe USDT for 50% APR".
   Sem ele fica um retângulo azul com um "View More" que não leva a nada. */
.newer-resource-item:has(> .item-detail > .item-title:empty) {
  display: none !important;
}

/* Faixa `access-tips` do topo: trazia "Complete advanced verification to win
   up to 500 USDT". Sem a promessa restou uma tarja de 40 px com uma seta
   solta, que ainda ocupa a primeira dobra inteira em largura. */
.access-tips-wrap,
.access-tips {
  display: none !important;
}

/* --- preço que não é ao vivo --------------------------------------------
 * `prices.js` marca TODA célula de preço como instantâneo e só tira a marca
 * de quem recebeu dado do feed. Aqui a marca vira coisa que se vê: o número
 * fica esmaecido, com um traço pontilhado embaixo e um "~" na frente.
 *
 * O "~" é o que carrega o significado sem depender de cor — quem não
 * distingue o esmaecido ainda lê que aquele número é aproximado. Preço de
 * captura com cara de cotação atual é o tipo de detalhe em que alguém confia
 * sem perceber que está confiando.
 */
[data-oc-snapshot] {
  opacity: 0.55;
  text-decoration: underline dotted currentColor 1px;
  text-underline-offset: 3px;
}
[data-oc-snapshot]::before {
  content: "~";
  opacity: 0.8;
  margin-right: 1px;
}

/* Aviso no rodapé. Precisa dos DOIS estados: quando nada está ao vivo e
   quando só parte está. No estado parcial, sem aviso, o leitor vê alguns
   números com "~" e outros sem, e não tem como saber o que a diferença
   significa — que é pior do que não marcar nada. */
/* 🔴 22/08/2026, decisão do dono: a barra sai.
 *
 * ⚠️ O QUE SE PERDE: a marca `~` continua em cada preço de instantâneo, e
 * agora sem legenda. Quem vê alguns números com `~` e outros sem não tem
 * como saber o que a diferença significa. A marca sozinha ainda diz "este
 * número é diferente"; deixa de dizer o quê.
 *
 * O conteúdo fica escrito aqui, comentado, para a próxima pessoa saber que
 * o mecanismo existe e por que a legenda sumiu — não é falta, é decisão.
 *
 * html[data-oc-precos="parcial"] body::after {
 *   content: "Live prices where available. Values marked ~ are from a captured snapshot.";
 * }
 * html[data-oc-precos="instantaneo"] body::after {
 *   content: "Prices shown are from a captured snapshot, not live quotes.";
 * }
 */
/* Sem `content`, um `::after` não gera caixa nenhuma — a regra abaixo já
 * estava inerte depois do corte acima. Fica comentada junto com ele para que
 * voltar a barra seja descomentar os dois blocos, não reescrever do zero.
 *
 * html[data-oc-precos] body::after {
 *   position: fixed;
 *   left: 0; right: 0; bottom: 0;
 *   z-index: 9999;
 *   padding: 7px 14px;
 *   font-size: 12px;
 *   letter-spacing: .02em;
 *   text-align: center;
 *   color: #0d0d0f;
 *   background: var(--offcode-brand, #f7931a);
 * }
 */

/* Linha de lista sem mercado correspondente: o catálogo da OFFCODE tem 21
   moedas com ícone e algumas listas do espelho têm mais linhas que isso. A
   excedente some em vez de ficar com o nome de uma moeda que não se negocia. */
[data-oc-nomarket] {
  display: none !important;
}

/* --- tela de negociação é instantâneo ------------------------------------
 * Livro de ofertas, profundidade, últimos negócios e preço de marca vieram
 * parados da captura. A marca aqui é de PÁGINA, não de célula: são sessenta e
 * poucas células, e sessenta tildes viram textura — o olho para de ler e a
 * marca deixa de marcar.
 */

/* A faixa é fixa e cobriria o cabeçalho do espelho; o corpo desce a altura
   dela. Sem isto o menu nasce escondido atrás do aviso. */

/* Dado congelado: esmaecido, sem tilde. O aviso do topo carrega o texto; aqui
   só o contraste reforça que aquele bloco não é cotação corrente. */
[data-oc-frozen] {
  opacity: 0.6;
}

/* Item do ticker de rodapé cujo par a OFFCODE não negocia. Mesmo marcador das
   listas: o nó fica, o item some, a fita não desmonta. */
.symbol-item-wrapper[data-oc-nomarket] {
  display: none !important;
}

/* --- modal de primeiro acesso ---------------------------------------------
 * A tela de spot abre com um diálogo "Welcome to spot trading" oferecendo um
 * guia de primeiros passos, ilustrado com os mascotes da plataforma de origem.
 * O truthpass esvaziou o texto, mas o diálogo continuou abrindo — sobrando a
 * arte deles em tela cheia e um botão sem rótulo.
 *
 * Esvaziar texto não fecha caixa: elemento que aparece por conta própria
 * precisa ser desligado, não só calado.
 */
.b-dialog-wrapper,
.b-dialog-mask {
  display: none !important;
}

/* --- os avisos em cada idioma -------------------------------------------
 * Estas duas frases nascem em `content:` do CSS, não no HTML — então o
 * catálogo de tradução não as alcança, e elas ficaram em inglês nas sete
 * árvores enquanto todo o resto do cromo já estava traduzido.
 *
 * 🔑 Texto gerado por CSS é invisível para qualquer extrator que leia o HTML.
 * Ou se traduz aqui, por seletor de idioma, ou se move o texto para um nó.
 * A escolha foi aqui: mover exigiria injetar elemento em 490 páginas.
 *
 * O `<html lang>` já é carimbado por idioma pelo i18n_build, então `:lang()`
 * resolve sozinho.
 */
html[lang="pt"][data-oc-precos="parcial"] body::after {
  content: "Preços ao vivo quando disponíveis. Valores marcados com ~ vêm de uma captura.";
}
html[lang="pt"][data-oc-precos="instantaneo"] body::after {
  content: "Os preços exibidos vêm de uma captura; não são cotação ao vivo.";
}
html[lang="es"][data-oc-precos="parcial"] body::after {
  content: "Precios en vivo cuando están disponibles. Los valores marcados con ~ vienen de una captura.";
}
html[lang="es"][data-oc-precos="instantaneo"] body::after {
  content: "Los precios mostrados vienen de una captura; no son cotización en vivo.";
}
html[lang="ru"][data-oc-precos="parcial"] body::after {
  content: "Живые цены там, где доступны. Значения с ~ взяты из снимка.";
}
html[lang="ru"][data-oc-precos="instantaneo"] body::after {
  content: "Показанные цены взяты из снимка и не являются живой котировкой.";
}
html[lang="id"][data-oc-precos="parcial"] body::after {
  content: "Harga langsung bila tersedia. Nilai bertanda ~ berasal dari tangkapan.";
}
html[lang="id"][data-oc-precos="instantaneo"] body::after {
  content: "Harga yang ditampilkan berasal dari tangkapan, bukan kuotasi langsung.";
}
html[lang="hi"][data-oc-precos="parcial"] body::after {
  content: "जहाँ उपलब्ध है वहाँ लाइव मूल्य। ~ चिह्नित मान एक कैप्चर से हैं।";
}
html[lang="hi"][data-oc-precos="instantaneo"] body::after {
  content: "दिखाए गए मूल्य एक कैप्चर से हैं, लाइव भाव नहीं।";
}
html[lang="zh"][data-oc-precos="parcial"] body::after {
  content: "有数据时显示实时价格；标有 ~ 的数值来自快照。";
}
html[lang="zh"][data-oc-precos="instantaneo"] body::after {
  content: "所示价格来自快照，并非实时报价。";
}

/* "View details" apontava para o regulamento da campanha que já saiu. */
a[class*="view-detail"],
.banner-detail,
[class*="banner"] a[href$="/en/"] {
  display: none !important;
}

/* --- páginas jurídicas: a versão que vincula é a inglesa -----------------
 * Termos de uso, política de privacidade, divulgação de risco e compliance
 * ficam em inglês nas sete árvores. Não é lacuna de tradução: é decisão.
 *
 * Traduzir contrato sem revisão jurídica muda o que a pessoa aceita. Uma
 * cláusula de arbitragem, um limite de responsabilidade ou um trecho sobre
 * dado pessoal traduzido com nuance errada não é erro de estilo — é outro
 * contrato. É o que a maioria das corretoras faz: uma versão vinculante,
 * traduções quando houver revisão de advogado no idioma.
 *
 * O aviso existe para o leitor saber POR QUE aquela página está em inglês.
 * Página jurídica em outro idioma sem explicação parece descuido, e descuido
 * numa página de termos convida a pessoa a não lê-la.
 */
html:not([lang="en"])
  body:has(.legal-body, [class*="terms"], [class*="privacy"])
  .page-content::before,
html:not([lang="en"]) main:has([class*="legal"])::before {
  content: "This page is shown in English. The English version is the binding one; translations follow legal review in each language.";
  display: block;
  margin: 0 0 24px;
  padding: 12px 16px;
  border-left: 2px solid var(--offcode-brand, #f7931a);
  background: rgba(247, 147, 26, 0.08);
  font-size: 13px;
  line-height: 1.5;
  color: #c8c4b8;
}
html[lang="pt"] main:has([class*="legal"])::before {
  content: "Esta página está em inglês. A versão em inglês é a que vincula; as traduções saem após revisão jurídica em cada idioma.";
}
html[lang="es"] main:has([class*="legal"])::before {
  content: "Esta página está en inglés. La versión en inglés es la vinculante; las traducciones salen tras revisión jurídica en cada idioma.";
}
html[lang="ru"] main:has([class*="legal"])::before {
  content: "Эта страница на английском. Обязательной является английская версия; переводы выходят после юридической проверки на каждом языке.";
}
html[lang="id"] main:has([class*="legal"])::before {
  content: "Halaman ini dalam bahasa Inggris. Versi Inggris yang mengikat; terjemahan menyusul setelah tinjauan hukum di tiap bahasa.";
}
html[lang="hi"] main:has([class*="legal"])::before {
  content: "यह पृष्ठ अंग्रेज़ी में है। बाध्यकारी संस्करण अंग्रेज़ी है; अनुवाद हर भाषा में कानूनी समीक्षा के बाद आएँगे。";
}
html[lang="zh"] main:has([class*="legal"])::before {
  content: "本页面为英文。以英文版本为准；各语言译本将在法律审核后发布。";
}

/* --- vídeo de fundo do herói --------------------------------------------
 * A dobra da origem é vídeo full-bleed com o texto escrito por cima. O
 * espelho herdou a estrutura, mas os slides eram banner de campanha e saíram.
 * Aqui entra o vídeo da OFFCODE no mesmo papel.
 *
 * `object-fit: cover` porque o vídeo é 16:9 e a dobra é mais larga que alta em
 * telas grandes e mais alta que larga no celular: cortar a sobra é o que faz
 * o quadro preencher em qualquer proporção. Diferente da maquete de celular,
 * onde cortar destruía o enquadramento — aqui o vídeo É o fundo, e sobra
 * pensada para ser cortada é o que um fundo precisa ter.
 *
 * `z-index` 0 no vídeo, 1 no véu, 2 no texto. O véu não é enfeite: texto
 * branco sobre vídeo em movimento fica ilegível nos quadros claros, e a
 * legibilidade não pode depender de qual segundo do filme está passando.
 */
.hero-banner {
  position: relative;
  overflow: hidden;
}

.oc-hero-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
  pointer-events: none;
}

.oc-hero-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* Mais escuro à esquerda, onde o texto vive; quase limpo à direita, para o
     vídeo respirar.
   *
   * 🔴 A queda começava em 34% e chegava a .30 em 62%. A coluna de texto vai
   * de 5% a 58% da largura — o fim de cada linha caía justamente na parte
   * mais clara do véu. Medido em 24/08/2026 sobre dez instantes do filme: a
   * ficha (19px, #cfcabd) fechava em 3,62, abaixo do piso de 4,5. Título
   * (4,53) e linha de destaque (7,84) passavam, porque são texto grande.
   *
   * 🔑 A queda foi ADIADA, não aprofundada: o platô vai até 40% e o joelho
   * para 62%, mas de 80% em diante o véu segue quase o que era (.18 contra
   * .12). O sujeito do filme mora à direita e escurecê-lo resolveria o
   * contraste apagando a única razão de haver um filme ali.
   *
   * 🔑 .46 em 62% e não .60: medido, .46 fecha em 5,49 e .60 em 7,18. O
   * segundo passa mais folgado e custa o vídeo — a folga que interessa é a
   * que sobra depois do piso, não a maior de todas. */
  background:
    linear-gradient(
      90deg,
      rgba(6, 6, 8, 0.88) 0%,
      rgba(6, 6, 8, 0.76) 40%,
      rgba(6, 6, 8, 0.46) 62%,
      rgba(6, 6, 8, 0.18) 80%,
      rgba(6, 6, 8, 0.12) 100%
    ),
    linear-gradient(
      180deg,
      rgba(6, 6, 8, 0.55) 0%,
      rgba(6, 6, 8, 0) 22%,
      rgba(6, 6, 8, 0) 72%,
      rgba(6, 6, 8, 0.65) 100%
    );
}

.oc-hero {
  z-index: 2;
}

/* No celular a coluna de texto é o centro, então o véu fecha por igual.
 *
 * 🔴 O ponto de 45% valia .58 e a copy nova caiu exatamente ali. Medido em
 * 24/08/2026, compondo o véu sobre OITO instantes do filme e pegando o pixel
 * mais claro de cada um sob a faixa do texto: a ficha (15px, #cfcabd) fechava
 * em 4,16 — abaixo do piso de 4,5 do texto normal. A linha de destaque
 * passava (7,03), porque é maior, mais branca e mais pesada.
 *
 * 🔑 Quem sobe é o VÉU, não a cor do texto: subir a cor até passar exigiria
 * #e8e4da e aí a ficha empataria com a linha de destaque — o degrau que o
 * dono pediu sumiria para consertar contraste. O véu resolve sem tocar na
 * hierarquia.
 *
 * 🔑 .70 e não .62: medido, .62 fecha em 4,52 e .70 em 5,88. Oito quadros são
 * uma amostra, não o filme inteiro — encostar no piso com dois centésimos de
 * folga é apostar que nenhum quadro entre as amostras é mais claro. */
@media (max-width: 780px) {
  .oc-hero-scrim {
    background: linear-gradient(
      180deg,
      rgba(6, 6, 8, 0.74) 0%,
      rgba(6, 6, 8, 0.7) 45%,
      rgba(6, 6, 8, 0.86) 100%
    );
  }
}

/* Quem pediu menos movimento não recebe um filme rodando em laço na dobra. */
@media (prefers-reduced-motion: reduce) {
  .oc-hero-bg {
    display: none;
  }
  .hero-banner {
    background: #08080a;
  }
}

/* Os cinco filmes do herói ficam empilhados; só o `.is-active` aparece. A
   transição é de opacidade e não de display: `display:none` descarrega o
   quadro e a troca pisca preto entre um filme e o outro. */
.oc-hero-bg {
  opacity: 0;
  transition: opacity 0.7s ease;
}
.oc-hero-bg.is-active {
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .oc-hero-bg {
    transition: none;
  }
}

/* --- headlines da home: quebra do documento ------------------------------
 * As quatro headlines da narrativa vêm escritas em linhas, e as linhas são
 * o argumento: duas para o que o mercado fez e duas para o que a OFFCODE
 * faz; "TRADE IT / AUTOMATE IT / DISTRIBUTE IT / DIRECT IT" é uma escada.
 * Entregue à quebra automática, o texto junta as duas metades na mesma
 * linha e o paralelismo some — a frase continua lá e o argumento não.
 *
 * 🔑 `pre-line` honra o `\n` que vem no próprio texto e AINDA requebra a
 * linha longa quando a coluna aperta. `<br>` faria só a primeira metade e
 * ainda seria elemento novo no DOM.
 */
.deposit-section .title,
.ai-section .title,
.security-trust .title,
.register-cta .title {
  white-space: pre-line;
}

/* --- frase de fechamento --------------------------------------------------
 * `.highlight` era o realce do VALOR do brinde ("7,800 USDT") e vem verde da
 * origem. Verde é cor de ganho: numa plataforma financeira, uma frase verde
 * ao lado de um campo de cadastro lê como número de lucro, não como remate
 * editorial. A frase entra no tom do corpo e quem grita é a headline. */
/* `[dir][dir]` porque o realce da origem vem como `[dir] .highlight[data-v]`
   — mesma especificidade e mais tarde na cascata; sem isso, ganha o verde. */
[dir][dir] .register-cta .hint-text,
[dir][dir] .register-cta .hint-text .highlight {
  color: #b9b5aa;
  font-weight: 400;
}
[dir][dir] .register-cta .hint-text {
  font-size: 16px;
  letter-spacing: 0;
}

/* --- headlines no telefone -----------------------------------------------
 * As quebras do documento só entregam o paralelismo se a linha COUBER. Num
 * viewport de 390px sobram 350px de coluna e, no piso de 34px do clamp, três
 * das quatro linhas do herói passam de 390px — voltam a requebrar e a
 * headline vira sete linhas irregulares, que é o defeito que as quebras
 * existiam para resolver.
 *
 * Medido com `canvas.measureText` na própria fonte da página:
 *   "OFFCODE DECENTRALIZES"  438px @34px  →  cabe em 350px a partir de ~27px
 *   "CREATES THE VOLUME."    358px @32px  →  cabe a partir de ~31px
 *   "IT CAN NEVER EXPOSE."   354px @32px  →  cabe a partir de ~31px
 *
 * Os valores abaixo levam folga sobre esses limites: fonte carregada com
 * métrica ligeiramente diferente não pode desmanchar a quebra.
 */
@media (max-width: 480px) {
  /* 🔑 A medida acima vale para as headlines de TRÊS a QUATRO linhas, que são
   * as das seções. A da dobra virou uma linha de sete caracteres em
   * 24/08/2026 e não disputa mais os 350px de coluna com ninguém: a 49px
   * (390px de tela) ela ocupa ~211px. Manter os 30px ali seria aplicar a
   * ela um limite que a frase dela não tem mais.
   *
   * 🔴 Aquele teto (`clamp(40px, 12.5vw, 66px)`) valia enquanto a frase era
   * `NO KYC.` — sete caracteres. A de 29/08/2026 tem duas linhas de vinte e
   * um, e medido num telefone de 440px de largura o corpo saía a 55px:
   * `TRANSPARENCY` sozinha mede 430px e a coluna tem 431. A palavra encostava
   * na borda e a tela CORTAVA o fim dela — a tese da página chegava truncada.
   *
   * 🔑 O corpo novo sai da mesma medida que o dono aprovou na captura dele: a
   * linha mais longa ocupando ~82% da coluna, não a coluna inteira. A 6.8vw
   * isso dá 26,5px numa tela de 390 e 30px numa de 440 — inglês em 322px e
   * 363px, com folga em ambas. Espanhol e indonésio seguem quebrando em duas
   * linhas (`LA TRANSPARENCIA ES NUESTRA.` mede 486px a 30px), que é o que o
   * `pre-line` existe para fazer; o que não pode é cortar. */
  .oc-hero-title {
    font-size: clamp(24px, 6.8vw, 32px);
  }
  /* A ficha usa a coluna inteira do telefone; os 40em do desktop passariam
     de 600px numa tela de 390 e não limitariam nada. */
  .hero-banner .oc-hero-sub {
    max-width: none;
    letter-spacing: 0.04em;
  }
  /* A oferta segue sendo o degrau mais alto depois da tese, mas em 350px de
     coluna 24px dariam quatro linhas — a evidência viraria bloco. */
  .hero-banner .oc-hero-note {
    max-width: none;
    font-size: clamp(17px, 4.9vw, 21px);
    letter-spacing: 0.02em;
  }
  .deposit-section .title,
  .ai-section .title,
  .security-trust .title,
  .register-cta .title {
    font-size: clamp(22px, 6.6vw, 30px);
  }
}

/* --- herói em janela baixa -----------------------------------------------
 * A faixa entre a navbar e o botão é o orçamento vertical do herói, e ela
 * encolhe com a janela: 393px numa tela de 900, 293px numa de 800. A copy
 * nova ocupa ~430px no corpo cheio.
 *
 * ⚠️ A tela de 800 já era apertada ANTES: medido em produção, o bloco antigo
 * (281px) fechava com -3px de folga ali. A copy nova não criou o aperto,
 * chegou nele com o dobro de texto.
 *
 * Compacta na ordem de prioridade do documento — headline, eyebrow,
 * supporting, proof line — então quem sai primeiro é a proof line, que é a
 * quarta. A headline nunca sai e nunca requebra: é a tese da página.
 */
@media (min-width: 781px) and (max-height: 820px) {
  /* 🔑 O corpo do título já cede sozinho aqui — o termo `13vh` do clamp base
   * entrega 104px numa janela de 800 e 91px numa de 700. O que esta regra
   * ainda precisa fazer é fechar o espaço ENTRE os dois registros. */
  .oc-hero-title {
    margin-bottom: 18px;
  }
  .oc-hero-eyebrow {
    margin-bottom: 12px;
  }
  /* 🔑 Escopado igual à regra base: sem `.hero-banner` esta linha perderia
   * para ela por especificidade (0,1,0 contra 0,2,0) e a compactação de
   * janela baixa não aconteceria — a media query passaria a existir sem
   * efeito nenhum, em silêncio. */
  .hero-banner .oc-hero-title {
    margin-bottom: 18px;
  }
  .hero-banner .oc-hero-sub {
    max-width: none;
    font-size: clamp(14px, 1.2vw, 16px);
    line-height: 1.45;
  }
  /* 🔴 Esta regra dizia `display: none` para a proof line, e estava certa
   * enquanto o slot carregava a quarta prioridade — uma linha de selos que
   * o parágrafo acima já repetia. Desde 24/08/2026 ele carrega a OFERTA, que
   * é o segundo motivo da página existir. Esconder a oferta em toda janela
   * abaixo de 820px de altura seria apagar metade da copy em metade dos
   * laptops, sem nada no lugar. Ela COMPACTA, não some. */
  .hero-banner .oc-hero-note {
    margin-top: 12px;
    font-size: clamp(15px, 1.4vw, 20px);
    line-height: 1.3;
    max-width: none;
  }
}

/* ══ Copy trading ═══════════════════════════════════════════════════════
 *
 * A vitrine da /CopyTrading não tem mais card escrito no HTML: o
 * `copytrading.js` clona um `<template>` por estratégia que a API devolver.
 * O estado vazio é parte do produto — sem trader cadastrado a lista diz que
 * não há, em vez dos doze cards de contas reais da origem que estavam ali.
 *
 * 🔴 TODA regra daqui é escrita com DOIS níveis de seletor de propósito.
 * A folha da origem traz um reset `[dir] *` — especificidade (0,1,0), igual à
 * de uma classe — e vem DEPOIS na cascata. Com seletor de classe simples ele
 * empata e ganha por ordem: `margin-bottom: 12px` virava `0px` sem erro
 * nenhum, e o diálogo saiu com todos os rótulos colados nos campos. O texto
 * estava lá, do tamanho certo, na posição errada.
 *
 * 🔑 Neste espelho, regra nova compete com um reset alheio. Um nível a mais
 * de seletor é o que faz a regra existir de fato.
 */
.oc-copy-lista {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 16px;
  width: 100%;
}

.oc-copy-lista .oc-copy-vazio,
.oc-copy-vazio {
  grid-column: 1 / -1;
  padding: 56px 24px;
  text-align: center;
  border: 1px dashed rgba(185, 181, 170, 0.28);
  border-radius: 14px;
}
.oc-copy-vazio .oc-copy-vazio-t {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  color: #f5f3ee;
}
.oc-copy-vazio .oc-copy-vazio-s {
  margin: 6px 0 0;
  font-size: 13px;
  color: #7e796e;
}

/* Contador do herói. O `2.000` da origem virou o número que a API devolve; a
 * cor e o tamanho vinham de uma regra com o atributo de escopo do Vue, que o
 * markup reescrito não carrega — sem isto o texto sai PRETO sobre preto. */
.top-section-wrap .stats {
  display: flex;
  align-items: baseline;
  gap: 8px;
  color: #b9b5aa;
  font-size: 14px;
}
.top-section-wrap .stats em {
  font-style: normal;
  font-size: 40px;
  font-weight: 700;
  line-height: 1.1;
  color: #f5f3ee;
}

/* "Seja um trader": era um `<div>` clicável na origem — sem foco, sem Enter,
 * invisível para leitor de tela. Virou `<button>`, e o reset da origem tira a
 * aparência de botão do navegador, então ela é reposta aqui. */
.section-header button.apply-trader-entry .oc-bt-rot {
  gap: 6px;
}

/* ── diálogo ─────────────────────────────────────────────────────────── */
.oc-copy-modal {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(0, 0, 0, 0.62);
}
.oc-copy-modal .oc-copy-modal-caixa {
  width: 100%;
  max-width: 420px;
  padding: 24px;
  border-radius: 16px;
  background: #16161a;
  border: 1px solid rgba(185, 181, 170, 0.16);
  color: #f5f3ee;
  max-height: 90vh;
  overflow-y: auto;
}
.oc-copy-modal .oc-copy-modal-t {
  margin: 0 0 18px;
  font-size: 17px;
  font-weight: 600;
  line-height: 1.3;
}
.oc-copy-modal .oc-copy-termo {
  margin: 0 0 16px;
  font-size: 13px;
  line-height: 1.6;
  color: #b9b5aa;
}
.oc-copy-modal .oc-copy-aceite {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  font-size: 13px;
  line-height: 1.4;
  cursor: pointer;
}
.oc-copy-modal .oc-copy-aceite input {
  margin: 2px 0 0;
  flex: none;
}

.oc-copy-modal .oc-copy-campo {
  display: block;
  margin: 0 0 16px;
}
.oc-copy-modal .oc-copy-campo span {
  display: block;
  margin: 0 0 6px;
  font-size: 12px;
  line-height: 1.3;
  color: #b9b5aa;
}
.oc-copy-modal .oc-copy-campo input,
.oc-copy-modal .oc-copy-campo textarea {
  display: block;
  width: 100%;
  margin: 0;
  padding: 10px 12px;
  border-radius: 9px;
  border: 1px solid rgba(185, 181, 170, 0.22);
  background: #0d0d0f;
  color: #f5f3ee;
  font: inherit;
  line-height: 1.4;
  box-sizing: border-box;
}
.oc-copy-modal .oc-copy-campo textarea {
  resize: vertical;
  min-height: 68px;
}
.oc-copy-modal .oc-copy-campo input:focus,
.oc-copy-modal .oc-copy-campo textarea:focus {
  outline: 2px solid var(--offcode-brand, #f7931a);
  outline-offset: 1px;
}
.oc-copy-modal .oc-copy-ajuda {
  margin: -10px 0 16px;
  font-size: 11px;
  line-height: 1.4;
  color: #7e796e;
}

/* ── diálogos do vault: campos curtos lado a lado, unidade DENTRO do campo,
   fatos em pastilha e o aviso de saldo antes do clique ────────────────── */
.oc-copy-modal .oc-cv-sub {
  margin: -12px 0 18px;
  font-size: 12.5px;
  line-height: 1.5;
  color: #b9b5aa;
}
/* Três valores de 2-3 dígitos não merecem três caixas da largura do nome. */
.oc-copy-modal .oc-cv-grade {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin: 0 0 16px;
}
.oc-copy-modal .oc-cv-grade .oc-copy-campo { margin: 0; }
/* A unidade fica ancorada no campo, não perdida no rótulo. */
.oc-copy-modal .oc-cv-uni { position: relative; }
.oc-copy-modal .oc-cv-uni input { padding-right: 46px; }
.oc-copy-modal .oc-cv-uni i {
  position: absolute;
  right: 12px;
  bottom: 11px;
  font-style: normal;
  font-size: 12px;
  color: #7e796e;
  pointer-events: none;
}
.oc-copy-modal .oc-cv-chips { display: flex; gap: 6px; margin: 8px 0 0; flex-wrap: wrap; }
.oc-copy-modal .oc-cv-chip {
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid rgba(185, 181, 170, 0.22);
  background: #0d0d0f;
  color: #b9b5aa;
  font: inherit;
  font-size: 11.5px;
  line-height: 1.4;
  cursor: pointer;
}
.oc-copy-modal .oc-cv-chip.oc-on { border-color: var(--offcode-brand, #f7931a); color: #f5f3ee; }
/* Rótulo à esquerda, número à direita: dá para ler de relance. */
.oc-copy-modal .oc-cv-linha {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin: 8px 0 0;
  font-size: 12px;
  line-height: 1.45;
  color: #7e796e;
}
.oc-copy-modal .oc-cv-linha b { color: #f5f3ee; font-weight: 600; }
.oc-copy-modal .oc-cv-linha button {
  margin-left: 8px;
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-size: 12px;
  color: var(--offcode-brand, #f7931a);
  cursor: pointer;
}
.oc-copy-modal .oc-cv-pills { display: flex; gap: 6px; margin: 14px 0 0; flex-wrap: wrap; }
.oc-copy-modal .oc-cv-pill {
  padding: 4px 10px;
  border-radius: 999px;
  background: #0d0d0f;
  border: 1px solid rgba(185, 181, 170, 0.16);
  font-size: 11.5px;
  line-height: 1.4;
  color: #b9b5aa;
}
/* Saldo abaixo do mínimo: dizer ANTES, com a saída ao lado — em vez de deixar
   a pessoa digitar, clicar e levar erro do servidor. */
.oc-copy-modal .oc-cv-aviso {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 14px 0 0;
  padding: 10px 12px;
  border-radius: 10px;
  background: rgba(247, 147, 26, 0.08);
  border: 1px solid rgba(247, 147, 26, 0.28);
  font-size: 12px;
  line-height: 1.45;
  color: #f5f3ee;
}
.oc-copy-modal .oc-cv-aviso button {
  flex: none;
  border: 0;
  background: var(--offcode-brand, #f7931a);
  color: #0a0a0a;
  font: inherit;
  font-size: 11.5px;
  font-weight: 700;
  line-height: 1.2;
  padding: 7px 12px;
  border-radius: 999px;
  cursor: pointer;
}
.oc-copy-modal .oc-copy-aceite { margin: 16px 0 0; }
@media (max-width: 520px) {
  .oc-copy-modal .oc-cv-grade { grid-template-columns: 1fr; }
  .oc-copy-modal .oc-cv-aviso { flex-direction: column; align-items: stretch; }
}
.oc-copy-modal .oc-copy-modal-e {
  margin: 12px 0 0;
  font-size: 12.5px;
  line-height: 1.45;
  color: #ff6b6b;
}
.oc-copy-modal .oc-copy-modal-b {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  margin: 20px 0 0;
}
.oc-copy-modal .oc-copy-modal-b button {
  padding: 10px 18px;
  border-radius: 999px;
  font: inherit;
  line-height: 1.2;
  cursor: pointer;
}
.oc-copy-modal .oc-copy-cancelar {
  background: none;
  border: 1px solid rgba(185, 181, 170, 0.28);
  color: #b9b5aa;
}
.oc-copy-modal .oc-copy-ok {
  border: 0;
  background: var(--offcode-brand, #f7931a);
  color: #0d0d0f;
  font-weight: 600;
}
.oc-copy-modal .oc-copy-ok[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ── FAQ ─────────────────────────────────────────────────────────────────
 * O da captura descrevia outro produto e o primeiro item prometia dinheiro
 * ("subsidy up to the face value of the voucher"). Virou `<details>`, que abre
 * e fecha sem JS — o acordeão da origem dependia do runtime Vue que a captura
 * não trouxe. */
.oc-faq .oc-faq-item {
  border-bottom: 1px solid rgba(185, 181, 170, 0.14);
  padding: 16px 4px;
}
.oc-faq .oc-faq-item summary {
  cursor: pointer;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.4;
  color: #f5f3ee;
  list-style: none;
}
.oc-faq .oc-faq-item summary::-webkit-details-marker {
  display: none;
}
.oc-faq .oc-faq-item summary::after {
  content: "+";
  float: right;
  color: #7e796e;
  font-weight: 400;
}
.oc-faq .oc-faq-item[open] summary::after {
  content: "−";
}
.oc-faq .oc-faq-item p {
  margin: 10px 0 0;
  font-size: 13.5px;
  line-height: 1.6;
  color: #b9b5aa;
}

/* Carrossel "Novos traders": mesma grade da lista, sem swiper. */
/* Ver `.oc-mk-abas` em `mercados.css`: `overflow-x` sozinho faz do elemento um
   scroller vertical de curso zero, e o dedo que toca aqui deixa de rolar a
   página. */
.oc-novos {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  overflow-y: hidden;
  touch-action: pan-x pan-y;
  padding-bottom: 4px;
}
.oc-novos > * {
  flex: 0 0 auto;
}

/* Convite dentro do estado vazio. O botão do cabeçalho é discreto de
 * propósito — foi desenhado para conviver com uma lista cheia. Com zero
 * trader, a tela inteira é o convite. */
/* 30/08/2026: é o botão padrão do site (`botao.css`); só a margem é daqui. */
.oc-copy-vazio .oc-copy-vazio-cta {
  margin: 20px 0 0;
}

/* Botões da CAPTURA vestidos pelo `chanfra()` do copytrading.js: "My data",
 * o "Copy"/"Add margin" dos cartões, "Become a trader" e as abas do ranking.
 * A moldura que a origem dava a cada um sai — o corte é dos pseudo-elementos,
 * e um fundo herdado apareceria ATRÁS dele como um retângulo. */
[dir] .oc-bt.bx-btn-primary,
[dir] .oc-bt.follow-btn,
[dir] .oc-bt.apply-trader-entry,
[dir] .list-tab .tab-item.oc-bt {
  height: var(--h) !important;
  min-height: 0;
  min-width: 0;
  margin: 0;
  padding: 0 !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: transparent !important;
  box-shadow: none !important;
  color: var(--bt-tinta) !important;
  line-height: 1;
}
/* A aba ATIVA da origem traz `border: 1px solid #fff; border-radius: 100px`
 * e pinta o `.label` de branco por uma regra mais longa que a nossa —
 * medido: (0,5,0) contra (0,4,0). O `!important` é o jeito de vencer uma
 * folha que não é nossa sem copiar o seletor dela. */
[dir] .list-tab .tab-item.oc-bt,
[dir] .list-tab .tab-item.oc-bt.active {
  border: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
}
[dir] .list-tab .tab-item.oc-bt .label,
[dir] .list-tab .tab-item.oc-bt.active .label,
[dir] .oc-bt.apply-trader-entry .text {
  color: inherit !important;
  font-size: inherit;
  font-weight: 600;
}
[dir] .list-tab .tab-list {
  display: flex;
  gap: 8px;
}

/* Ausência de dado não tem cor.
 *
 * 🔴 `.profit-percent` e `.profit` já são VERDES na folha da origem, mesmo sem
 * `up`. O traço de "ainda não operou" saía com a cor de lucro — num trader com
 * zero operações fechadas, um traço verde lê como ganho. O `!important` é
 * necessário: as regras de cor da origem também o usam. */
.trader-card .profit-percent.oc-sem-dado,
.new-trader-item .profit.oc-sem-dado,
.oc-sem-dado {
  color: #7e796e !important;
}

/* O item de menu que era um BANNER da origem (23/08/2026).
 *
 * `<a class="nav-item"><div class="nav-img">` — sem texto, sem rotulo, so uma
 * arte promocional vinda de `social_feed_pictures` do dominio da BingX. A
 * limpeza de pixel trocou a arte por um GIF de 1x1 (70 bytes), e o navegador
 * o esticou para 32x32: virou um quadrado azul solido entre "Mais" e o resto
 * do menu, em 791 paginas, levando para a home.
 *
 * 🔑 Neutralizar o pixel resolve a MARCA, nao o espaco que ele ocupava. Um
 * item de menu sem texto nao tem como ser lido nem clicado com intencao —
 * o certo e nao existir.
 *
 * Escondido por CSS de proposito: e aditivo e reversivel. Um passe que
 * apagasse o `<a>` das 791 paginas nao teria segunda chance.
 */
.nav-item:has(> .nav-img) {
  display: none !important;
}

/* ── Reserva do par de sinal (24/08/2026) ────────────────────────────
 *
 * O par de alta e baixa NÃO nasce aqui: cada página da captura traz um
 * `<style>` de ~54 KB no `<head>` com o tema da origem, e é lá que
 * `--kline-up`/`--kline-down` são definidas — em QUATRO combinações (tema
 * claro/escuro × a preferência `kline_color_type`, que deixa o usuário pôr
 * VERMELHO como alta, convenção de boa parte da Ásia). O `_tools/cor_sinal.py`
 * troca os valores nas quatro.
 *
 * 🔴 Eu quase impus um `:root { --kline-up: … }` daqui achando que as
 * variáveis nunca tinham sido definidas — a leitura em runtime mostrou
 * `#1CC166` vindo de `:root[theme="dark"][kline_color_type="…"]`, que pontua
 * (0,3,0) e ganha de `:root` (0,1,0) com folga.
 *
 * 🔑 Sobrescrever teria sido pior que não funcionar: a preferência de
 * inversão continuaria no seletor da interface e deixaria de mudar qualquer
 * coisa — controle que parece funcionar e não faz nada.
 *
 * O que fica aqui é RESERVA, para página do espelho que não carregue o bloco
 * de tema. Especificidade baixa de propósito: onde o tema existe, é ele que
 * manda. */
:root {
  --kline-up: #00e08f;
  --kline-down: #ff4d4f;
}
html.light,
html[theme="light"] {
  --kline-up: #008555;
  --kline-down: #d92d3f;
}

/* ── Convite de cadastro só para quem não tem conta (24/08/2026) ──────
 *
 * 🔴 A dobra da home oferecia `Sign Up` num botão branco e o rodapé trazia a
 * seção `register-cta` inteira — com formulário de e-mail — para uma conta
 * LOGADA. Medido em produção: `/api/auth/me` respondendo 200 e os dois CTAs
 * visíveis, com `Depositar` e o menu de conta desenhados na mesma tela.
 *
 * 🔑 A tela não pode se contradizer: a barra afirmando "você está dentro" e a
 * dobra oferecendo entrada. Numa corretora o custo não é estético — o botão
 * leva quem já podia negociar para uma tela de cadastro.
 *
 * Quem carimba `data-oc-sessao` na raiz é o `barra-conta.js`, que já resolve
 * `/auth/me` (ver `marcaSessao`). Sem resposta o atributo não existe e o
 * convite continua visível — o lado certo para errar.
 *
 * Aqui não precisa de `[dir]`: `html[data-oc-sessao="on"] .hero-banner
 * .cta-actions` já pontua (0,3,1) e passa longe do reset `[dir] div` (0,1,1).
 */
html[data-oc-sessao="on"] .hero-banner .cta-actions {
  display: none !important;
}

/* A seção inteira sai, não só o botão: o que resta dela seria um título
 * chamando para criar conta e um campo de e-mail sem destino. */
html[data-oc-sessao="on"] .register-cta {
  display: none !important;
}

/* O item de menu do rodapé, carimbado pelo `barra-conta.js` (ver
 * `cadastroNoRodape`) — ele era o único link morto da página e agora tem
 * destino, mas só faz sentido para quem ainda não tem conta.
 *
 * ⚠️ Medido em produção 03/09: este alvo NÃO EXISTE MAIS. O rodapé único de
 * 01/09 (`poe_rodape.py`) substituiu o `.footer-top` da captura, e com ele
 * foi o `a[href="javascript:;"]` que o `cadastroNoRodape` procura — zero
 * ocorrências na home e no cadastro. A função virou passe morto e esta regra
 * ficou sem alvo. Fica registrado em vez de removido porque tirar a função
 * do `barra-conta.js` é mudança à parte; o que não podia continuar é o
 * comentário afirmando um elemento que já não está na página.
 *
 * 🔴 `a[...]`, e não `[...]` solto: `data-oc-cadastro` tem DOIS donos. Este
 * link do rodapé e o `<form>` inteiro da página `/signup`, carimbado pelo
 * `_tools/poe_cadastro.py`. O seletor genérico derrubava os dois, e o efeito
 * só aparecia para quem abrisse `/signup` COM SESSÃO: o formulário piscava e
 * sumia, deixando a página com a arte de marketing e mais nada. Medido em
 * produção 03/09 — o campo de convite chegava preenchido com o código do
 * indicador, invisível dentro de um formulário com `display:none`.
 *
 * 🔑 A lição é velha e voltou: marcador compartilhado morde nos dois
 * sentidos. Antes de reusar um `data-*` que já existe, `grep` no nome — quem
 * mais o carimba decide o alcance da sua regra, não a sua intenção. */
html[data-oc-sessao="on"] a[data-oc-cadastro] {
  display: none !important;
}

/* Na página de cadastro esconder continua certo — quem já está dentro não
 * recebe oferta de entrar —, mas a tela precisa de destino: o cartão sobe no
 * mesmo passe que derruba o formulário, então não existe quadro com os dois
 * nem quadro vazio. Quem monta o cartão é o `_local/cadastrar.js`. */
html[data-oc-sessao="on"] form[data-oc-cadastro] {
  display: none !important;
}
[data-oc-ja-dentro] {
  display: none !important;
}
html[data-oc-sessao="on"] [data-oc-ja-dentro] {
  display: flex !important;
}

/* ── Rodízio da linha de baixo: ENCERRADO (28/08/2026) ────────────────
 *
 * O palco, as duas mensagens e a transição saíram junto com o rodízio: a
 * frase da identidade virou o título da dobra e a oferta de indicação desceu
 * para a seção de REDE. O motor está fora do `_local/replica.js` e o markup
 * fora do `_tools/home_narrativa.py`.
 *
 * 🔑 Regra de CSS órfã não aparece na tela e não dá erro — ela fica sendo
 * baixada por 861 páginas e confunde quem for mexer no herói depois,
 * procurando um palco que não existe mais.
 *
 * O que ficou aprendido, porque volta a valer se alguém pedir outro rodízio:
 * as duas mensagens ocupavam a MESMA célula de grade, para a altura do palco
 * ser a da maior e nada saltar na troca — o `.oc-hero` está preso ao rodapé,
 * e um palco que mudasse de altura empurraria a headline para cima e para
 * baixo a cada 13 segundos. E a saída era mais curta que a entrada (300 ms
 * contra 640 ms): o que sai já foi lido, o que entra precisa ser alcançado.
 */

/* ── O sublinhado da aba segue a aba ATIVA ───────────────────────────────
 *
 * Os grupos de aba da captura (`.bx-tab-bar`) marcam a aba escolhida com
 * `.bx-tab-active` e desenham o traço embaixo com um elemento SEPARADO,
 * `.bx-tab-slider`, posicionado em pixel. No app da origem o Vue recalcula
 * esse pixel a cada clique; aqui o Vue não veio, então o traço ficou onde a
 * captura o largou.
 *
 * 🔴 Medido em 25/08/2026 em `/markets`: a aba ativa é `Spot` (x=28), o
 * traço está em x=93 — debaixo de `Futuros`. No desktop o desvio é de 97px.
 * Duas afirmações opostas na mesma barra, e a que o olho lê primeiro é a
 * errada: `CopyTrading` e `bot-trading` escapavam só porque ali a aba ativa
 * por acaso é a primeira.
 *
 * 🔑 Traço em elemento próprio, posicionado em pixel, é uma cópia do estado
 * que precisa ser mantida em sincronia por alguém. Como borda da PRÓPRIA aba
 * ativa, não há o que sincronizar: a marca nasce onde a classe está, e
 * acompanha se ela mudar.
 */
.bx-tab-slider {
  display: none !important;
}

[dir] .bx-tab-bar .bx-tab-item.bx-tab-active {
  border-bottom: 2px solid var(--offcode-brand, #f7931a);
}

/* ── esqueleto de carregamento ───────────────────────────────────────────
 *
 * Retângulo cinza que ocupa o LUGAR do que ainda não chegou.
 *
 * 🔴 A carteira ficava três segundos com uma frase solta numa tela preta
 * (dono, 28/08/2026 — foto). Frase sozinha não diz se está lendo, se quebrou
 * ou se a conta está vazia, e ocupa uma linha onde vão aparecer doze: quando
 * o número entra, a página inteira salta.
 *
 * 🔑 O esqueleto tem de ter a FORMA do que vem, senão é só outro jeito de
 * ficar em branco. Por isso as medidas vivem junto de cada tela, e aqui só a
 * textura.
 *
 * Sem `border`, `margin` ou `padding`: são as três que o reset `[dir]` da
 * origem zera, e quem precisar delas escreve sob `[dir]`.
 *
 * O brilho é decorativo — `prefers-reduced-motion` desliga, e o bloco
 * continua marcando o lugar. */
.oc-esq {
  position: relative;
  overflow: hidden;
  background: #131313;
  border-radius: 4px;
  flex: none;
}

.oc-esq::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, 0.05) 50%,
    rgba(255, 255, 255, 0) 100%
  );
  animation: oc-esq-brilho 1.4s ease-in-out infinite;
}

@keyframes oc-esq-brilho {
  to {
    transform: translateX(100%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .oc-esq::after {
    animation: none;
  }
}

/* O recado vivo que acompanha o esqueleto. Sai da tela e continua no leitor:
 * doze retângulos não se leem, uma frase sim. */
.oc-so-leitor {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

[dir] .oc-so-leitor {
  border: 0;
  margin: -1px;
  padding: 0;
}

/* ── a conta daquele líder, no cartão de quem já segue ─────────────────
 *
 * Cada trader copiado roda numa conta Aster própria (29/08/2026): saldo,
 * posições e high-water mark separados. A linha diz quanto há NAQUELA conta —
 * é o número que decide se a cópia vai operar, e ele não é o saldo da carteira.
 *
 * 🔑 `:root ` no prefixo por causa do reset da origem (`[dir] p { margin: 0 }`,
 * especificidade 0,1,1): sem ele a margem desta linha nasce zerada e o texto
 * cola no rodapé do cartão. É a quinta vez que este reset morde o projeto. */
:root .oc-copy-conta {
  margin: 10px 0 0;
  font-size: 12px;
  line-height: 1.4;
  color: #8b93a7;
  font-variant-numeric: tabular-nums;
}
/* Sem margem a cópia não opera — o aviso não é um número, é o que falta. */
.oc-copy-conta.oc-copy-sem-margem {
  color: var(--offcode-brand, #f7931a);
}

/* Rodapé da captura: a frase de KYC vive dentro de `.icons`, que é flex —
   flex engole o espaço entre nós inline e "Riscos" colava em "antes"
   (auditoria 30/08). Margem no próprio link resolve nos 7 idiomas. */
.footer-right-section .icons a[href*="legal/risk"] {
  margin: 0 0.3em;
}

/* 31/08/2026 (dono): o CTA da dobra estava GRANDE demais no celular — encolhe
 * um degrau, mantendo o corte. Só telas estreitas: no desktop ele está certo. */
@media (max-width: 700px) {
  [dir] .oc-hero-cta {
    --h: 46px;
    --r: 13px;
    --raio: 13px;
    min-width: 240px;
    font-size: 16px;
  }
  [dir] .oc-hero-cta-txt {
    padding: 0 36px 0 18px;
  }
  [dir] .oc-hero-cta-seta {
    font-size: 18px;
  }
}

/* Resíduo da captura da origem: um bloco «Referral Link Generator» flutuante
 * que aparecia em /wallet e /security (a nossa navegação já substituiu a
 * barra a que ele pertencia). Aparecia ao lado de «Entre para ver seus
 * saldos» e fazia a página de SEGURANÇA anunciar link de indicação —
 * auditoria de 31/08/2026. */
[dir] .copy-invite-code {
  display: none !important;
}
