/* allSwap v21 — sistema "pôster preto" (ver DESIGN.md + PLANO-V21.md) */
@font-face{
  font-family:"Anton";
  src:url('/v22/fonts/anton.woff2') format('woff2');
  font-weight:400;font-style:normal;font-display:swap;
}
:root{
  /* v22 — escada malva (ART2-2): as superfícies acima do preto ganham um fio
     do matiz da marca, mesma luminância da escada cinza antiga. --ink e o
     theme-color do index.html NÃO mudam. */
  --ink:#050505; --ink-2:#0E0C0F; --ink-3:#161318; --ink-4:#1F1B21;
  --pink:#FF2D8F; --pink-2:#ED1E79; --pink-deep:#B60C57; --pink-dim:rgba(255,45,143,.13);
  --white:#FFFFFF; --mute:#A79BA3; --mute-2:#8F8494; --press:#170A10;
  --hair:rgba(255,255,255,.12); --hair-2:rgba(255,255,255,.06);
  --teal:#2FD3A5; --gold:#F5C24B; --violet:#9B8CFF;
  /* F5 (rodada 1): erro é VERMELHO, não o rosa da marca — erro cor de marca
     vira decoração e ninguém lê como problema. Formulários usam este token. */
  --danger:#FF5C5C;
  /* F4 (rodada 1): verde de acerto legível nos 2 temas (deck .yes, checks) */
  --green:#4ADE80;
  /* v22 — chrome (UX2-1): header e tabbar OPACOS de propósito — a .97 o card
     fantasma do deck aparecia através do header no arremesso do swipe.
     --glass é o translúcido legítimo: vive SOBRE O MAPA do radar, onde ver
     através é o ponto. */
  --chrome:#050505; --chrome-2:#050505; --glass:rgba(5,5,5,.92);
  --display:"Anton",Impact,system-ui,sans-serif;
  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Inter,"Helvetica Neue",sans-serif;
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
  --safe-b:env(safe-area-inset-bottom,0px);
  /* Reforma Baygon (19/ago): barra um pouco maior e com folga garantida
     embaixo — em celular de gesto a barrinha do sistema caía EM CIMA dos
     ícones quando o env() vinha 0 (Android web/WebView). */
  --tabh:68px;
  --tab-safe:max(var(--safe-b),16px);
  /* v22 — corpo de texto por token (UX2-6, escopo restrito): consumido SÓ por
     ui.css, mod-otto e mod-conversas nesta rodada; html.txt-lg re-declara os
     tokens. Demais módulos migram na v23. */
  --fs-body:14.5px; --fs-sub:13px; --fs-hint:12.5px; --fs-k:10.5px;
  /* v22 — sombras compostas num token só (UX2-8 + ART2-4): o tema claro troca
     o highlight interno por sombra de papel redefinindo só os tokens. */
  --shadow-card:inset 0 1px 0 rgba(255,255,255,.05);
  --shadow-sheet:inset 0 1px 0 rgba(255,255,255,.05),0 -18px 48px rgba(0,0,0,.5);
  --shadow-mdl:inset 0 1px 0 rgba(255,255,255,.05),0 24px 64px rgba(0,0,0,.55);
  /* Geometria por PAPEL, não por gosto: o raio passa a dizer o que a coisa é.
     sm = controle pequeno e caixa de aviso; md = bloco de conteúdo curto;
     lg = card; xl = superfície que cobre a tela (folha e modal); pill = trilho.
     Quem escrever componente novo escolhe o papel, não um número. */
  --r-sm:10px; --r-md:14px; --r-lg:18px; --r-xl:20px; --r-pill:99px;
}
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
html,body{height:100%}
/* F2 (rodada 1): o arrasto horizontal do deck NUNCA pode virar a navegação
   "voltar" do navegador (testador saiu do app no meio do swipe). O gesto de
   swipe-nav do Chrome/Edge nasce do overscroll no eixo X — cortado na raiz. */
html,body{overscroll-behavior-x:none}
/* 21/ago — o CARD EM VOO nao pode inchar a viewport do WebView.
   `overflow-x:hidden` estava so no body, e no Android o que manda no viewport
   e o ROOT: o card que sai (`.dk-card.out-r`, translate 126%) transbordava a
   largura, o WebView entrava em "shrink to fit" e dava zoom-out. Medido no
   moto g15: `innerHeight` saltava 901 -> 1314 -> 1389 CSS px no meio do gesto.
   `fitStack()` remedia a barra de decisao nessa viewport falsa e escrevia
   `--dkh` de 838px (era 422), a pilha dobrava, a tabbar caia para fora da tela
   e por ~500ms sobrava um retangulo chapado com o gradiente da capa do proximo
   anuncio ocupando quase tudo — o "a tela toda fica azul" que o dono viu (azul
   quando a capa seguinte era azul; a cor era sempre a do proximo card).
   `clip` e nao `hidden`: no root, `hidden` propaga para o viewport e cria
   container de rolagem; `clip` corta o transbordo lateral e deixa o eixo Y
   `visible`, entao o scroll vertical das telas longas continua igual. */
html{overflow-x:clip}
html{background:var(--ink)}
body{background:var(--ink);color:var(--white);font-family:var(--sans);font-size:var(--fs-body);line-height:1.45;
  overflow-x:hidden;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
button,input,select,textarea{font:inherit;color:inherit}
button{cursor:pointer;border:none;background:none}
a{color:inherit;text-decoration:none}
::selection{background:var(--pink);color:#fff}
.hidden{display:none!important}
.mono{font-family:var(--mono);font-variant-numeric:tabular-nums}
.wrap{width:100%;max-width:440px;margin:0 auto;padding:0 16px}

/* ---------- tipografia ---------- */
.disp{font-family:var(--display);text-transform:uppercase;letter-spacing:0;line-height:1.1;font-weight:400}
h1.disp{font-size:34px}
.disp-xl{font-size:40px}
.disp-lg{font-size:30px}
/* v22 (UX2-6): display pequeno (≤22px) respira com .015em; ≥30px mantém 0 —
   tracking relativo ao corpo, não ao pôster. */
.disp-md{font-size:22px;letter-spacing:.015em}
.lbl{font-size:var(--fs-k);font-weight:800;letter-spacing:.11em;text-transform:uppercase;color:var(--mute-2)}
.sub{color:var(--mute);font-size:var(--fs-sub)}
.hint{color:var(--mute);font-size:var(--fs-hint)}
.pink{color:var(--pink)}
.tealc{color:var(--teal)}
.goldc{color:var(--gold)}
.num{font-family:var(--mono);font-variant-numeric:tabular-nums;font-weight:700}

/* ---------- marca ---------- */
.wm{display:inline-flex;align-items:baseline;font-weight:900;letter-spacing:-1px;line-height:1}
/* v22 (UX2-1): o "all" acompanha o chrome — em chrome claro, tinta escura. */
.wm .a{color:var(--white)}
.wm .s{color:var(--pink)}
.mark{width:30px;height:30px;flex:none;object-fit:contain}
.mark-fb{width:30px;height:30px;flex:none;border-radius:9px;display:grid;place-items:center;font-weight:900;
  font-size:16px;background:var(--pink);color:#0A0006}
.tagline{font-size:11px;font-weight:700;letter-spacing:.24em;text-transform:uppercase;color:var(--mute)}
.tagline b{color:var(--pink);font-weight:800}

/* ---------- estrutura ---------- */
.rule{height:1px;background:var(--hair);border:0;margin:14px 0}
.rule.glow{background:linear-gradient(90deg,transparent,rgba(255,45,143,.75),transparent);height:1px}
.rule.tight{margin:10px 0}
.sec{margin:22px 0 10px;display:flex;align-items:baseline;gap:10px}
.sec h2{font-family:var(--display);text-transform:uppercase;font-size:19px;letter-spacing:.015em;font-weight:400;line-height:1.1}
.sec .more{margin-left:auto;font-size:11.5px;font-weight:800;color:var(--pink);letter-spacing:.3px}
.card{background:var(--ink-2);border:1px solid var(--hair);border-radius:var(--r-lg);padding:16px;
  box-shadow:var(--shadow-card)}
.card + .card{margin-top:10px}
.card.flat{background:none;border-color:var(--hair-2)}
.card.pink-edge{border-color:rgba(255,45,143,.45)}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.grid2 > *{min-width:0}
.stack{display:grid;gap:10px}

/* ---------- ícones desenhados (AS.icon) ---------- */
.ic{width:1em;height:1em;flex:none;display:inline-block;vertical-align:-.14em}

/* ---------- ícone de linha em círculo (do anúncio) ---------- */
.ico{width:40px;height:40px;flex:none;border-radius:50%;border:1.5px solid var(--pink);color:var(--pink);
  display:grid;place-items:center;font-size:17px;line-height:1}
.ico .ic{width:1.2em;height:1.2em;vertical-align:0}
.ico.sm{width:30px;height:30px;font-size:13px;border-width:1.5px}
.ico.lg{width:56px;height:56px;font-size:24px}
.ico.mutec{border-color:var(--hair);color:var(--mute)}
.ico.tealc{border-color:rgba(47,211,165,.6);color:var(--teal)}
.ico.goldc{border-color:rgba(245,194,75,.6);color:var(--gold)}
.ico.solid{background:var(--pink);color:#0A0006;border-color:transparent}
/* v22 (ART1-3): violeta é autoria — o círculo do Otto quando ele assina. */
.ico.vio{border-color:rgba(155,140,255,.6);color:var(--violet)}

/* ---------- KPI ---------- */
.kpi{display:grid;gap:2px}
.kpi .v{font-family:var(--display);font-size:30px;line-height:.95;letter-spacing:0;font-weight:400}
.kpi .v.mono{font-family:var(--mono);font-size:22px;font-weight:700;letter-spacing:-.5px}
.kpi .d{font-size:11px;font-weight:800;font-family:var(--mono)}
.kpi .d.up{color:var(--teal)}
.kpi .d.dn{color:var(--pink)}
.kpi-row{display:grid;grid-template-columns:1fr 1fr;gap:16px 12px}

/* ---------- linha de lista ---------- */
.row{display:flex;align-items:center;gap:12px;padding:13px 0;border-bottom:1px solid var(--hair-2);
  width:100%;text-align:left}
.row:last-child{border-bottom:0}
.row .body{flex:1;min-width:0}
.row .t{font-size:14.5px;font-weight:700;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.row .s{font-size:12.5px;color:var(--mute);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:1px}
.row .r{margin-left:auto;text-align:right;flex:none}
.row .r .v{font-family:var(--mono);font-weight:700;font-size:13.5px}
.row .r .k{font-size:10px;color:var(--mute-2);letter-spacing:.6px;text-transform:uppercase}
.row .chev{color:var(--mute-2);font-size:16px;flex:none}
.row.press:active{background:var(--press)}
.av{width:40px;height:40px;flex:none;border-radius:12px;display:grid;place-items:center;font-weight:800;font-size:13px;
  background:var(--ink-4);border:1px solid var(--hair);font-family:var(--sans);overflow:hidden}
.av img{width:100%;height:100%;object-fit:cover}
.av.dot::after{content:"";position:absolute}

/* ---------- revelação progressiva ----------
   O <details class="dk-disc"> nasceu no deck (rodada 1) e virou componente do
   sistema: o que fala de dinheiro, custódia, taxa ou responsabilidade nunca é
   apagado — sai do CAMINHO de quem está decidindo e fica a um toque. Na frente
   ficam o número e a consequência; o parágrafo mora dentro.
   <details> é bloco: não pode ser aberto dentro de um <p>. */
.disc{margin-top:10px}
.disc > summary{display:flex;align-items:center;gap:8px;min-height:36px;cursor:pointer;list-style:none;
  font-size:12px;font-weight:700;letter-spacing:.2px;color:var(--mute)}
.disc > summary::-webkit-details-marker{display:none}
.disc > summary::after{content:"+";margin-left:auto;flex:none;width:20px;height:20px;border-radius:50%;
  border:1px solid var(--hair);display:grid;place-items:center;font-size:13px;line-height:1;color:var(--mute-2)}
.disc > summary:hover{color:var(--white)}
.disc[open] > summary{color:var(--white)}
.disc[open] > summary::after{content:"\2212";border-color:var(--pink);color:var(--pink)}
.disc > summary + *{margin-top:0}
/* Resposta ao toque: o que estava escondido ENTRA, em vez de piscar no lugar.
   <details> não anima sozinho — 120 ms de subida bastam para o olho seguir de
   onde o texto veio e não reler a tela inteira. É o único movimento do
   componente: nada pulsa, nada se repete. */
.disc[open] > summary + *{animation:discIn .12s cubic-bezier(.2,.9,.25,1)}
@keyframes discIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}

/* ---------- a leitura do Otto na superfície da decisão ----------
   O servidor (api/app/services/otto_mesa.py) já escreve o que o Otto viu na
   conta quando uma proposta entra. Isso vivia SÓ como mensagem no fio da
   conversa — rolava para cima e sumia justamente quando a pessoa ia decidir.
   Este bloco é o mesmo violeta do moderador (o da mesa a três e o da bolha
   `.cv-ottoline`), agora onde estão aceitar, recusar e contrapor: duas telas
   (folha da proposta em mod-conversas.js e folha da Mesa em mod-mesa.js) usam
   o MESMO componente, então ele mora aqui, como o `.disc`.
   Só entra: 160 ms de subida, uma vez, para o olho achar quem falou. */
.otto-read{margin-top:11px;border:1px solid rgba(155,140,255,.3);background:rgba(155,140,255,.07);
  border-radius:var(--r-md);padding:10px 13px;font-size:13px;line-height:1.5;text-align:left;
  animation:ottoRead .16s cubic-bezier(.2,.9,.25,1)}
.otto-read .who{display:flex;align-items:center;gap:6px;font-family:var(--mono);font-size:10px;
  font-weight:800;letter-spacing:1px;text-transform:uppercase;color:var(--violet);margin-bottom:5px}
.otto-read .who .ic,.otto-read .who svg{width:13px;height:13px;vertical-align:0}
/* a voz do cérebro por cima do parecer (20/ago): leitura verificada em cima da
   conta que já está na folha — negrito para se distinguir do texto do parecer */
.otto-read .voz,.bf-juizo .voz{display:block;margin:0 0 7px;font-weight:600;line-height:1.45;
  animation:ottoRead .16s cubic-bezier(.2,.9,.25,1)}
.bf-juizo .voz{margin:6px 0 0;font-size:12.5px}
@keyframes ottoRead{from{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}

/* ---------- tag ---------- */
/* v22 (UX2-5): piso tipográfico — nada lido abaixo de 10px (9.5→10.5). */
.tag{display:inline-flex;align-items:center;gap:4px;font-size:10.5px;font-weight:800;letter-spacing:.085em;
  text-transform:uppercase;border:1px solid var(--hair);border-radius:6px;padding:3px 7px;color:var(--mute);
  white-space:nowrap}
/* Rosa é cor de FUNDO, não de texto branco em cima: #fff sobre --pink dá
   3,49:1 e reprova AA. A tinta escura da marca dá 5,93:1 — é a mesma decisão
   já tomada na landing (site/index.html › .btn.solid). */
.tag.pink{color:#0A0006;border-color:transparent;background:var(--pink)}
.tag.pinkline{color:var(--pink);border-color:rgba(255,45,143,.5)}
.tag.teal{color:var(--teal);border-color:rgba(47,211,165,.45)}
.tag.gold{color:var(--gold);border-color:rgba(245,194,75,.45)}
.tag.violet{color:var(--violet);border-color:rgba(155,140,255,.45)}
.vf{display:inline-grid;place-items:center;width:14px;height:14px;border-radius:50%;background:var(--teal);
  color:#04231a;font-size:9px;font-weight:900;vertical-align:1px}

/* ---------- botões ---------- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:48px;padding:0 18px;
  border-radius:12px;font-size:14.5px;font-weight:800;letter-spacing:.2px;transition:opacity .15s,
  background .15s,border-color .15s}
.btn:active{background:var(--press)}
/* mesma razão da .tag.pink: 3,49:1 → 5,93:1, sem trocar o rosa da marca */
.btn.solid{background:var(--pink);color:#0A0006}
.btn.solid:hover{background:var(--pink-2)}
.btn.solid:active{background:var(--pink-2)}
/* F4 (rodada 1): tokens no lugar de branco literal — o tema claro troca os
   tokens e estes botões ficavam invisíveis (branco sobre branco). */
.btn.line{border:1px solid var(--hair);color:var(--white)}
.btn.line:hover{border-color:var(--pink);color:var(--white)}
.btn.ghost{color:var(--pink);padding:0 6px;min-height:40px}
.btn.block{width:100%}
.btn.sm{min-height:38px;font-size:13px;padding:0 13px;border-radius:var(--r-sm)}
.btn.xs{min-height:32px;font-size:12px;padding:0 10px;border-radius:9px;font-weight:800}
.btn[disabled]{opacity:.4;cursor:default}
/* v22 (ART2-5): o CTA principal emite luz — mas com contenção: dentro do corpo
   de modal tudo é FOSCO (só o CTA do rodapé acende) e, quando há dois solids
   lado a lado, só o ÚLTIMO carrega o halo. Um glow por tela, sempre no botão
   que fecha a decisão. */
.btn.solid:not(.sm):not(.xs){box-shadow:0 8px 22px rgba(255,45,143,.20)}
.btn.solid:not(.sm):not(.xs):active{box-shadow:0 4px 12px rgba(255,45,143,.14)}
.mdl-body .btn.solid{box-shadow:none}
.mdl-foot .btn.solid:not(:last-of-type),
.btn-row .btn.solid:not(:last-of-type){box-shadow:none}
html[data-tema="claro"] .btn.solid:not(.sm):not(.xs){box-shadow:0 6px 16px rgba(237,30,121,.16)}
html[data-tema="claro"] .mdl-body .btn.solid{box-shadow:none}
.btn-row{display:flex;gap:9px}
.btn-row > .btn{flex:1}
.spin{width:15px;height:15px;border-radius:50%;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;
  display:inline-block;animation:sp .7s linear infinite}
@keyframes sp{to{transform:rotate(360deg)}}

/* ---------- campos ---------- */
.field{margin-bottom:13px}
.field > label{display:block;margin-bottom:6px}
.input{width:100%;background:var(--ink-3);border:1px solid var(--hair);border-radius:12px;padding:13px 14px;
  font-size:15px;outline:none;transition:border-color .15s}
.input:focus{border-color:var(--pink)}
/* O exemplo dentro do campo é instrução, não decoração: em #4B4B55 ele dava
   2,13:1 sobre --ink-3 e sumia no sol. --mute-2 é o mesmo cinza do resto do
   texto secundário do sistema (5,16:1) — continua claramente "ainda vazio". */
.input::placeholder{color:var(--mute-2)}
textarea.input{min-height:70px;resize:vertical}
select.input{appearance:none}
.err{border:1px solid rgba(255,45,143,.5);background:rgba(255,45,143,.1);color:#FFC2DC;border-radius:var(--r-sm);
  padding:10px 12px;font-size:13px;margin-bottom:12px}

/* ---------- medidor ---------- */
/* medidor: .meter (alias .bar para markup ja escrito; :not(header) evita colidir com <header class="bar">) */
.meter,.bar:not(header){height:5px;border-radius:var(--r-pill);background:var(--ink-4);overflow:hidden}
.meter > i,.bar:not(header) > i{display:block;height:100%;background:var(--pink);border-radius:var(--r-pill)}
.meter.teal > i,.bar:not(header).teal > i{background:var(--teal)}
.steps{display:flex;gap:4px}
.steps i{flex:1;height:4px;border-radius:var(--r-pill);background:var(--ink-4)}
.steps i.on{background:var(--pink)}
.steps.teal i.on{background:var(--teal)}

/* ---------- login ---------- */
/* A PORTA (26/ago) — UMA JANELA SÓ.
   Antes: bandeira, pôster de 3 linhas, duas linhas de argumento com ícone, o
   logo repetido, o selo "Deslizou · Conectou · Swapou", o formulário e duas
   linhas de nota comercial. Nove blocos de texto empilhados: ~1300px de altura
   num aparelho de 844px, ou seja, a pessoa tinha de ROLAR a porta para achar o
   botão de entrar. Porta não é landing — a mesma pessoa abre esta tela dezenas
   de vezes e o argumento de venda já foi feito no site.
   Agora: marca, pôster, formulário, nota. Quatro blocos, uma tela, sem rolagem.
   As frases removidas continuam traduzidas (login.lead1/2, login.tagline) e o
   estatico() do i18n.js pinta só o que acha no DOM — apagar o elemento não
   quebra porta nenhuma das sete. */
/* A porta é uma GRADE DE DOIS LUGARES: o formulário e o palco da animação.
   Até 26/ago era uma coluna só com a animação em `position:fixed` por baixo de
   tudo — a roda cruzava o título e o botão, e a única forma de manter a tela
   legível era abafar a animação com um véu. O resultado foi o pior dos dois
   mundos: fundo feio E escondido.
   Agora cada um tem seu lugar. No celular a grade é vertical (palco em cima,
   formulário embaixo); no desktop vira duas colunas (formulário à esquerda,
   palco ocupando a direita inteira). Como nada se sobrepõe, o véu deixou de
   existir e a cena pôde ganhar cor, contorno e luz. */
/* `height`, não `min-height`: com altura indefinida o Chromium dimensiona as
   trilhas `fr` pelo conteúdo (o piso do palco virava 1fr=132px e o vão 2fr
   ganhava 264px numa tela sem folga nenhuma). Altura DEFINIDA faz a folga real
   da tela ser o que se reparte entre palco e vão — e quando o conteúdo passa
   da tela, quem segura é o overflow-y:auto que sempre esteve aqui. */
#login{height:100dvh;display:grid;overflow-y:auto;
  grid-template-columns:minmax(0,1fr);
  /* vão do topo (até 21dvh) · pôster (auto) · formulário (auto) · vão de baixo
     (o resto). O PALCO NÃO MORA MAIS NA GRADE (27/ago): ele é uma camada
     absoluta de FUNDO no topo da tela — ver o bloco dele abaixo — e por isso
     as trilhas só posicionam o texto. A versão em que o palco era a trilha
     `1fr` prendia o bloco de agir ao rodapé (toda folga virava animação) e a
     tentativa seguinte, de congelar o palco e jogar a folga para baixo,
     encolhia a cena — o Marllon pediu as duas coisas de volta: o grafo GRANDE
     no fundo, como era, e o texto ~10% acima do rodapé (subiu 15, desceu 5).
     O vão de cima é quem dita a altura do texto: cresce até 21dvh e para —
     numa tela justa ele absorve só a folga que existe e nada rola. O texto
     PODE cobrir a barriga do grafo; é fundo, não vizinho de fileira (pôster e
     caixa levam z-index por isso).
     A ordem do DOM continua marca → cena → formulário (a marca é o primeiro
     conteúdo que um leitor de tela encontra) e o palco é `aria-hidden`. */
  grid-template-rows:minmax(0,21dvh) auto auto minmax(0,1fr);
  position:relative;
  padding:calc(env(safe-area-inset-top,0px) + 56px) 18px calc(env(safe-area-inset-bottom,0px) + 20px);
  background:var(--ink);
  /* a cor em que a cena se dissolve nas bordas do palco: é o que impede o
     palco de ler como um RETÂNGULO colado na tela. Por tema, porque no claro
     dissolver no preto desenharia uma moldura escura em volta da cena. */
  --porta-fim:var(--ink)}
html[data-tema="claro"] #login{--porta-fim:#F6F4F6}
/* `margin:auto` num item de grade centraliza SEM cortar o topo quando o
   conteúdo passa da tela. `align-items:center` cortaria: num aparelho de
   640px de altura, ou com a fonte do sistema aumentada, a marca sairia por
   cima da borda e não haveria rolagem que a trouxesse de volta. */
.login-box{width:100%;max-width:404px;margin:auto;position:relative;z-index:1;
  grid-column:1;grid-row:3}
/* (o palco não tem colocação de grade no celular: é camada absoluta de fundo —
   ver o bloco "---- o palco ----". No desktop a media query o devolve à
   coluna da direita.) */
/* O pôster é item da grade, na frente do palco (z-index): o grafo é FUNDO e o
   texto passa por cima dele sem perder leitura. Mesma largura e mesmo
   `margin:auto` da caixa, senão a marca desalinha do formulário por um fio.
   A COLOCAÇÃO mora aqui, e não na seção "pôster" lá embaixo, por causa da
   ordem do arquivo: aquela seção vem DEPOIS da media query do desktop e, com a
   mesma especificidade, desfazia o `grid-row` de lá — o pôster voltava para a
   linha-vão de cima e abria um buraco entre o título e o campo de e-mail. */
.poster{width:100%;max-width:404px;
  margin:clamp(4px,1.1vh,12px) auto clamp(12px,2.4vh,22px);
  grid-column:1;grid-row:2;position:relative;z-index:1}

/* ---- fundo: o carrossel da permuta ----
   Dois anéis concêntricos de cartas girando em SENTIDOS OPOSTOS, inclinados,
   em 3D de CSS puro. É a permuta como objeto: enquanto um anel leva as cartas
   para a direita, o outro traz as dele para a esquerda, e as duas rodas se
   cruzam sem parar. Cada carta tem duas faces — rosa de um lado, violeta do
   outro —, então a metade de perto do anel é rosa, a de longe é violeta, e
   elas trocam de cor sozinhas conforme a roda vira.

   O truque de custo, e o motivo de isto rodar num WebView de celular fraco:
   só TRÊS elementos são animados (o eixo e os dois anéis). As 13 cartas têm
   transform ESTÁTICO — quem as move é o transform do anel-pai, que o
   compositor resolve numa matriz só. Sem WebGL, sem canvas, sem biblioteca,
   sem blur e sem backdrop-filter (o WebView paga caro por cada um destes).

   A camada mora DENTRO do #login de propósito: quando a sessão abre, o #login
   vira display:none e a animação some junto. Nenhum quadro pago no deck. */
/* ---- o palco ----
   No celular o palco é CAMADA DE FUNDO (27/ago): absoluto, sangrando a largura
   inteira, do teto até ~36% da tela — o espaço que a trilha `1fr` dava a ele
   numa tela alta, agora garantido em toda tela. Ele não disputa fileira com o
   texto: o pôster e a caixa têm z-index e passam POR CIMA da barriga da cena
   quando a tela é baixa; a dissolução das bordas (::after) e o pó de luz da
   malha aguentam texto em cima sem matar leitura. Foi pedido assim: o grafo
   grande de fundo valia mais que a faixa exclusiva e encolhida.
   No desktop a media query o devolve ao fluxo: coluna da direita inteira.
   O piso de 220px é para paisagem/tela minúscula, onde 36dvh viraria um fio.
   `perspective` saiu junto com o carrossel de cartas: a cena WebGL tem projeção
   própria e o suplente de agora são pontos chapados, que não giram em 3D. */
/* top:7dvh (27/ago): a cena desceu para encostar a barriga NA marca — no teto
   ela flutuava descolada do texto; atrás do "allSwap" ela vira o fundo dele. */
.porta-palco{position:absolute;top:7dvh;left:0;right:0;
  height:max(36dvh,220px);margin:0;
  overflow:hidden}
.porta-palco > canvas{position:absolute;inset:0;display:block;
  width:100%;height:100%}
/* O suplente de CSS só existe quando o WebGL não sobe — porta3d.js marca
   `.sem3d`. Escondido por padrão: se ficasse visível até o script rodar, a
   porta abriria com a constelação parada POR CIMA da malha viva por um quadro. */
.porta-palco .pb-pontos{display:none}
.porta-palco.sem3d .pb-pontos{display:block}
.porta-palco.sem3d > canvas{display:none}
/* A cena se dissolve nas bordas em vez de terminar numa aresta reta: sem isto
   o palco lê como um retângulo de vídeo colado na tela, e no celular a faixa
   ganharia duas linhas horizontais que não existem em lugar nenhum do app. */
.porta-palco::after{content:'';position:absolute;inset:-1px;pointer-events:none;
  background:radial-gradient(76% 82% at 50% 50%,transparent 46%,var(--porta-fim) 99%)}
.porta-palco > i{position:absolute;display:block}
/* O clarão atrás da cena. Eram DOIS borrões descentrados numa caixa de
   `inset:-25%`: fora da tela inteira eles nunca fechavam, mas dentro de um
   palco com `overflow:hidden` a elipse era cortada antes de acabar e cada um
   virava um RETÂNGULO claro visível no canto — apareceu nos dois prints.
   Agora é um só, centrado na cena, e o degradê termina em 74% do raio: bem
   antes da borda da caixa, então não há aresta para cortar. */
.pb-aura{inset:0;
  background:radial-gradient(44% 46% at 50% 52%,rgba(255,45,143,.17),transparent 74%);
  animation:pb-respira 26s ease-in-out infinite}

/* ---- o suplente: constelação parada ----
   Sem WebGL não há malha, não há pulso e não há cadeia — mas um palco em
   branco é pior que um desenho quieto. Sobram os pontos: as mesmas empresas,
   sem as ligações acesas. Nada de fingir movimento que a máquina não pode
   pagar; eles só respiram, cada um no seu tempo (`--d`).
   O carrossel de cartas que morava aqui foi REMOVIDO com a cena nova: carta é
   o vocabulário do deck e não dizia nada na porta — o suplente tinha de falar
   a mesma língua do titular. */
.pb-pontos{position:absolute;inset:0}
.pb-pontos > i{position:absolute;left:var(--x);top:var(--y);
  width:var(--s);height:var(--s);margin:calc(var(--s) / -2) 0 0 calc(var(--s) / -2);
  border-radius:99px;background:var(--violet);
  /* a auréola é `box-shadow`, não `filter:blur` — o WebView paga caro por cada
     filtro, e são 14 deles na tela ao mesmo tempo. */
  box-shadow:0 0 calc(var(--s) * 2.4) rgba(155,140,255,.55);
  animation:pb-respira 7s ease-in-out infinite;animation-delay:var(--d)}
/* os três maiores puxam o rosa da marca: uma constelação de uma cor só lê como
   poeira, e com dois tons ela ganha hierarquia mesmo parada. */
.pb-pontos > i:nth-child(3n+2){background:var(--pink);
  box-shadow:0 0 calc(var(--s) * 2.4) rgba(255,45,143,.5)}

@keyframes pb-respira{
  0%,100%{transform:scale(1);opacity:.85}
  50%    {transform:scale(1.1) translate(1.5%,-1.5%);opacity:1}
}
/* O VÉU MORREU. Ele existia para impedir que uma carta rosa cruzasse por trás
   do rótulo E-MAIL DA EMPRESA e derrubasse o contraste — sintoma de uma
   composição em que a animação e o texto disputavam o mesmo espaço. Com o
   palco, nenhum pixel da cena encosta em nenhum pixel de texto, e o problema
   de contraste deixa de existir na origem em vez de ser abafado. Fica só a
   dissolução das bordas do palco (.porta-palco::after), que é composição, não
   correção. */
/* No claro o degradê rosa sobre papel pesa o dobro do que pesa sobre preto, e
   a carta desenhada a borda BRANCA desaparece — sem a borda, o carrossel vira
   uma mancha rosa que muda de forma e ninguém entende o que é. A borda passa a
   ser de tinta (o mesmo --hair do tema) e o brilho interno vira branco de
   papel: a carta volta a ter aresta, e o 3D se lê nos dois temas. (A cena
   WebGL resolve o mesmo problema por conta própria, em porta3d.js › tema().) */
html[data-tema="claro"] .porta-palco.sem3d{opacity:.62}
/* no papel o ponto violeta claro some: no claro ele vira tinta. */
html[data-tema="claro"] .pb-pontos > i{box-shadow:none;opacity:.55}

/* ---- desktop: o palco vira a metade direita da tela ----
   No aparelho a divisão é por ANDAR (faixa em cima, formulário embaixo) porque
   não há largura para dividir. No monitor há largura sobrando — e era ali que
   estava o desperdício da versão anterior: a roda espremida atrás de uma
   coluna de 404px enquanto dois terços da tela eram preto vazio.
   904px é o ponto em que a coluna do formulário (404px) e um palco que valha a
   pena (>420px) cabem com respiro entre eles. */
@media (min-width:904px){
  #login{grid-template-columns:minmax(340px,42%) minmax(0,1fr);
    /* QUATRO linhas: duas de conteúdo (pôster, formulário) entre duas linhas-vão
       de `1fr`. É o que centra o par verticalmente SEM esticá-lo — a versão com
       `auto auto` + altura mínima no palco fazia as duas linhas de conteúdo
       crescerem para acomodar o palco, e a sobra virava um buraco entre o
       título e o campo de e-mail e outro embaixo do rodapé. Aqui a sobra vai
       toda para os vãos, que não têm conteúdo dentro. */
    grid-template-rows:minmax(0,1fr) auto auto minmax(0,1fr);
    column-gap:clamp(20px,3.4vw,64px);
    padding:calc(env(safe-area-inset-top,0px) + 64px) clamp(24px,4vw,72px)
            calc(env(safe-area-inset-bottom,0px) + 32px) clamp(30px,6vw,104px)}
  .poster{grid-column:1;grid-row:2;margin:0 0 clamp(14px,2.6vh,26px)}
  .login-box{grid-column:1;grid-row:3;margin:0}
  /* `min-height:0` num item de grade é obrigatório para ele PODER encolher:
     sem isso o mínimo automático do conteúdo mantém a linha alta e o palco
     estoura a viewport num monitor baixo. */
  /* o palco atravessa as quatro linhas: é o único item que enxerga a altura
     inteira da tela, e é por isso que ele pode ser o lado alto da composição
     sem empurrar nada do outro lado. */
  /* `position:relative` + `top:auto` desfazem o fundo absoluto do celular:
     aqui o palco volta a ser item da grade, sem o mergulho de 7dvh. */
  .porta-palco{grid-column:2;grid-row:1 / -1;margin:0;position:relative;top:auto;
    height:100%;min-height:0}
  /* Na coluna alta a dissolução tem de ser mais frouxa: com o mesmo raio da
     faixa do celular, a borda escura comeria os arcos laterais da cena. */
  .porta-palco::after{
    background:radial-gradient(78% 72% at 50% 50%,transparent 46%,var(--porta-fim) 99%)}
}

/* ---- pôster ---- */
/* A marca subiu para CIMA do pôster: identificar o app é a primeira coisa que
   a tela deve fazer, e o lockup repetido lá embaixo (com o selo junto) só
   existia porque a versão antiga usava o rodapé do pôster como assinatura. */
/* O pôster saiu de dentro da .login-box e virou item da grade, para o palco
   poder ficar ENTRE ele e os campos. As mesmas 404px de largura e o mesmo
   `margin:auto` da caixa, senão a marca desalinha do formulário por um fio. */
.poster{text-align:left}
.brandline{display:flex;align-items:center;gap:9px;margin:0 0 13px}
.brandline .mark,.brandline .mark-fb{width:26px;height:26px}
.brandline .wm{font-size:26px}
/* 3 linhas de Anton continuam sendo o pôster da marca (e o login.h1 já está
   traduzido com os <br> nas quatro línguas). O que mudou foi a ESCALA: no
   tamanho antigo o título sozinho comia 150px de uma tela que precisa caber
   inteira. */
.poster h1{font-family:var(--display);text-transform:uppercase;
  font-size:clamp(29px,8.4vw,42px);line-height:1.02;letter-spacing:0;font-weight:400}
.poster h1 .pk{color:var(--pink)}

/* ---- as duas portas, no FIM da tela ----
   Até 26/ago o "Criar conta" era um botão rosa no TOPO do formulário e o entrar
   era um contorno lá embaixo, separados por um divisor que existia só para
   explicar essa inversão. A ordem de leitura brigava com a ordem de uso: quem
   digitou e-mail e senha tinha de passar POR CIMA do botão errado.
   Agora os dois ficam colados, no fim, onde a mão já está — e o divisor sumiu
   junto, porque não há mais duas metades para separar. ENTRAR volta a ser o
   cheio: é a conclusão do formulário logo acima dele. */
.porta-acoes{display:grid;gap:10px;margin-top:4px}
#loginErr{margin-bottom:12px}
/* ---- a recusa como POP-UP (27/ago, r7) ----
   O cartão fixo dentro do formulário "ficava para sempre" (Marllon) — recusa
   é ACONTECIMENTO, não estado. Virou um pop-up que desce do teto, conta o que
   houve e vai embora sozinho em 3s; o fio de progresso na base é o aviso de
   que ele vai sumir, e um toque o dispensa antes. Os botões que moravam no
   cartão não fazem falta: o "Esqueci a senha" permanente está logo abaixo dos
   campos, a senha volta focada e selecionada, e a re-tentativa do sem-internet
   é um listener, não um botão (core.js › loginErrCard).
   Fundo SÓLIDO de propósito: ele flutua sobre o grafo e sobre texto — nada de
   backdrop-filter (imposto por quadro no WebView) nem transparência que
   deixaria a malha vazar por trás da frase. */
.porta-pop{position:fixed;left:50%;top:calc(env(safe-area-inset-top,0px) + 64px);
  transform:translateX(-50%);z-index:70;width:min(404px,calc(100vw - 36px));
  display:flex;gap:11px;align-items:flex-start;padding:13px 15px 15px;
  border-radius:16px;border:1px solid rgba(255,45,143,.42);
  background:#1D1219;color:#FFC2DC;font-size:13px;
  box-shadow:0 18px 50px rgba(0,0,0,.5);
  cursor:pointer;overflow:hidden}
.porta-pop .pp-ico{flex:0 0 auto;width:36px;height:36px;border-radius:11px;
  display:grid;place-items:center;
  background:rgba(255,45,143,.13);border:1px solid rgba(255,45,143,.28)}
.porta-pop .pp-ico svg{width:19px;height:19px}
.porta-pop .pp-tx{display:grid;gap:2px;min-width:0;align-self:center}
.porta-pop .pp-tx b{font-size:13.5px}
.porta-pop .pp-tx span{opacity:.85;line-height:1.4}
.porta-pop .pp-tempo{position:absolute;left:0;right:0;bottom:0;height:2px;
  background:linear-gradient(90deg,var(--pink),var(--violet));
  transform-origin:left}
.porta-pop.saindo{opacity:0;transform:translate(-50%,-12px);pointer-events:none}
html[data-tema="claro"] .porta-pop{background:#FFFBFD;color:#A3213B;
  border-color:rgba(198,46,56,.4);box-shadow:0 18px 44px rgba(122,20,44,.18)}
html[data-tema="claro"] .porta-pop .pp-ico{background:rgba(198,46,56,.07);border-color:rgba(198,46,56,.3)}
@media (prefers-reduced-motion:no-preference){
  .porta-pop{animation:pp-entra .34s cubic-bezier(.16,1,.3,1);
    transition:opacity .24s ease,transform .24s ease}
  .porta-pop .pp-tempo{animation:pp-tempo 3s linear forwards}
}
@keyframes pp-entra{from{opacity:0;transform:translate(-50%,-14px)}to{opacity:1;transform:translate(-50%,0)}}
@keyframes pp-tempo{from{transform:scaleX(1)}to{transform:scaleX(0)}}
/* sem movimento: o fio que encolhe é justamente movimento — some; o pop-up
   aparece e desaparece seco, e o tempo de 3s continua o mesmo. */
@media (prefers-reduced-motion:reduce){.porta-pop .pp-tempo{display:none}}
/* R2 (G16): "Esqueci a senha" tem 26px de caixa — a MIRA cresce até 44px. */
#forgotBtn{display:block;position:relative;margin:-2px 0 14px auto;padding:4px 0;
  border:0;background:none;color:var(--mute-2);font:inherit;font-size:var(--fs-hint);
  text-decoration:underline;cursor:pointer}
#forgotBtn:hover{color:var(--white)}
#forgotBtn::after{content:'';position:absolute;inset:calc((44px - 100%) / -2) 0}
#login .hint{text-align:center;margin-top:15px;line-height:1.4}

/* ---- aparelho BAIXO (≤700px de altura) ----
   A porta foi medida para caber inteira em 844px; num Android de 640px ela
   passava ~90px e o CRIAR CONTA nascia cortado ao meio — a única tela do app
   em que o botão de entrar exigia rolagem. Aqui cede quem tem gordura, na
   ordem: o teto (a fileira fixa do topo precisa de 48px, não 56), o palco (a
   malha continua legível em 100px — o enquadramento dela é por aspecto, se
   ajusta sozinho) e os respiros do pôster e do rodapé. Campo e botão não
   encolhem: são o que a mão precisa acertar.
   Fica DEPOIS de todas as regras que sobrescreve (o bloco de colocação da
   grade, o palco e a fileira de ações) — mesma especificidade, quem vale é a
   última. Só no layout de coluna única (<904px): num monitor BAIXO o desktop
   já resolve a altura com as linhas-vão, e estas margens desfariam as dele. */
@media (max-height:700px) and (max-width:903.98px){
  #login{padding-top:calc(env(safe-area-inset-top,0px) + 48px);
    padding-bottom:calc(env(safe-area-inset-bottom,0px) + 12px);
    /* vão do topo menor: o grafo é fundo e não precisa de fileira própria —
       o texto sobe o suficiente para caber sem rolar. */
    grid-template-rows:minmax(0,16dvh) auto auto minmax(0,1fr)}
  .poster{margin:2px auto 10px}
  .brandline{margin-bottom:9px}
  .porta-acoes{gap:8px}
  #forgotBtn{margin-bottom:10px}
  #login .hint{margin-top:10px}
}

/* ---- fileira do topo ---- */
/* Uma fileira só: bandeira à esquerda, tema e Hub à direita. O seletor de
   idioma é injetado pelo i18n DENTRO da .login-box (insertAdjacentHTML
   afterbegin, i18n.js) — `fixed` tira ele do fluxo do pôster sem que o JS
   precise saber que ele mudou de lugar. */
#login .lang-dd{position:fixed;top:calc(env(safe-area-inset-top,0px) + 12px);left:14px;
  z-index:60;margin:0}
.porta-top{position:fixed;top:calc(env(safe-area-inset-top,0px) + 12px);right:14px;z-index:60;
  display:flex;align-items:center;gap:8px}
.top-hub{font-size:11.5px;font-weight:700;color:var(--mute-2);padding:6px 10px;border-radius:8px}
.top-hub:hover{color:var(--white)}
/* R2 (G2h): alternador de tema no topo do login — 32px de caixa, 44px de mira
   (mesmo truque do .btn.sm), antes de existir qualquer sessão. */
.top-tema{position:relative;width:32px;height:32px;border-radius:99px;
  border:1px solid var(--hair);color:var(--mute);display:grid;place-items:center;background:none}
.top-tema svg{width:17px;height:17px}
.top-tema:hover{color:var(--white);border-color:var(--hair)}
.top-tema::after{content:'';position:absolute;inset:-6px}

/* ---- entrada ---- */
/* A porta se monta de cima para baixo uma vez só: marca, pôster, formulário,
   nota. É hierarquia, não enfeite — diz em que ordem ler. Não se repete e não
   fica em laço. */
@media (prefers-reduced-motion:no-preference){
  .login-box > *{animation:porta-in .5s cubic-bezier(.16,1,.3,1) backwards}
  /* o palco entra ANTES do texto e só em opacidade: a cena já está
     girando quando aparece, e deslizá-la junto com o resto faria a roda
     chegar torta na primeira volta. */
  .porta-palco{animation:porta-fade .62s ease backwards}
  .poster{animation:porta-in .5s cubic-bezier(.16,1,.3,1) backwards;animation-delay:.04s}
  .login-box > form{animation-delay:.12s}
  .login-box > .hint{animation-delay:.18s}
}
@keyframes porta-in{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@keyframes porta-fade{from{opacity:0}to{opacity:1}}
@media (prefers-reduced-motion:reduce){
  .pb-pontos > i,.pb-aura,.porta-palco,.poster,.login-box > *{animation:none!important}
}

/* ---------- shell ---------- */
#app{min-height:100dvh;display:flex;flex-direction:column}
/* O header e a tabbar tinham backdrop-filter LIGADO O TEMPO TODO. Sob 92%/96%
   de preto o borrão não aparecia — mas obrigava o compositor a reprocessar duas
   faixas de largura total a cada quadro em que qualquer coisa se mexia (arrasto
   do card, saída do swipe, giro do Swapou!, rolagem). Trocado por um preto um
   fio mais fechado: mesmo desenho, sem o imposto por quadro. */
header.bar{position:sticky;top:0;z-index:40;background:var(--chrome);
  padding-top:env(safe-area-inset-top,0px);
  border-bottom:1px solid transparent;transition:border-color .2s}
/* v22 (UX2-3): o traço do header só existe quando há conteúdo passando por
   baixo — acende com scrollY>8 (core.js › boot) e apaga no topo. Threshold
   único, sem histerese. */
header.bar.lift{border-bottom-color:var(--hair-2)}
header.bar .row-h{display:flex;align-items:center;gap:8px;padding:10px 0;flex-wrap:nowrap}
header .wm{font-size:19px}
.hpill{position:relative;display:inline-flex;align-items:center;gap:5px;border:1px solid var(--hair);border-radius:var(--r-pill);
  padding:5px 10px;font-size:11px;font-weight:800;white-space:nowrap;flex:none;font-family:var(--mono)}
.hpill[role="button"]::after{content:'';position:absolute;inset:-9px 0}
.hpill .ic{width:13px;height:13px;vertical-align:0}
.hpill [data-icon]{display:inline-flex;align-items:center}
.hpill .k{font-size:10px;letter-spacing:.7px;text-transform:uppercase;color:var(--mute-2);font-family:var(--sans)}
.hpill.plan-premium{color:var(--gold);border-color:rgba(245,194,75,.5)}
.hpill.plan-business{color:var(--teal);border-color:rgba(47,211,165,.5)}
.hpill.plan-basic{color:var(--mute)}
.spacer{flex:1}
main{flex:1;padding:12px 0 calc(var(--tabh) + 30px + var(--tab-safe))}
nav.tabbar{position:fixed;left:0;right:0;bottom:0;z-index:45;background:var(--chrome-2);
  border-top:1px solid var(--hair-2);padding-bottom:var(--tab-safe)}
nav.tabbar .row-t{display:grid;padding:0}
nav.tabbar button{position:relative;height:var(--tabh);display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:4px;font-size:10px;font-weight:800;letter-spacing:.3px;color:var(--mute-2);
  min-width:0;max-width:100%;overflow:hidden;white-space:nowrap}
nav.tabbar button .g{font-size:20px;line-height:1;display:grid;place-items:center}
nav.tabbar button.on{color:var(--pink)}
nav.tabbar .tb-ind{position:absolute;top:0;left:0;height:2px;background:var(--pink);pointer-events:none;
  width:calc(56% / var(--n,5));transform:translateX(calc((var(--i,0) + .22) * 100% / .56));
  transition:transform .18s ease-out}
nav.tabbar .tb-ind.off{opacity:0}
/* O numeral aqui é o texto mais hostil do sistema: 9px, peso 800, dentro de um
   selo de 15px. Em branco sobre --pink dava 3,49:1 — a mesma tinta escura das
   .btn.solid/.tag.pink leva a 5,93:1 e é o que decide se "3" ou "8" some. */
nav.tabbar .bdg{position:absolute;top:9px;right:calc(50% - 20px);min-width:16px;height:16px;border-radius:var(--r-pill);
  background:var(--pink);color:#0A0006;font-size:10px;font-weight:800;display:grid;place-items:center;padding:0 4px;
  font-family:var(--mono)}
/* O selo só se mexe quando a CONTAGEM SOBE — chegou coisa nova esperando por
   você. A barra é reescrita a cada troca de tela, e animar em toda reescrita
   transformaria o aviso em enfeite (o core guarda a última contagem por aba
   justamente para saber a diferença). */
@keyframes bdgUp{
  0%{transform:scale(.6);opacity:0}
  55%{transform:scale(1.18);opacity:1}
  100%{transform:scale(1);opacity:1}
}
nav.tabbar .bdg.up{animation:bdgUp .26s cubic-bezier(.2,.9,.25,1) both}

/* ---------- segmento de superfície ----------
   Duas telas que respondem à mesma pergunta viradas para lados opostos — o
   Radar mostra o que a rede OFERECE, o Reverso o que ela PROCURA. Uma delas
   deixou a barra para a aba de Swaps entrar; este segmento é o preço disso:
   um toque, sempre no mesmo lugar, no topo das duas. */
.nav-seg{display:flex;gap:4px;padding:3px;margin:0 0 12px;border:1px solid var(--hair);
  border-radius:var(--r-pill);background:var(--ink-2)}
.nav-seg > *{flex:1 1 0;min-width:0;display:flex;align-items:center;justify-content:center;gap:6px;
  height:34px;border-radius:var(--r-pill);font-size:12px;font-weight:800;letter-spacing:.3px;color:var(--mute);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  transition:background .16s ease,color .16s ease}
.nav-seg > .on{background:var(--ink-4);color:var(--white)}
.nav-seg .ic{width:15px;height:15px;flex:none}
@media (max-width:340px){.nav-seg .ic{display:none}}
@media (prefers-reduced-motion:reduce){.nav-seg > *{transition:none}}
html.no-anim nav.tabbar .bdg.up{animation:none}
.view-head{margin:4px 0 12px}
.view-head h1{font-family:var(--display);text-transform:uppercase;font-size:30px;letter-spacing:0;line-height:1.1;
  font-weight:400}
.view-head p{color:var(--mute);font-size:13px;margin-top:5px}
.back{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:800;color:var(--mute);
  letter-spacing:.6px;text-transform:uppercase;margin-bottom:10px}

/* ---------- estados ---------- */
.empty{text-align:center;padding:38px 20px}
.empty .ico{margin:0 auto 14px}
.empty h3{font-family:var(--display);text-transform:uppercase;font-size:22px;line-height:1.1;letter-spacing:.015em;
  font-weight:400;margin-bottom:7px}
/* v22 (UX2-9): vazio compacto para superfícies pequenas (dropdown do sino). */
.empty.tight{padding:22px 16px}
.empty p{color:var(--mute);font-size:13.5px;max-width:300px;margin:0 auto}
.empty .btn{margin-top:16px}
/* Mercado abrindo (Deslizar, Radar, Comunidade, Reverso): o vazio de um país
   que ainda não tem empresa nenhuma, que é o oposto do vazio por filtro. O
   único movimento é a ENTRADA do estado — 180 ms de subida para o olho pousar
   no que mudou. Não pulsa, não repete: é notícia de mercado começando, não
   festa. */
.mkt-open{animation:mktIn .18s cubic-bezier(.2,.9,.25,1) both}
@keyframes mktIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}
@media (prefers-reduced-motion:reduce){.mkt-open{animation:none}}
html.no-anim .mkt-open{animation:none!important}
.skel{border-radius:var(--r-md);background:linear-gradient(100deg,rgba(255,255,255,.05) 30%,rgba(255,255,255,.1) 50%,
  rgba(255,255,255,.05) 70%);background-size:220% 100%;animation:sh 1.3s linear infinite}
@keyframes sh{from{background-position:120% 0}to{background-position:-20% 0}}

/* ---------- folha / modal ---------- */
#modalRoot{position:fixed;inset:0;z-index:70;pointer-events:none}
#modalRoot.on{pointer-events:auto}
.ovl{position:absolute;inset:0;background:rgba(0,0,0,.72);backdrop-filter:blur(3px);opacity:0;transition:opacity .2s}
#modalRoot.on .ovl{opacity:1}
.sheet{position:absolute;left:0;right:0;bottom:0;display:flex;flex-direction:column;max-height:92dvh;
  background:var(--ink-2);border-top:1px solid var(--hair);border-radius:var(--r-xl) var(--r-xl) 0 0;
  box-shadow:var(--shadow-sheet);
  /* v22 (UX1-5): a folha ENTRA de baixo de verdade — min(100%,60vh) em vez de
     um empurrão de 18px; folha alta pede ~300ms para o olho acompanhar. */
  transform:translateY(min(100%,60vh));opacity:0;transition:transform .3s cubic-bezier(.2,.9,.25,1),opacity .2s}
#modalRoot.on .sheet{transform:translateY(0);opacity:1}
.mdl{position:absolute;left:50%;top:50%;width:min(94vw,430px);max-height:88dvh;display:flex;flex-direction:column;
  /* v22 (UX1-5): entrada por translateY(28px) — mesmo vocabulário da folha. */
  transform:translate(-50%,-50%) translateY(28px) scale(.97);opacity:0;background:var(--ink-2);border:1px solid var(--hair);
  box-shadow:var(--shadow-mdl);
  border-radius:var(--r-xl);transition:transform .22s cubic-bezier(.2,.9,.25,1),opacity .2s}
#modalRoot.on .mdl{transform:translate(-50%,-50%) scale(1);opacity:1}
.grab{width:36px;height:4px;border-radius:var(--r-pill);background:var(--hair);margin:9px auto 2px;flex:none}
.sheet .grab,.sheet .mdl-head{touch-action:none}
.mdl-head{display:flex;align-items:center;gap:10px;padding:12px 16px;border-bottom:1px solid var(--hair-2);flex:none}
.mdl-head h3{font-family:var(--display);text-transform:uppercase;font-size:20px;letter-spacing:.015em;line-height:1.1;
  font-weight:400}
.mdl-head .x{margin:-6px -6px -6px auto;width:44px;height:44px;border-radius:12px;border:1px solid var(--hair);
  color:var(--mute);display:flex;align-items:center;justify-content:center;flex:none}
.mdl-head .x:active{background:var(--press)}
.mdl-head .x .ic{width:18px;height:18px;vertical-align:0}
.mdl-body{padding:16px;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;flex:1}
.mdl-foot{padding:12px 16px calc(12px + var(--safe-b));border-top:1px solid var(--hair-2);flex:none;
  background:var(--ink-2)}

/* ---------- toasts ---------- */
.toasts{position:fixed;left:0;right:0;bottom:calc(var(--tabh) + 14px + var(--safe-b));z-index:80;display:flex;
  flex-direction:column;align-items:center;gap:8px;pointer-events:none;padding:0 16px}
/* Modal aberto: o toast sobe para o topo. Ancorado no rodapé ele pousava exatamente
   sobre o CTA do .mdl-foot (toasts z-80 fica ACIMA do #modalRoot z-70) — o aviso de
   boas-vindas cobria o botão do modal pós-cadastro. #modalRoot precede .toasts no
   index.html, então o irmão-geral (~) enxerga o estado .on. */
/* F10 (rodada 1): no topo o toast desce para DEBAIXO do header (~54px) — em
   cima dele cobria sino/plano/saldo e ficava ilegível sobre o chrome. */
#modalRoot.on ~ .toasts{bottom:auto;top:calc(62px + env(safe-area-inset-top,0px))}
/* No deck a âncora de rodapé pousava exatamente sobre a barra Passar/Tenho
   interesse — o toast confirmava a decisão COBRINDO os botões dela. Com o deck
   aberto (body[data-view], core.js go()) o aviso sobe para o topo. */
body[data-view="dossie"] .toasts{bottom:auto;top:calc(62px + env(safe-area-inset-top,0px))}
/* R3 (H13): na conversa a âncora de rodapé pousava sobre o campo "Escreva…" —
   o toast sobe para debaixo do header, como no deck. */
body[data-view="chat"] .toasts{bottom:auto;top:calc(62px + env(safe-area-inset-top,0px))}
/* O #131316 era um cinza órfão — não existia em lugar nenhum do sistema e não
   acompanhava troca de tema. --ink-3 é o mesmo degrau de superfície elevada
   usado pelos campos, e o raio passa a ser o do papel (bloco curto). */
.toast{max-width:420px;background:var(--ink-3);border:1px solid var(--hair);border-radius:var(--r-md);padding:11px 14px;
  font-size:13px;font-weight:600;animation:tin .2s cubic-bezier(.2,.9,.25,1);display:flex;align-items:flex-start;
  gap:9px}
.toast .ic{width:16px;height:16px;margin-top:1px;vertical-align:0}
.toast.ok{border-color:rgba(47,211,165,.5);color:#BFF3E5}
.toast.err{border-color:rgba(255,45,143,.55);color:#FFC2DC}
.toast.ai{border-color:rgba(155,140,255,.55);color:#DCD6FF}
@keyframes tin{from{transform:translateY(8px);opacity:0}to{transform:translateY(0);opacity:1}}

/* ---------- planos ---------- */
.plan-lock{display:flex;align-items:flex-start;gap:11px;border:1px solid rgba(245,194,75,.35);border-radius:var(--r-md);
  padding:12px 13px;font-size:12.5px;color:var(--mute)}
.plan-lock b{color:var(--white)}
.plan-card{border:1px solid var(--hair);border-radius:16px;padding:14px}
.plan-card.on{border-color:rgba(245,194,75,.55)}
.plan-card .top{display:flex;align-items:baseline;gap:8px}
.plan-card .top .nm{font-family:var(--display);text-transform:uppercase;font-size:22px;line-height:1.1;
  letter-spacing:.015em;font-weight:400}
.plan-card .top .pr{margin-left:auto;font-family:var(--mono);font-size:12.5px;color:var(--mute)}
.plan-perks{list-style:none;display:grid;gap:6px;margin:10px 0}
.plan-perks li{position:relative;padding-left:17px;font-size:12.5px;color:var(--mute)}
.plan-perks li::before{content:"→";position:absolute;left:0;color:var(--pink);font-weight:800}
.trial{border:1px dashed var(--hair);border-radius:12px;padding:11px 12px;font-size:12.5px;color:var(--mute)}
.trial b{color:var(--white)}

@media (max-width:400px){
  header .wm{display:none}
  .view-head h1{font-size:28px}
}
@media (prefers-reduced-motion:reduce){
  *{animation-duration:.001s!important;animation-iteration-count:1!important;transition-duration:.05s!important}
  /* v22 (UX1-9): superfícies que ENTRAM não teleportam — trocam o deslize por
     um cross-fade de 160ms. Opacity-só: transform congelado. */
  .ovl,.sheet,.mdl,.toast,.dk-scrim,.dk-sheet{transition-duration:.16s!important;
    transition-property:opacity!important;transform:none!important}
  nav.tabbar .tb-ind{transition:none}
  .disc[open] > summary + *{animation:none}
  .otto-read{animation:none}
}
/* v22 (UX2-4b): GÊMEO de html.hi-con abaixo — quem pede mais contraste ao
   SISTEMA recebe o mesmo tratamento sem abrir Configurações. EDITAR JUNTO. */
/* R2 (G2g): o boot agora carimba data-tema="escuro" como padrão explícito —
   o seletor deixou de ser "sem atributo" e passou a ser "não-claro", senão
   este bloco nunca mais valeria para ninguém. */
@media (prefers-contrast:more){
  html:not([data-tema="claro"]):not([data-tema="auto"]){
    --hair:rgba(255,255,255,.32);
    --hair-2:rgba(255,255,255,.2);
    --mute:#D8D0D6;
    --mute-2:#BDB3BC;
  }
  html:not([data-tema="claro"]):not([data-tema="auto"]) .card,
  html:not([data-tema="claro"]):not([data-tema="auto"]) .cf-list,
  html:not([data-tema="claro"]):not([data-tema="auto"]) .cm-post{border-width:1.5px}
}
/* v22 (UX2-4b): sem transparência quando o sistema pede opacidade. */
@media (prefers-reduced-transparency:reduce){
  .ovl{backdrop-filter:none;background:rgba(0,0,0,.85)}
}

/* ==========================================================================
   v21 — preferências de aparência com efeito real
   O que a tela de Configurações grava em /api/me/settings vira atributo e
   classe no <html> (mod-perfil.js › aplicaAparencia). Daqui para baixo é o
   que cada opção MUDA de verdade — nenhuma delas é enfeite.
   ========================================================================== */

/* Texto maior: a base sobe e tudo que é medido em rem/em acompanha; o que é
   px fixo (números monoespaçados, selos) fica, para a grade não estourar. */
html.txt-lg body{font-size:16.5px}
html.txt-lg .hint,html.txt-lg .sub{font-size:14px}
html.txt-lg .lbl{font-size:11.5px}
/* v22 (UX2-6): quem consome os tokens de corpo (ui.css, mod-otto,
   mod-conversas) escala junto re-declarando só os tokens. */
html.txt-lg{--fs-body:16.5px;--fs-sub:14px;--fs-hint:14px;--fs-k:11.5px}
/* R2 (G9): os tamanhos PINADOS dos módulos entram na régua do texto maior —
   inclusive todo valor em R$, que estava fora dela. A migração completa por
   token fica para a v23; aqui sobem os textos informativos de 9,5–13px que a
   auditoria mediu fora da escala. */
html.txt-lg .tag{font-size:11.5px}
html.txt-lg .row .s{font-size:14px}
html.txt-lg .row .t{font-size:16px}
html.txt-lg .row .r .v{font-size:15px}
html.txt-lg .row .r .k{font-size:11px}
html.txt-lg .pay-amt{font-size:22px}
html.txt-lg .pay-line{font-size:14px}
html.txt-lg .plan-note{font-size:13.5px}
html.txt-lg .plan-perks li,html.txt-lg .plan-card .why{font-size:14px}
/* deck: rótulos e o par que decide o swipe */
html.txt-lg .dk-nm b,html.txt-lg .dk-nm i{font-size:14px}
html.txt-lg .dk-sb{font-size:14.5px}
html.txt-lg .dk-deal .w{font-size:14px}
html.txt-lg .dk-deal .v{font-size:18px}
html.txt-lg .dk-sub{font-size:13px}
html.txt-lg .dk-shead .vl b{font-size:17px}
html.txt-lg .dk-shead .vl span{font-size:11.5px}
html.txt-lg .dk-act .lb{font-size:14px}
/* mesa/mesa3/reverso/radar: linhas informativas pequenas */
html.txt-lg .m3-leg,html.txt-lg .m3-legs summary{font-size:14px}
html.txt-lg .m3-sys{font-size:13px}
html.txt-lg .m3-bub{font-size:15px}
html.txt-lg .cv-kv{font-size:14px}
html.txt-lg .cv-note{font-size:13.5px}
html.txt-lg .rd-meta{font-size:13.5px}
html.txt-lg .kpi .v.mono{font-size:24px}

/* Alto contraste: as hairlines saem da transparência e o texto secundário
   deixa de ser cinza-sobre-preto.
   v22 (UX2-4b): GÊMEO do bloco @media (prefers-contrast:more) acima — quem
   editar um, edita o outro. */
html.hi-con{
  --hair:rgba(255,255,255,.32);
  --hair-2:rgba(255,255,255,.2);
  --mute:#D8D0D6;
  --mute-2:#BDB3BC;
}
html.hi-con .card,html.hi-con .cf-list,html.hi-con .cm-post{border-width:1.5px}

/* Menos animações: o mesmo corte de prefers-reduced-motion, mas por escolha
   explícita do usuário — inclusive o carimbo do swipe e o giro do Swapou!. */
html.no-anim *{
  animation-duration:.001s!important;
  animation-iteration-count:1!important;
  transition-duration:.05s!important;
}
html.no-anim .dk-stamp .mk,html.no-anim .cv-rig,html.no-anim .cv-mc,
html.no-anim .cv-mark{transition:none!important}
/* v22 (UX1-9): espelho do cross-fade do prefers-reduced-motion — superfícies
   entram por opacidade, 160ms, transform congelado. */
html.no-anim .ovl,html.no-anim .sheet,html.no-anim .mdl,html.no-anim .toast,
html.no-anim .dk-scrim,html.no-anim .dk-sheet{transition-duration:.16s!important;
  transition-property:opacity!important;transform:none!important}
/* Mesma regra vale para o retorno ao dedo que a rodada de limpeza acrescentou:
   a lavagem de cor na borda do card e o card de trás subindo com `--f` são
   movimento, e movimento aqui está desligado por escolha do usuário. A mola do
   snap-back já cai no corte de transition acima. */
html.no-anim .dk-card[data-i="0"][data-dir]::after{display:none!important}
html.no-anim .dk-card[data-i="1"]{transform:translateY(10px) scale(.968)!important;opacity:.46!important}
/* A celebração do fechamento da permuta é movimento com propósito, mas continua
   sendo movimento: com "menos animações" a faixa aparece pronta e o anel some. */
html.no-anim .mesa-cel{animation:none!important}
html.no-anim .mesa-cel .cel-ring{display:none!important}
/* a revelação progressiva continua funcionando sem o movimento de entrada */
html.no-anim .disc[open] > summary + *{animation:none!important}
/* a leitura do Otto aparece pronta: o bloco é conteúdo, a subida é só o rastro */
html.no-anim .otto-read{animation:none!important}
/* sem movimento não há o que compositar: nenhuma camada de GPU fica reservada */
html.no-anim .cv-cel.hot .cv-rig,html.no-anim .cv-cel.hot .cv-mc,
html.no-anim .cv-cel.hot .cv-mark,html.no-anim .dk-card .dk-stamp,
html.no-anim .dk-card .dk-stamp .mk{will-change:auto!important}

/* Tema claro: o sistema é todo feito de tokens, então trocar o tema é trocar
   os tokens — nenhuma regra de componente precisa saber que existe tema. */
html[data-tema="claro"]{
  --ink:#F6F4F6; --ink-2:#FFFFFF; --ink-3:#F0EDF1; --ink-4:#E4DFE6;
  --white:#141116; --mute:#5C5360; --mute-2:#6E6474;
  --hair:rgba(20,17,22,.14); --hair-2:rgba(20,17,22,.07);
  --press:#FCE7F1; --pink-dim:rgba(255,45,143,.1);
  /* v22: chrome claro de verdade (UX2-1), violeta que passa AA sobre #F6F4F6
     (ART1-3: #5B4BC4 dá 5,7:1) e sombras de papel no lugar do highlight. */
  --chrome:#F6F4F6; --chrome-2:#F6F4F6; --glass:rgba(246,244,246,.92);
  --violet:#5B4BC4;
  --danger:#C62E38;   /* F5: vermelho AA sobre superfícies claras */
  --green:#17803D;    /* F4: verde AA sobre superfícies claras */
  /* R2 (G2b): teal e âmbar ESCUROS no claro — os originais davam 1,9:1 e
     1,65:1 sobre papel. #0B6B54 = 5,6:1 e #7A5D10 = 5,3:1 sobre --ink-3;
     todo selo/estimado/ok que fala por token herda a correção. */
  --teal:#0B6B54; --gold:#7A5D10;
  --shadow-card:0 1px 2px rgba(20,17,22,.05);
  --shadow-sheet:0 -12px 36px rgba(20,17,22,.18);
  --shadow-mdl:0 18px 48px rgba(20,17,22,.2);
}
html[data-tema="claro"] body{background:var(--ink);color:var(--white)}
html[data-tema="claro"] .cm-post,html[data-tema="claro"] .card,
html[data-tema="claro"] .cf-list,html[data-tema="claro"] .pf-head{box-shadow:var(--shadow-card)}
html[data-tema="claro"] ::selection{background:var(--pink);color:#fff}
/* R2 (G2b): o visto de verificada usa --teal de FUNDO com tinta escura — com o
   teal escurecido no claro, a tinta vira branca para o check não sumir. */
html[data-tema="claro"] .vf{color:#fff}
/* R2 (G2c): tinta dos toasts no claro — os tons pastel do escuro (#BFF3E5,
   #FFC2DC, #DCD6FF) somem sobre --ink-3 claro. Valores AA medidos. */
html[data-tema="claro"] .toast.ok{color:#0B5C41}
html[data-tema="claro"] .toast.err{color:#A3213B}
/* 26/ago: a .err NUNCA teve versao clara. O rosa pastel #FFC2DC sobre papel
   da ~1,2:1 — "Sessao expirada. Entre novamente." aparecia em branco sobre
   branco na porta do login, e o mesmo valia para toda recusa de formulario
   do app no tema claro. Tinta e borda passam a sair do vermelho de erro que
   o tema ja define (--danger #C62E38), como manda a F5 da rodada 1. */
html[data-tema="claro"] .err{color:#A3213B;background:rgba(198,46,56,.08);
  border-color:rgba(198,46,56,.38)}
html[data-tema="claro"] .toast.ai{color:var(--violet)}
/* R2 (G2f): aviso âmbar (folha de pagamento/proposta) legível no claro. */
html[data-tema="claro"] .pay-box.warn{color:#6B5310}
html[data-tema="claro"] .pay-box.warn b{color:#6B5310}
html[data-tema="claro"] .pay-st.bad{color:#A3213B}
/* R2 (G2a): dezenas de frases do i18n carregam color:#EDEDF2 INLINE (a cor faz
   parte da chave de tradução e não pode mudar sem órfão). No claro esse quase
   branco dá 1,17:1 — o seletor de atributo devolve a tinta do tema por cima
   do estilo inline. */
html[data-tema="claro"] [style*="#EDEDF2"]{color:var(--white)!important}
@media (prefers-color-scheme:light){
  html[data-tema="auto"]{
    --ink:#F6F4F6; --ink-2:#FFFFFF; --ink-3:#F0EDF1; --ink-4:#E4DFE6;
    --white:#141116; --mute:#5C5360; --mute-2:#6E6474;
    --hair:rgba(20,17,22,.14); --hair-2:rgba(20,17,22,.07);
    --press:#FCE7F1; --pink-dim:rgba(255,45,143,.1);
    /* v22: espelho do bloco claro explícito acima — editar junto. */
    --chrome:#F6F4F6; --chrome-2:#F6F4F6; --glass:rgba(246,244,246,.92);
    --violet:#5B4BC4;
    --danger:#C62E38;   /* F5: espelho do claro explícito */
    --green:#17803D;    /* F4: espelho do claro explícito */
    --teal:#0B6B54; --gold:#7A5D10;   /* R2 (G2b): espelho do claro */
    --shadow-card:0 1px 2px rgba(20,17,22,.05);
    --shadow-sheet:0 -12px 36px rgba(20,17,22,.18);
    --shadow-mdl:0 18px 48px rgba(20,17,22,.2);
  }
  html[data-tema="auto"] body{background:var(--ink);color:var(--white)}
  /* R2 (G2a–f): espelho das correções de tinta do claro explícito. */
  html[data-tema="auto"] .vf{color:#fff}
  html[data-tema="auto"] .toast.ok{color:#0B5C41}
  html[data-tema="auto"] .toast.err{color:#A3213B}
  html[data-tema="auto"] .toast.ai{color:var(--violet)}
  html[data-tema="auto"] .pay-box.warn{color:#6B5310}
  html[data-tema="auto"] .pay-box.warn b{color:#6B5310}
  html[data-tema="auto"] .pay-st.bad{color:#A3213B}
  html[data-tema="auto"] [style*="#EDEDF2"]{color:var(--white)!important}
}

/* ------------------------------------------------- bandeiras de idioma ----
   O seletor da primeira interação (login e 1º passo do cadastro): um botão
   com a bandeira da porta atual; clicar desce o dropdown com os mercados. */
.lang-dd{position:relative;display:inline-block;margin:0 0 14px}
.ldd-btn{display:flex;align-items:center;gap:6px;padding:4px 8px;border-radius:6px;
  border:1px solid rgba(255,255,255,.16);background:rgba(255,255,255,.05);
  color:var(--mute-2,#9a9aa2);cursor:pointer;line-height:0}
.ldd-btn:hover{border-color:rgba(255,255,255,.45)}
.ldd-flag svg{width:24px;height:16px;border-radius:2px;display:block}
.ldd-car{width:10px;height:6px;flex:none}
.ldd-menu{position:absolute;top:calc(100% + 6px);left:0;z-index:80;min-width:216px;
  padding:6px;border-radius:var(--r-sm);border:1px solid rgba(255,255,255,.12);
  background:var(--ink-3);box-shadow:0 14px 36px rgba(0,0,0,.55)}
.ldd-l{display:block;font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;
  color:var(--mute-2,#9a9aa2);padding:4px 8px 6px}
.ldd-i{display:flex;align-items:center;gap:9px;width:100%;padding:7px 8px;border:0;
  border-radius:6px;background:none;color:var(--white,#fff);cursor:pointer;
  font:inherit;font-size:13.5px;text-align:left}
.ldd-i svg{width:22px;height:15px;border-radius:2px;flex:none}
.ldd-i:hover{background:rgba(255,255,255,.07)}
.ldd-i.on{background:var(--pink-dim,rgba(255,45,143,.13))}

/* ==========================================================================
   Foco visível — quem navega por teclado precisa saber ONDE está
   O app inteiro rodava sem um único :focus-visible: com o outline nativo
   apagado pelo reset, a tecla Tab movia um cursor invisível. É a mesma regra
   já em pé na landing (site/index.html), agora no app, para os dois lados da
   porta responderem igual.
   :where() zera a especificidade: qualquer componente pode redesenhar o próprio
   foco sem precisar de !important, e nada aqui vence uma regra de módulo.
   O par :focus:not(:focus-visible) existe para o anel NÃO vazar no toque — o
   dedo não precisa de mira, e sem isso todo botão tocado ficaria contornado. */
:where(button,a,summary,input,select,textarea,[tabindex]):focus-visible{
  outline:2px solid var(--pink);outline-offset:3px;border-radius:inherit}
:focus:not(:focus-visible){outline:none}

/* ==========================================================================
   Alvo de toque de 44px sem mexer no desenho
   .btn.sm (38px), .btn.xs (32px) e o resumo do .disc (36px) são pequenos DE
   PROPÓSITO — são ações secundárias e devem parecer secundárias. O que não pode
   ser pequeno é a área que o dedo acerta. O sistema já resolve isso na .hpill
   do cabeçalho com um pseudo transparente que estica a área além da caixa; aqui
   a mesma ideia vira regra geral: a caixa continua com o tamanho desenhado, a
   MIRA cresce até 44px. Nada muda de aparência, nada muda de posição.
   inset:calc((44px - 100%) / -2) 0 — a porcentagem vertical mede a altura do
   próprio elemento, então a sobra é dividida igualmente para cima e para baixo.
   O ::before no summary (e não ::after) é obrigatório: o ::after dele já é o
   +/− da revelação progressiva. */
.btn.xs,.btn.sm,.disc > summary{position:relative}
.btn.xs::after,.btn.sm::after,.disc > summary::before{
  content:'';position:absolute;inset:calc((44px - 100%) / -2) 0}
