/* app.css — layout e componentes da bancada ui/v2. ZERO cor literal: tudo por var() de
 * tokens.css (o teste `test_tokens_css_e_o_unico_lugar_com_cor` reprova o contrário).
 *
 * BANCADA 25/08/2026 (identidade V1 aprovada, FOLHA-VISUAL §F1). Três mudanças estruturais em
 * cima do arquivo herdado da v1, todas com defeito nomeado na MATRIZ-E2:
 *   1. Fontes self-host (Fraunces + Hanken Grotesk) declaradas logo abaixo — a maquete usava
 *      Google Fonts como mock e o produto tem decisão registrada de "sem fonte de rede".
 *   2. Base 14px FIXA: o `body` nascia 15px e ENCOLHIA para 14px no desktop, e mais 57
 *      declarações de `font-size` reduziam componente por componente dentro das media queries
 *      `min-width`. Todas removidas — o desktop não encolhe mais.
 *   3. Bloco `═ V2 ═` no fim do arquivo: chrome colapsável + componentes da maquete V1,
 *      escopados em `.v2` para não vestir tela herdada por acidente.
 */

/* ─────────────────────────── fontes self-host (sem rede) ───────────────────────────
 * woff2 VARIÁVEIS: um arquivo por subset cobre a faixa inteira de peso. Procedência,
 * versão, tamanho e sha256 de cada arquivo em `static/fonts/ORIGEM.md`. */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/fraunces-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/fraunces-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../fonts/hanken-grotesk-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../fonts/hanken-grotesk-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* (herança da v1 — o comentário original do arquivo)
 * app.css — layout e componentes da UI v2. ZERO cor literal: tudo por var() de tokens.css.
 * Esqueleto lido de starlette-admin/templates/layout.html (page → aside.navbar-vertical →
 * page-wrapper), densidade e gramática visual do deck de referência (chapéu navy com filete
 * dourado, eyebrow em versalete espaçado, número-herói em tinta escura, cor só no marcador).
 * Sem Tailwind, sem CDN, sem fonte de rede.
 *
 * V2-MOBILE — 24/08/2026 (bronca do dono: "a versão mobile tá um lixo"). O arquivo era
 * desktop-first com UMA media query (1180px) e tudo tinha sido julgado só em 1536: a barra navy
 * de 236px comia 60% de uma tela de 390 e sobravam ~117px de miolo — 8 das 9 telas rolavam de
 * lado (medido, tabela em IMPLEMENTACAO-V2-MOBILE.md §2).
 * Agora é MOBILE-FIRST: o que está fora de media query é a regra do celular; o desktop volta
 * inteiro em `@media (min-width: 1024px)` e a grade larga em `(min-width: 1180px)`.
 * Degraus: 640px (cartão → tabela) · 1024px (gaveta → barra fixa) · 1180px (grade de 4).
 */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }
body {
  font-family: var(--sans); font-size: 14px; line-height: 1.45;
  color: var(--ink); background: var(--bg);
  -webkit-font-smoothing: antialiased;
  padding-top: var(--alt-topbar);          /* a topbar de celular é fixa */
}
a { color: var(--ink); text-underline-offset: 2px; }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible,
summary:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }
.sidebar a:focus-visible, .sidebar button:focus-visible { outline-color: var(--ouro); }
/* nada de mídia estoura a coluna */
img, svg, video, canvas, iframe { max-width: 100%; }
/* Ícone do sprite (`class="ic"`) sem regra de local específico caía no tamanho intrínseco do
 * SVG (300×150 — o defeito "ícone gigante" de 25/08, `/biblioteca` sem contenção). Piso de
 * 20px cobre todo uso não escopado; seletor mais específico (`.item-nav .ic` etc.) continua
 * vencendo por especificidade normal do CSS. */
.ic { width: 20px; height: 20px; flex: none; }

/* eyebrow: o rótulo em versalete espaçado que o deck usa em toda seção */
.eyebrow { font-family: var(--mono); font-size: 10.5px; letter-spacing: .19em;
  text-transform: uppercase; color: var(--ouro-ink); }

/* ============================================== chrome de celular: topbar + véu + gaveta */
.topbar { position: fixed; top: 0; left: 0; right: 0; z-index: 40; height: var(--alt-topbar);
  display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 0 12px;
  background: linear-gradient(180deg, var(--nav) 0%, var(--nav-2) 100%);
  border-bottom: 2px solid var(--ouro); }
.topbar-marca { display: flex; align-items: center; min-height: 44px; padding: 0 2px; }
.topbar-marca img { display: block; height: 19px; width: auto; }
.botao-menu { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 14px;
  background: transparent; color: var(--nav-ink); border: 1px solid var(--nav-line-forte);
  border-radius: var(--raio); font: inherit; font-size: 14px; cursor: pointer; }
.botao-menu:hover, .botao-menu[aria-expanded="true"] { background: var(--nav-3); border-color: var(--ouro); }
.botao-menu .barras { display: inline-grid; gap: 3px; }
.botao-menu .barras i { display: block; width: 17px; height: 2px; background: var(--nav-ink); }
.veu { position: fixed; inset: 0; z-index: 45; background: var(--backdrop); }
.veu[hidden] { display: none; }

/* ================================================================= esqueleto */
.page { display: block; min-height: 100vh; }

/* ---------- barra lateral navy: no celular ela é GAVETA (fora do fluxo) ---------- */
.sidebar, aside.navbar-vertical {
  position: fixed; top: 0; left: 0; bottom: 0; z-index: 50;
  width: min(86vw, 306px); height: 100vh;
  background: linear-gradient(180deg, var(--nav) 0%, var(--nav-2) 100%);
  color: var(--nav-ink); border-right: 1px solid var(--nav);
  display: flex; flex-direction: column;
  transform: translateX(-100%); visibility: hidden;
  transition: transform .18s ease-out, visibility .18s;
}
body.menu-aberto .sidebar, body.menu-aberto aside.navbar-vertical {
  transform: none; visibility: visible; box-shadow: var(--sombra-modal);
}
@media (prefers-reduced-motion: reduce) { .sidebar, aside.navbar-vertical { transition: none; } }
.sidebar nav { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.sidebar header { padding: 14px 14px 12px; border-bottom: 2px solid var(--ouro); }
.sidebar section { padding: 6px 10px 14px; overflow-y: auto; flex: 1; min-height: 0;
  -webkit-overflow-scrolling: touch; }
.sidebar footer { padding: 10px 14px; border-top: 1px solid var(--nav-line); }
.sidebar .marca { position: relative; padding-right: 96px; }
/* link vira a marca clicável sem mudar o layout: mesmo box block que os filhos já tinham */
.sidebar .marca-link { display: block; color: inherit; text-decoration: none; }
.sidebar .marca-img { display: block; height: 21px; width: auto; }
.sidebar .marca small { display: block; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .19em; text-transform: uppercase; color: var(--ouro); margin-top: 7px; }
.fechar-menu { position: absolute; top: -4px; right: 0; display: inline-flex; align-items: center;
  min-height: 44px; padding: 0 12px; background: transparent; color: var(--nav-ink);
  border: 1px solid var(--nav-line-forte); border-radius: var(--raio); font: inherit;
  font-size: 13px; cursor: pointer; }
.fechar-menu:hover { background: var(--nav-3); border-color: var(--ouro); }

.grupo-nav { font-family: var(--mono); font-size: 10px; letter-spacing: .19em;
  text-transform: uppercase; color: var(--nav-muted); padding: 14px 8px 5px; }
.item-nav { display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 10px 10px;
  margin-bottom: 2px; border-radius: var(--raio); text-decoration: none; color: var(--nav-ink);
  font-size: 15px; border-left: 2px solid transparent; }
.item-nav:hover { background: var(--nav-3); }
.item-nav[aria-current="page"] { background: var(--nav-3); border-left-color: var(--ouro);
  font-weight: 600; }
.item-nav .sinal { font-family: var(--mono); font-size: 12px; color: var(--nav-muted);
  margin-left: auto; }
.item-nav[aria-current="page"] .sinal { color: var(--ouro-2); }
.caso-nav { padding: 4px 8px 2px; }
.caso-nav .rot { font-family: var(--mono); font-size: 9.5px; letter-spacing: .19em;
  text-transform: uppercase; color: var(--nav-muted); }
.caso-nav .nome { font-size: 14px; color: var(--ouro-2); margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* identificação do cliente na barra (24/08/2026): abaixo do apelido, menor, sem competir com ele */
.caso-nav .razao { font-size: 11.5px; color: var(--nav-muted); margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.caso-nav .cnpj { font-family: var(--mono); font-size: 11px; color: var(--nav-muted);
  margin-top: 1px; }
.usuario-nav { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.usuario-nav .quem { font-size: 13px; color: var(--nav-ink); }
.usuario-nav .quem small { display: block; font-family: var(--mono); font-size: 10px;
  letter-spacing: .12em; color: var(--nav-muted); }
.btn-sair { appearance: none; background: transparent; color: var(--nav-ink); cursor: pointer;
  border: 1px solid var(--nav-line-forte); border-radius: var(--raio); font: inherit;
  font-size: 13px; min-height: 44px; padding: 0 14px; }
.btn-sair:hover { background: var(--nav-3); border-color: var(--ouro); }
/* ZERA-BOLETIM / M-5 — o gêmeo ícone-só da saída de contexto NÃO existe fora do rail colapsado:
   expandida (e no celular, onde a barra é gaveta e não colapsa) a saída é a de dentro do
   "Acesso rápido". `display:none` tira do fluxo E do foco — nada de controle duplicado.
   Quem o liga é `html.barra-colapsada .sair-rail` (bloco V2, @media min-width:1024px). */
.sair-rail { display: none; }

/* ---------- miolo claro ---------- */
.page-wrapper { min-width: 0; display: flex; flex-direction: column; background: var(--bg); }

/* trilha (breadcrumb) — barra fina no topo de TODA tela; no celular ela QUEBRA em linhas */
.trilha { min-height: var(--alt-trilha); display: flex; flex-wrap: wrap; align-items: center;
  gap: 4px 7px; padding: 7px 14px; background: var(--panel); border-bottom: 1px solid var(--line);
  font-size: 12.5px; color: var(--muted); }
.trilha a { color: var(--muted); text-decoration: none;
  display: inline-flex; align-items: center; min-height: 44px; }   /* alvo de toque */
.trilha a:hover { color: var(--ink); text-decoration: underline; }
.trilha .sep { color: var(--line-forte); }
.trilha [aria-current="page"] { color: var(--ink); font-weight: 600; }

.page-header { border-bottom: 1px solid var(--line); background: var(--panel);
  padding: 12px 14px 13px; display: flex; flex-direction: column; align-items: stretch;
  justify-content: flex-start; gap: 11px; }
.page-header h1 { font-family: var(--serif); font-size: 20px; margin: 0; font-weight: 600;
  letter-spacing: -.005em; overflow-wrap: anywhere; }
.page-header .sub { font-size: 12.5px; color: var(--muted); margin-top: 3px; font-family: var(--mono);
  overflow-wrap: anywhere; }
/* F-48b ADENDO (27/08): o FAB de suporte voltou a flutuar fixo no canto inferior direito em
   TODAS as larguras (widget.js) — mitigação obrigatória: reservar rodapé ≥88px pra nenhuma
   última linha/controle da página ficar embaixo dele (só o padding-bottom muda, nas 3 faixas). */
.page-body { padding: 14px 14px 96px; }
.barra-acao { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.barra-acao .btn { flex: 1 1 auto; justify-content: center; }

/* ================================================================= blocos */
.cartao { background: var(--panel); border: 1px solid var(--line); border-radius: var(--raio);
  box-shadow: var(--sombra); margin-bottom: var(--gap); }
.cartao > h2 { font-family: var(--serif); font-size: 16px; margin: 0; padding: 11px 14px;
  border-bottom: 1px solid var(--line); font-weight: 600; }
.cartao > .corpo { padding: 13px 14px; }
.nota { font-size: 13px; color: var(--muted); }
.mono { font-family: var(--mono); font-size: 14px; overflow-wrap: anywhere; }  /* D6: CNPJ no cartão mobile ficava a 13px */
.nowrap { white-space: nowrap; }
.rolagem { overflow-x: auto; max-width: 100%; -webkit-overflow-scrolling: touch; }

/* ---------- chapéu do caso: o navy do deck dentro do miolo claro ---------- */
.chapeu-caso { background: linear-gradient(180deg, var(--nav) 0%, var(--nav-2) 100%);
  color: var(--nav-ink); border-bottom: 2px solid var(--ouro); border-radius: var(--raio) var(--raio) 0 0;
  padding: 14px 14px 15px; }
.chapeu-caso .eyebrow { color: var(--ouro); }
.chapeu-caso h2 { font-family: var(--serif); font-size: 21px; margin: 5px 0 0; font-weight: 600;
  color: var(--nav-ink); letter-spacing: -.01em; overflow-wrap: anywhere; }
/* razão social do cliente, logo abaixo do apelido no chapéu do caso (24/08/2026) */
.chapeu-caso .razao-social { font-size: 14px; color: var(--nav-muted); margin-top: 4px;
  overflow-wrap: anywhere; }
.chapeu-caso .meta { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 9px;
  font-size: 14px; color: var(--nav-muted); }
.chapeu-caso .meta b { color: var(--nav-ink); font-weight: 600; }
.chapeu-caso .meta .mono { color: var(--nav-ink); }
.chapeu-caso .selo { border: 1px solid var(--nav-line-forte); border-radius: 999px;
  padding: 1px 9px; font-family: var(--mono); font-size: 11px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ouro-2); }

/* ---------- linha de etapas: no celular é LISTA VERTICAL, mesmos estados ---------- */
.etapas { list-style: none; margin: 0; padding: 0;
  display: grid; grid-auto-flow: row; grid-auto-columns: auto;
  background: var(--panel); border: 1px solid var(--line); border-top: 0;
  border-radius: 0 0 var(--raio) var(--raio); }
.etapas .et { padding: 12px 14px 13px; border-top: 1px solid var(--line); position: relative; }
.etapas .et:first-child { border-top: 0; }
.etapas .et .trilho { height: 2px; background: var(--line); margin-bottom: 9px; }
.etapas .et .n { font-family: var(--mono); font-size: 11px; letter-spacing: .19em; color: var(--muted); }
.etapas .et .t { font-size: 15px; font-weight: 600; margin-top: 3px; display: flex;
  align-items: center; gap: 7px; }
.etapas .et .ponto { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 9px;
  border: 2px solid var(--line-forte); background: var(--panel); }
.etapas .et .s { font-size: 13px; color: var(--muted); margin-top: 4px; line-height: 1.35; }
.etapas .et.feita .trilho { background: var(--ok); }
.etapas .et.feita .ponto { border-color: var(--ok); background: var(--ok); }
.etapas .et.feita .s { color: var(--ink-2); }
.etapas .et.atual .trilho { background: var(--ouro); }
.etapas .et.atual .ponto { border-color: var(--ouro-ink); background: var(--ouro); }
.etapas .et.atual .n { color: var(--ouro-ink); }
.etapas .et.espera .t { color: var(--muted); font-weight: 600; }

/* ---------- cartões-resumo (gramática do slide 05: filete colorido, valor em tinta) ---------- */
.resumo { display: grid; grid-template-columns: 1fr; gap: var(--gap); margin-bottom: var(--gap); }
.resumo .cx { background: var(--panel); border: 1px solid var(--line); border-top: 3px solid var(--na);
  border-radius: var(--raio); padding: 12px 14px 13px; box-shadow: var(--sombra); min-width: 0; }
.resumo .cx .rot { display: flex; align-items: center; gap: 7px; font-family: var(--mono);
  font-size: 11px; letter-spacing: .17em; text-transform: uppercase; color: var(--ink-2); }
.resumo .cx .bolha { width: 8px; height: 8px; border-radius: 50%; background: var(--na); flex: 0 0 8px; }
.resumo .cx .v { font-family: var(--serif); font-size: 26px; font-weight: 600; margin-top: 7px;
  color: var(--ink); letter-spacing: -.015em; overflow-wrap: anywhere; }
.resumo .cx .v.faixa { font-size: 18px; }
.resumo .cx .s { font-size: 13px; color: var(--muted); margin-top: 4px; }
.resumo .cx.verde { border-top-color: var(--ok); } .resumo .cx.verde .bolha { background: var(--ok); }
.resumo .cx.amarelo { border-top-color: var(--warn); } .resumo .cx.amarelo .bolha { background: var(--warn); }
.resumo .cx.cond { border-top-color: var(--accent); } .resumo .cx.cond .bolha { background: var(--accent); }
.resumo .cx.exposicao { border-top-color: var(--bad); } .resumo .cx.exposicao .bolha { background: var(--bad); }

/* ---------- atalhos do hub: 2×2 no celular ---------- */
.atalhos { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gap); }
.atalhos .at { display: block; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--raio); padding: 12px 12px; text-decoration: none; box-shadow: var(--sombra);
  min-height: 44px; min-width: 0; }
.atalhos a.at:hover { border-color: var(--line-forte); background: var(--panel-2); }
.atalhos .at .t { font-size: 14.5px; font-weight: 600; display: flex; align-items: center;
  justify-content: space-between; gap: 8px; }
.atalhos .at .t .seta { font-family: var(--mono); color: var(--ouro-ink); }
.atalhos .at .s { font-size: 12.5px; color: var(--muted); margin-top: 5px; line-height: 1.4; }
.atalhos .at.mudo { opacity: .62; }
.atalhos .at.mudo .t .seta { color: var(--muted); }

.duas-colunas { display: grid; grid-template-columns: 1fr; gap: var(--gap); align-items: start; }

/* `table.densa` REMOVIDA no Lote 0 (25/08/2026, consolidação da gramática de tabela) — toda a
   cobertura (marcador 4 cores, num/mono, acoes, zebra/hover, pilha-cab, 2 níveis por célula)
   migrou pra `.tabela` (ver bloco "tabela densa" mais abaixo, hoje de-escopado de `.v2`). */

/* ---------- /clientes no dedo: a tabela de 10 colunas vira cartão empilhado (<640px) ------- */
.lista-cartoes { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--gap); }
.cartao-caso { background: var(--panel); border: 1px solid var(--line);
  border-left: 4px solid var(--na); border-radius: var(--raio); box-shadow: var(--sombra);
  padding: 12px 13px 13px; min-width: 0; }
.cartao-caso.verde { border-left-color: var(--ok); }
.cartao-caso.amarelo { border-left-color: var(--warn); }
.cartao-caso .topo { display: flex; align-items: flex-start; justify-content: space-between;
  gap: 10px; flex-wrap: wrap; }
.cartao-caso .nome { font-size: 17px; font-weight: 600; text-decoration: none;
  overflow-wrap: anywhere; min-height: 44px; display: inline-flex; align-items: center; }
.cartao-caso .nome:hover { text-decoration: underline; }
.cartao-caso .linha { display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: baseline;
  font-size: 14px; padding: 4px 0; border-top: 1px solid var(--line); }
.cartao-caso .linha .rot { font-family: var(--mono); font-size: 11px; letter-spacing: .15em;
  text-transform: uppercase; color: var(--muted); flex: 0 0 auto; min-width: 88px; }
.cartao-caso .valores { display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
  align-items: end;                      /* rótulo de 2 linhas não desalinha os números */
  margin: 9px 0 4px; }
.cartao-caso .valores .rot { display: block; font-family: var(--mono); font-size: 11px;
  letter-spacing: .15em; text-transform: uppercase; color: var(--ink-2); }
.cartao-caso .valores .v { display: block; font-family: var(--serif); font-size: 19px;
  font-weight: 600; color: var(--ink); margin-top: 3px; overflow-wrap: anywhere; }
.cartao-caso .acoes-cartao { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px;
  margin-top: 11px; }
.botao-toque { display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 44px; padding: 0 12px; font-size: 14px; font-family: inherit; text-decoration: none;
  border: 1px solid var(--line-forte); border-radius: var(--raio); background: var(--panel);
  color: var(--ink); cursor: pointer; }
.botao-toque:hover { background: var(--panel-2); }
.botao-toque.principal { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.botao-toque[aria-disabled="true"] { color: var(--muted); background: var(--panel-2);
  border-style: dashed; cursor: default; }

/* ---------- chips de filtro (padrão MoJ, server-side) ---------- */
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.chip { display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 44px; padding: 8px 14px; font-size: 14px;
  border: 1px solid var(--line-forte); border-radius: 999px; background: var(--panel);
  color: var(--ink-2); text-decoration: none; }
.chip:hover { background: var(--panel-2); }
.chip[aria-pressed="true"] { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.chip .x { font-weight: 700; }
/* D3 (24/08): atalho de tabela sem destino — o caso não tem resultado.json/pasta deck. Fica
   visível e apagado; `--muted` sobre `--panel-2` mede 5,17:1, acima do piso de 4,5. */
.chip.off { color: var(--muted); background: var(--panel-2); border-style: dashed; cursor: default; }
button.chip { font-family: inherit; cursor: pointer; }
.acoes-envio { display: flex; flex-wrap: wrap; gap: 6px; }
.acoes-envio form { display: inline; margin: 0; }

/* ---------- badge de estado ---------- */
.badge { display: inline-block; padding: 2px 9px; font-size: 12px; border-radius: 999px;
  border: 1px solid var(--line-forte); background: var(--panel-2); color: var(--ink-2); white-space: nowrap; }
.badge.ok { border-color: var(--ok); color: var(--ok); background: var(--ok-tint); }
/* F-52: `color` é TEXTO sobre o tint — vai no valor de texto (--warn-txt, 5,17:1 sobre o tint).
   A borda continua no valor de traço, que é onde o amarelo tem de gritar contra o vermelho. */
.badge.warn { border-color: var(--warn); color: var(--warn-txt); background: var(--warn-tint); }
.badge.bad { border-color: var(--bad); color: var(--bad); background: var(--bad-tint); }
.badge.na { border-color: var(--na); color: var(--na); background: var(--na-tint); }

/* ---------- task list GOV.UK ---------- */
ul.task-list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
ul.task-list li { display: flex; justify-content: space-between; align-items: flex-start;
  flex-wrap: wrap; gap: 8px 16px; padding: 11px 4px; border-bottom: 1px solid var(--line); }
ul.task-list .titulo { font-weight: 600; font-size: 15px; }
ul.task-list .detalhe { font-size: 13px; color: var(--muted); margin-top: 2px; overflow-wrap: anywhere; }
.contador-task { font-size: 14px; color: var(--ink-2); margin: 0 0 10px; }

/* ---------- formulário ---------- */
label { display: block; font-size: 13.5px; color: var(--ink-2); margin-bottom: 5px; }
input[type=text], input[type=password], input[type=file], select {
  width: 100%; max-width: 100%; min-height: 44px; padding: 10px 12px;
  font-size: 16px;                      /* 16px evita o zoom automático do iOS ao focar */
  font-family: inherit; color: var(--ink);
  background: var(--panel); border: 1px solid var(--line-forte); border-radius: var(--raio);
}
input[type=file] { padding: 9px 10px; }
.campo { margin-bottom: 13px; }
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 44px; padding: 10px 16px; font-size: 14.5px;
  font-family: inherit; border-radius: var(--raio); border: 1px solid var(--accent);
  background: var(--accent); color: var(--accent-ink); cursor: pointer; text-decoration: none; }
.btn:hover { background: var(--nav); border-color: var(--nav); }
.btn.secundario { background: var(--panel); color: var(--ink); border-color: var(--line-forte); }
.btn.secundario:hover { background: var(--panel-2); }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }
.erro { border-left: 3px solid var(--bad); background: var(--bad-tint); color: var(--ink);
  padding: 10px 12px; border-radius: var(--raio); font-size: 14px; margin-bottom: 12px; }
.aviso { border-left: 3px solid var(--ouro); background: var(--panel-2);
  padding: 10px 12px; border-radius: var(--raio); font-size: 14px; margin-bottom: 12px; }

/* ---------- login ---------- */
.tela-login { min-height: 100vh; display: grid; place-items: center; padding: 20px 14px;
  background: linear-gradient(180deg, var(--nav) 0%, var(--nav-2) 60%, var(--nav) 100%); }
.caixa-login { width: 100%; max-width: 372px; background: var(--panel); border: 1px solid var(--line);
  border-top: 3px solid var(--ouro); border-radius: var(--raio);
  box-shadow: var(--sombra-modal); padding: 22px 18px 20px; }
.caixa-login .marca { text-align: center; margin-bottom: 6px; }
.caixa-login .marca-img { display: block; height: 34px; width: auto; margin: 0 auto 8px; }
.caixa-login .marca small { display: block; font-family: var(--mono); letter-spacing: .19em;
  text-transform: uppercase; font-size: 9.5px; color: var(--ouro-ink); }
.caixa-login p.nota { margin-top: 0; text-align: center; }
.caixa-login .btn { width: 100%; }
/* a tela de login não tem topbar: o corpo dela não herda o recuo do chrome de celular */
body.sem-chrome { padding-top: 0; }

/* ---------- progresso (htmx polling, nunca spinner mudo) ---------- */
progress { width: 100%; height: 12px; }
.etapa-atual { font-size: 14.5px; font-weight: 600; margin: 8px 0 4px; }
pre.log { background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--raio);
  padding: 10px; font-family: var(--mono); font-size: 12.5px; line-height: 1.5; max-height: 320px;
  overflow: auto; white-space: pre-wrap; word-break: break-word; margin: 0; }
.linha-etapas { display: flex; gap: 6px; flex-wrap: wrap; margin: 8px 0 12px; }
.linha-etapas .et { font-size: 12.5px; padding: 5px 10px; border: 1px solid var(--line); border-radius: 999px;
  color: var(--muted); }
.linha-etapas .et.feita { border-color: var(--ok); color: var(--ok); background: var(--ok-tint); }
.linha-etapas .et.atual { border-color: var(--accent); background: var(--accent); color: var(--accent-ink); }

/* ---------- tabs (macro do basecoat; o CSS dele é Tailwind e foi descartado) ---------- */
.tabs [role="tablist"] { display: flex; gap: 4px; border-bottom: 1px solid var(--line);
  margin-bottom: 14px; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.tabs [role="tab"] { appearance: none; background: transparent; border: 0; border-bottom: 2px solid transparent;
  min-height: 44px; padding: 8px 12px; font: inherit; font-size: 14.5px; color: var(--muted);
  cursor: pointer; white-space: nowrap; }
.tabs [role="tab"][aria-selected="true"] { color: var(--ink); border-bottom-color: var(--ouro); font-weight: 600; }
.tabs [role="tabpanel"] { overflow-x: auto; max-width: 100%; -webkit-overflow-scrolling: touch; }
.tabs [role="tabpanel"][hidden] { display: none; }

/* ---------- dialog (macro do basecoat, <dialog> nativo) ---------- */
dialog { border: 1px solid var(--line); border-radius: var(--raio); background: var(--panel);
  color: var(--ink); padding: 0; width: calc(100vw - 28px); max-width: 560px;
  box-shadow: var(--sombra-modal); }
dialog::backdrop { background: var(--backdrop); }
dialog header, dialog section, dialog footer { padding: 14px 16px; }
dialog header h2 { font-family: var(--serif); font-size: 17px; margin: 0 0 4px; }

/* ---------- monitor (listagem de alertas) ---------- */
.alerta-trecho { font-family: var(--mono); font-size: 12.5px; color: var(--ink-2); line-height: 1.45;
  max-width: 100%; overflow-wrap: anywhere; }
.alerta-teses { display: flex; flex-wrap: wrap; gap: 4px; }
.alerta-teses .t { font-family: var(--mono); font-size: 11.5px; border: 1px solid var(--line);
  border-radius: 3px; padding: 1px 6px; color: var(--ink-2); background: var(--panel-2); }

/* ---------- blocos do hub ---------- */
.bloco-caso { margin-bottom: var(--gap); }
.titulo-secao { font-family: var(--serif); font-size: 16px; font-weight: 600; margin: 18px 0 10px;
  padding-bottom: 6px; border-bottom: 1px solid var(--line); }
.titulo-secao:first-child { margin-top: 0; }
/* subtítulo dentro de um cartão (tela "Leitura do SPED", 24/08/2026) */
.sub-secao { font-family: var(--serif); font-size: 14px; font-weight: 600; margin: 14px 0 6px; }
/* seção "Documentos que destravam análise" na triagem (24/08/2026): outra gramática visual de
   propósito — lista de pedidos, não tabela de valores. A borda dourada à esquerda separa do
   cartão das oportunidades com valor sem inventar cor nova. */
.secao-documentos { border-left: 3px solid var(--ouro); }
.lista-documentos .titulo { font-weight: 600; }
.lista-documentos .frente-linha { margin-top: 3px; }
.selos-documento { display: flex; flex-wrap: wrap; gap: 5px; justify-content: flex-end; }
/* placar das três pilhas da "Leitura do SPED": a separação tem de ser vista antes da rolagem */
.placar-leitura { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-top: 14px; }
.placar-leitura .pilha { display: block; text-decoration: none; color: inherit;
  border: 1px solid var(--line); border-radius: var(--raio); padding: 10px 12px;
  background: var(--panel-2); }
.placar-leitura .pilha:hover { border-color: var(--ouro-ink); }
.placar-leitura .n { display: block; font-family: var(--serif); font-size: 24px; font-weight: 600;
  line-height: 1.1; }
.placar-leitura .rot { display: block; font-size: 13px; font-weight: 600; margin-top: 2px; }
.placar-leitura .diz { display: block; font-size: 12px; color: var(--muted); margin-top: 3px; }
@media (max-width: 639.98px) { .placar-leitura { grid-template-columns: 1fr; } }

/* ---------- deck (slides gerados pelo motor) ---------- */
.slide-deck { margin: 0 0 16px; }
.slide-deck img { display: block; width: 100%; max-width: 1000px; height: auto;
  border: 1px solid var(--line); border-radius: var(--raio); box-shadow: var(--sombra); }
.slide-deck figcaption { margin-top: 5px; }

/* ==================================================================================== 640px
 * Daqui para cima a tabela de casos volta (a tela já comporta as colunas com rolagem CONTIDA
 * dentro do bloco) e os cartões de valor deixam de ser uma coluna só. */
@media (min-width: 640px) {
  .lista-cartoes { display: none; }
  /* na faixa de tablet a tabela volta, e o chip de 44px na coluna Ações empilhava 5 vezes:
     a linha inteira ia a ~240px de altura (medido em 768x1024). Aqui ele fica compacto —
     32px de altura com 8px de espaçamento, o piso de alvo de toque da WCAG 2.5.8 (AA) é 24px;
     os 44px seguem valendo onde o dedo de fato opera, abaixo de 640px (cartão). */
  .rolagem-casos { display: block; }
  .resumo { grid-template-columns: repeat(2, 1fr); }
  .cartao-caso .valores { grid-template-columns: repeat(2, 1fr); }
  .page-body { padding: 16px 18px 96px; }
  .trilha, .page-header { padding-left: 18px; padding-right: 18px; }
}
/* CL-6 (25/08/2026): aqui vivia `.rolagem-casos { display: none }` — a metade que escondia a
   TABELA de clientes no celular para dar lugar a um `<ul class="lista-cartoes">` com o mesmo
   conteúdo e outros rótulos. O `<ul>` morreu (`_tabela_casos.html`) e a tabela passa a refluir
   para cartão por CSS, no bloco "CL-6 — reflow" no fim deste arquivo (§Mobile: "a MESMA
   `<table>` vira cartão via CSS; nunca HTML duplicado"). `.lista-cartoes`/`.cartao-caso`
   CONTINUAM aqui: `_tabela_teses.html`, `monitor.html` e `resultado.html` ainda os usam, e essas
   três telas estão fora do território deste conserto (aplicar pós-b3). */

/* =================================================================================== 1024px
 * O chrome volta a ser a barra navy fixa (a gaveta some), e a densidade volta à do desktop —
 * é esta faixa que o julgamento V2-HUB aprovou em 1536×756. */
@media (min-width: 1024px) {
  body { padding-top: 0; }
  .topbar, .veu, .fechar-menu { display: none; }
  .page { display: flex; }
  .sidebar, aside.navbar-vertical {
    /* z-index 30 (não auto): com auto, o tooltip do estado colapsado (z:60, mas DENTRO do
       contexto da barra) perde pro conteúdo que vem depois no DOM — a legenda renderizava
       ATRÁS dos KPI-cards (bronca do dono 26/08 09h55 BRT, print). 30 < topbar(40) < véu(45). */
    position: sticky; top: 0; left: auto; bottom: auto; z-index: 30;
    width: var(--larg-sidebar); flex: 0 0 var(--larg-sidebar); height: 100vh;
    transform: none; visibility: visible; box-shadow: none; transition: none;
  }
  .sidebar header { padding: 16px 16px 14px; }
  .sidebar .marca { padding-right: 0; }
  .page-wrapper { flex: 1; }
  .item-nav { min-height: 0; padding: 6px 9px; margin-bottom: 1px; }
  .btn-sair { min-height: 0; padding: 4px 9px; }

  .trilha { height: var(--alt-trilha); min-height: 0; flex-wrap: nowrap; gap: 7px;
    padding: 0 22px; }
  .trilha a { display: inline; min-height: 0; }
  .page-header { flex-direction: row; align-items: flex-end; justify-content: space-between;
    gap: 16px; padding: 13px 22px 14px; }
  .page-body { padding: 18px 22px 96px; }
  .barra-acao .btn { flex: 0 0 auto; }

  .cartao > h2 { padding: 10px 14px; }
  .chapeu-caso { padding: 15px 18px 16px; }
  .chapeu-caso .meta { gap: 6px 18px; }
  .atalhos .at { padding: 12px 14px; }

  .chips { gap: 6px; margin-bottom: 11px; }
  .chip { min-height: 0; padding: 3px 9px; }
  .acoes-envio { display: block; white-space: nowrap; }
  .badge { padding: 1px 8px; }
  ul.task-list li { flex-wrap: nowrap; gap: 16px; padding: 10px 4px; }

  label { margin-bottom: 4px; }
  input[type=text], input[type=password], input[type=file], select {
    min-height: 0; padding: 7px 9px; }
  .campo { margin-bottom: 12px; }
  .btn { min-height: 0; padding: 6px 14px; }
  .erro { padding: 9px 12px; }
  .aviso { padding: 9px 12px; }
  .caixa-login { padding: 26px 26px 22px; }
  progress { height: 10px; }
  .linha-etapas .et { padding: 3px 8px; }
  .tabs [role="tab"] { min-height: 0; }
  .tabs [role="tablist"] { overflow-x: visible; }
  dialog { width: auto; }
  .alerta-trecho { max-width: 620px; }
  .alerta-teses .t { padding: 0 5px; }
}

/* =================================================================================== 1180px
 * 1536×756 é a janela real do dono: só aqui a grade de 4 e a esteira horizontal aparecem. */
@media (min-width: 1180px) {
  .resumo, .atalhos { grid-template-columns: repeat(4, 1fr); }
  .duas-colunas { grid-template-columns: 1.35fr 1fr; }
  .etapas { grid-auto-flow: column; grid-auto-columns: 1fr; }
  .etapas .et { border-top: 0; border-left: 1px solid var(--line); }
  .etapas .et:first-child { border-left: 0; }
}

/* ---------- gestão de clientes (CRUD cru 24/08 — o workflow de polimento redesenha) ---------- */
.novo-cliente summary { display: inline-block; cursor: pointer; }
.novo-cliente form { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.novo-cliente form label { font-weight: 600; }
.novo-cliente form .nota { flex-basis: 100%; margin: 0; }
.gerir-caso { margin-top: 6px; }
.gerir-caso summary { cursor: pointer; }
.gerir-form { display: flex; gap: 6px; margin-top: 6px; flex-wrap: wrap; align-items: center; }
.gerir-form input[type=text] { max-width: 220px; }

/* ---------- triagem de oportunidades (24/08/2026) ---------- */
.contador-triagem { font-size: 15px; font-weight: 600; margin: 0 0 2px; color: var(--ink); }
.selos-op { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.selos-op .frente-op { font-family: var(--mono); font-size: 11px; letter-spacing: .13em;
  text-transform: uppercase; color: var(--muted); }
.valor-op { font-family: var(--serif); font-size: 26px; font-weight: 600; color: var(--ink);
  letter-spacing: -.015em; overflow-wrap: anywhere; }
.valor-op.faixa { font-size: 19px; }
.rot-bloco { font-family: var(--mono); font-size: 11px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--muted); margin: 13px 0 2px; }
.lista-op { margin: 4px 0 0; padding-left: 18px; font-size: 14px; line-height: 1.5; }
.lista-op li { margin-bottom: 4px; overflow-wrap: anywhere; }
.lista-op .nota { display: block; font-size: 12px; }
.acoes-decisao { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 4px; }
.acoes-decisao form { margin: 0; }
.form-descarte { border-top: 1px solid var(--line); margin-top: 12px; padding-top: 12px; }
.form-descarte input[type=text] { max-width: 460px; }
.nav-op { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 0 0 var(--gap); font-size: 14px; }
.nav-op .posicao { font-family: var(--mono); font-size: 12px; color: var(--muted); }
.nav-op .mudo { color: var(--muted); }
details.tecnico { background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--raio); margin-bottom: var(--gap); }
details.tecnico > summary { padding: 11px 14px; cursor: pointer; font-size: 14px;
  color: var(--ink-2); min-height: 44px; display: flex; align-items: center; }
details.tecnico[open] > summary { border-bottom: 1px solid var(--line); }
details.tecnico .rolagem { padding: 0 14px 12px; }

/* ---------- I4 (24/08/2026): a home do cliente CONDUZ ---------- */
/* O passo de agora, em destaque, entre o chapéu do caso e a esteira. Mobile-first: uma coluna,
   sem largura fixa; o botão nasce com 44px de alvo de toque. */
.passo-atual { background: var(--panel); border: 1px solid var(--line);
  border-left: 4px solid var(--ouro); padding: 13px 14px 15px; }
.passo-atual .rot { font-family: var(--mono); font-size: 10.5px; letter-spacing: .19em;
  text-transform: uppercase; color: var(--ouro-ink); }
.passo-atual h3 { font-family: var(--serif); font-size: 18px; font-weight: 600; margin: 4px 0 0;
  color: var(--ink); }
.passo-atual .instrucao { font-size: 14.5px; color: var(--ink-2); margin: 6px 0 0; line-height: 1.4; }
.passo-atual .onde { font-size: 13px; color: var(--muted); margin: 4px 0 11px; }
.passo-atual .btn { min-height: 44px; }
.passo-atual.fechado { border-left-color: var(--ok); }
.passo-atual.fechado .rot { color: var(--ok); }
/* carimbo do passo concluído e botão do passo de agora, dentro da esteira */
.etapas .et .carimbo { font-family: var(--mono); font-size: 11.5px; color: var(--ok);
  margin-top: 5px; }
.etapas .et .acao-etapa { margin-top: 9px; }
/* "os futuros apagados": o que ainda não chegou perde contraste, sem sumir da tela */
.etapas .et.espera { opacity: .58; }

/* ==================================================================== V1-VISUAL (24/08/2026)
 * Composição e identidade nas telas do fluxo. Nenhuma cor nova: tudo por var() de tokens.css
 * (a paleta é decisão do dono, não desta frente). O que muda é hierarquia — tamanho, peso,
 * espaço e agrupamento. Mobile-first, como o resto do arquivo.
 */

/* ---- número é número: alinha na vírgula em toda a plataforma ---- */
.resumo .cx .v, .valor-op,
.cartao-caso .valores .v, .painel-decisao .valor-op {
  font-variant-numeric: tabular-nums; }
/* `.tabela td.num`/`th.num` já ganham tabular-nums na regra da gramática de tabela (bloco
   "tabela densa" acima) — não repetir aqui (era `table.densa`, removido no Lote 0). */

/* ---------- tabela de oportunidades: uma FAIXA por situação ---------- */
/* A lista era plana: 22 a 37 linhas com três selos cada, sem separação entre o que tem valor e
   o que o próprio levantamento descartou. Agora cada pilha abre com uma faixa que diz o que ela
   é, quantas linhas tem e quanto soma — e a coluna de valor segue alinhada de cima a baixo. */
.tabela-ops tr.pilha-cab > th, .tabela-ops tr.pilha-cab > td {
  background: var(--panel-2); vertical-align: middle;
  border-top: 1px solid var(--line-forte); border-bottom: 1px solid var(--line-forte);
  padding-top: 10px; padding-bottom: 9px; }
.tabela-ops tbody.pilha:first-of-type tr.pilha-cab > th,
.tabela-ops tbody.pilha:first-of-type tr.pilha-cab > td { border-top: 0; }
.tabela-ops tr.pilha-cab > th { text-align: left; font-weight: 400; border-left: 3px solid var(--na); }
.tabela-ops tbody.verde tr.pilha-cab > th { border-left-color: var(--ok); }
.tabela-ops tbody.amarelo tr.pilha-cab > th { border-left-color: var(--warn); }
.tabela-ops tbody.vermelho tr.pilha-cab > th { border-left-color: var(--bad); }
.tabela-ops tr.pilha-cab .titulo { font-family: var(--serif); font-size: 15.5px; font-weight: 600;
  color: var(--ink); margin-right: 9px; }
.tabela-ops tr.pilha-cab .conta { font-family: var(--mono); font-size: 11px; letter-spacing: .13em;
  text-transform: uppercase; color: var(--muted); white-space: nowrap; }
.tabela-ops tr.pilha-cab .expl { display: block; font-size: 12.5px; color: var(--muted);
  margin-top: 2px; }
.tabela-ops tr.pilha-cab td.soma { font-family: var(--mono); font-weight: 600; color: var(--ink); }
.tabela-ops td { padding-top: 9px; padding-bottom: 9px; }
/* `.tabela-ops td.marcador { border-left-width: 3px; }` removida no Lote 0: era o mecanismo
   VELHO (border direto no td). O marcador agora é `::before` posicionado (regra de `.tabela`
   acima) — a largura de 3px já vem de lá, redeclará-la aqui não fazia mais nada. */
.tabela-ops a.link-caso { font-size: 14.5px; font-weight: 600; text-decoration: none; }
.tabela-ops a.link-caso:hover { text-decoration: underline; }
.tabela-ops .frente-linha { font-family: var(--mono); font-size: 11px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted); margin-top: 3px; }
/* o "o que falta" é o texto que o advogado lê de fato: ganha medida de leitura, não sobra */
.tabela-ops td.motivo { color: var(--ink-2); line-height: 1.4; }

/* ---------- tela de decisão: o dinheiro e os botões param de fugir da dobra ---------- */
/* Antes eram sete cartões de mesmo peso, empilhados; o valor ficava no terceiro e os botões de
   decisão só apareciam depois de rolar cinco blocos. Agora o painel de decisão acompanha a
   leitura no desktop e abre a tela no celular. */
.grade-op { display: grid; grid-template-columns: 1fr; gap: var(--gap); align-items: start; }
.grade-op > .coluna { min-width: 0; }
.painel-decisao { background: var(--panel); border: 1px solid var(--line);
  border-top: 3px solid var(--ouro); border-radius: var(--raio); box-shadow: var(--sombra);
  margin-bottom: var(--gap); }
.painel-decisao > .corpo { padding: 14px; }
.painel-decisao .rot-valor { font-family: var(--mono); font-size: 10.5px; letter-spacing: .19em;
  text-transform: uppercase; color: var(--ouro-ink); }
.painel-decisao .valor-op { margin-top: 4px; }
.painel-decisao .selos-op { margin: 11px 0 0; }
.painel-decisao .cerca { border-top: 1px solid var(--line); margin: 13px 0 0; padding-top: 12px; }
.painel-decisao .acoes-decisao .btn { flex: 1 1 auto; }
.painel-decisao .form-descarte { border-top: 0; margin-top: 10px; padding-top: 0; }
.painel-decisao .form-descarte input[type=text] { max-width: 100%; }
/* medida de leitura: linha de 150 caracteres não se lê, mesmo bonita */
.texto-medido p, .texto-medido li { max-width: 78ch; }

/* ---------- formulários de cliente: eram CRUD cru dentro de um <details> ---------- */
/* O campo de nome ocupava 1240px para caber 80 caracteres, o botão flutuava solto embaixo e o
   bloco não tinha título. Vira um painel com largura de formulário. */
.novo-cliente > summary { display: inline-flex; }
.novo-cliente[open] > summary { margin-bottom: 12px; }
/* a regra herdada `.novo-cliente form { display:flex }` colava o botão no campo e espremia o
   campo a ~190px: o painel é bloco, com o campo em cima e o botão embaixo */
.novo-cliente form.form-painel { display: block; }
.form-painel { max-width: 470px; }
.form-painel .titulo-form { font-family: var(--serif); font-size: 15px; font-weight: 600;
  margin: 0 0 3px; }
.form-painel .ajuda { font-size: 13px; color: var(--muted); margin: 0 0 12px; }
.form-painel .linha-botoes { display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  margin-top: 4px; }
.form-painel .nota { margin: 10px 0 0; }
.gerir-caso[open] > summary { margin-bottom: 8px; }
.gerir-painel { border-left: 2px solid var(--line); padding: 2px 0 2px 10px; margin-top: 6px; }
.gerir-painel .campo-gerir { display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  margin-bottom: 7px; }
.gerir-painel label { margin: 0 0 3px; }
.gerir-painel .nota { margin: 0; }

/* ---------- hub: o passo de agora ganha corpo ---------- */
.passo-atual .instrucao { max-width: 70ch; }
/* na esteira, o passo de agora tinha só o filete e o ponto dourados: some no meio de sete
   células. Um fundo de leve tinta dourada o encontra de longe, sem virar alerta. */
.etapas .et.atual { background: var(--warn-tint); }

/* o subtítulo da página é frase, não código: em mono ele lia como saída de terminal */
.page-header .sub { font-family: var(--sans); font-size: 13px; }

@media (min-width: 640px) {
  .tabela-ops td.motivo { max-width: 30ch; }
}

@media (min-width: 1024px) {
  .tabela-ops td.motivo { max-width: 42ch; }
  /* o nome da tese é a coluna que se lê; as duas colunas de selo não precisam de vão nenhum */
  .tabela-ops td:first-child, .tabela-ops th:first-child { width: 33%; }
  .tabela-ops td:nth-child(2), .tabela-ops th:nth-child(2) { width: 1%; white-space: nowrap; }
  .tabela-ops td:nth-child(4), .tabela-ops th:nth-child(4) { width: 1%; }
  /* a coluna de ações da lista de clientes empilhava seis chips em quatro linhas e a linha ia a
     ~120px de altura (medido na captura de 24/08 15h37 BRT). Com folga, cabem em duas. */
  /* 296px foi medido e REPROVADO: a tabela passou de 1256px e a `.rolagem` cortava a coluna do
     nome do cliente (captura passo2/21). 232px cabe na janela do dono e põe os seis atalhos em
     três linhas curtas — com o chip compacto, a linha inteira fica em ~70px em vez de 120px. */
  .passo-atual { padding: 16px 20px 18px; }
}

@media (min-width: 1180px) {
  .grade-op { grid-template-columns: minmax(0, 1.5fr) minmax(320px, 1fr); }
  /* o painel vem PRIMEIRO no HTML (para abrir a tela no celular) e vai para a direita aqui */
  .grade-op > .coluna { grid-column: 1; grid-row: 1; }
  /* o painel acompanha a leitura: decidir não pode depender de rolar de volta */
  .grade-op > .rail { grid-column: 2; grid-row: 1; position: sticky; top: 14px; }
}

/* ====================================================== C1 — CONSERTOS DO JULGAMENTO (24/08/2026)
 * Cada bloco aqui responde a um defeito nomeado em J1-FUNCIONAL.md / J2-PIXEL.md. Nenhuma cor
 * nova: tudo por var() de tokens.css.
 */

/* ---- P14/P12: a lista de oportunidades era renderizada DUAS vezes ----
 * A lista de CLIENTES tem o par completo (`.lista-cartoes` até 639,98px × `.rolagem-casos` a
 * partir de 640px). A lista de OPORTUNIDADES só tinha metade: `.lista-cartoes` sumia no desktop,
 * mas as FAIXAS de pilha do bloco de cartões continuavam visíveis (a "parede" de 5 linhas
 * corridas logo abaixo dos filtros — P12) e a tabela `.rolagem-ops` NUNCA era escondida no
 * celular (as mesmas 22 oportunidades de novo, 4.400px abaixo, atrás de 425px de rolagem
 * lateral — P14). O par agora é simétrico. */
@media (max-width: 639.98px) {
  .rolagem-ops { display: none; }
}
@media (min-width: 640px) {
  .ops-cartoes { display: none; }
}

/* ---- P15: <progress> sem estilo desenhava o azul padrão do Chrome no meio da paleta ---- */
progress { appearance: none; -webkit-appearance: none; border: 1px solid var(--line);
  border-radius: 999px; background: var(--panel-2); overflow: hidden; }
progress::-webkit-progress-bar { background: var(--panel-2); }
progress::-webkit-progress-value { background: var(--ok); }
progress::-moz-progress-bar { background: var(--ok); }

/* ---- P10: o intervalo do cartão condicionado encolhia o tipo para caber numa linha ----
 * O maior número da fileira era o que aparecia menor. Vai em duas linhas, no mesmo corpo. */
.resumo .cx .v .de, .resumo .cx .v .ate { display: block; }
.resumo .cx .v .ate { margin-top: 1px; }
.resumo .cx .v .de, .resumo .cx .v .ate { font-size: inherit; }

/* ---- P11: a ausência de valor é dita, não desenhada com o mesmo traço do número negativo ---- */
.mudo { color: var(--muted); }
.tabela td.num .nota { font-family: var(--f-mono); text-transform: lowercase; }
.valor-cartao .v.mudo { font-weight: 400; }

/* ---- P19: o seletor de arquivo do navegador falava inglês ---- */
.escolher-arquivo { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.escolher-arquivo .nome-arquivo { font-size: 13px; color: var(--muted); overflow-wrap: anywhere; }
/* o input continua no fluxo e FOCÁVEL (o navegador precisa dele para reportar "campo
   obrigatório"): fica invisível, não removido */
input.input-arquivo { position: absolute; opacity: 0; width: 1px; height: 1px; }

/* ---- P1: a coluna AÇÕES da lista de clientes terminava 49px fora da janela do dono ----
 * Seis chips numa coluna de 232px empurravam a tabela para 1585px em 1536. Ficou "abrir" + um
 * menu; os destinos continuam a um clique, dentro dele. */
/* `.linha-atalhos`/`.gerir-painel`/min-width 104px já vêm da regra `.tabela td.acoes` acima
   (bloco "tabela densa" — consolidado no Lote 0, 25/08/2026). */

/* ---------- CUR-G7 (25/08/2026): detalhe da tese em LEITURA primeiro, editar atrás de <details> ----------
 * Bronca do dono: a ficha inteira nascia em forms abertos. Cada bloco agora mostra a leitura
 * (`.leitura-bloco`, linhas rótulo/valor) e o form só aparece dentro de um <details class="editar-disc">
 * fechado por padrão — o `<summary>` é o botão discreto. Reusa `.rot-bloco`/`.form-painel` que já
 * existiam; nada de cor nova. */
.leitura-bloco { list-style: none; margin: 2px 0 0; padding: 0; }
.leitura-bloco li { display: flex; flex-wrap: wrap; gap: 4px 10px; padding: 5px 0;
  border-bottom: 1px solid var(--line); font-size: 14px; }
.leitura-bloco li:last-child { border-bottom: 0; }
.leitura-bloco .rot { font-family: var(--mono); font-size: 11px; letter-spacing: .13em;
  text-transform: uppercase; color: var(--muted); flex: 0 0 168px; }
.editar-disc { margin-top: 12px; border-top: 1px solid var(--line); padding-top: 10px; }
.editar-disc > summary { display: inline-flex; align-items: center; gap: 5px; cursor: pointer;
  font-size: 12.5px; color: var(--muted); list-style: none; min-height: 32px; }
.editar-disc > summary::-webkit-details-marker { display: none; }
.editar-disc > summary::before { content: "✎"; font-size: 11px; }
.editar-disc > summary:hover { color: var(--ink-2); }
.editar-disc[open] > summary { color: var(--ink-2); margin-bottom: 10px; }
.editar-disc .rot-bloco:first-of-type { margin-top: 0; }
@media (max-width: 639.98px) {
  .leitura-bloco .rot { flex: 0 0 100%; }
}

/* ---------- CUR-G8 (25/08/2026): infos curtas viram CHIP, nunca linha inteira ----------
 * Bronca do dono: "uma linha pra cada info mesmo que pequena, ao invés de ir contendo em
 * pequenas boxes que preveem o limite de texto do conteúdo pra ficar mais harmônico". `.chips`
 * é a faixa densa (flex-wrap) de `.chip` — cada um `width: fit-content`, dimensionado pelo
 * conteúdo típico (max-width curto + ellipsis; `title` cobre o excepcional). Eixos viram grade
 * de cards pequenos (`.grade-eixos` / `.cartao-eixo`) em vez de blocos empilhados. */
.chips { display: flex; flex-wrap: wrap; gap: 6px 8px; margin: 4px 0 0; }
.chip { display: inline-flex; align-items: baseline; gap: 6px; width: fit-content;
  max-width: 260px; padding: 4px 10px; border: 1px solid var(--line); border-radius: 8px;
  font-size: 13px; line-height: 1.3; background: transparent; }
.chip .rot { font-family: var(--mono); font-size: 10px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted); flex: 0 0 auto; }
.chip .v { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chip a.v { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; }
.chip.chip-solto { padding: 3px 9px; font-size: 12.5px; }

.grade-eixos { display: grid; grid-template-columns: 1fr; gap: 10px; margin-top: 4px; }
.cartao-eixo { border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px; }
.cartao-eixo .rot-bloco { margin-top: 0; }
.cartao-eixo .chips { margin-top: 6px; }
.detalhe-eixo { margin-top: 7px; }
.detalhe-eixo > summary { cursor: pointer; font-size: 12px; color: var(--muted);
  list-style: none; }
.detalhe-eixo > summary::-webkit-details-marker { display: none; }
.detalhe-eixo > summary::before { content: "▸ "; }
.detalhe-eixo[open] > summary::before { content: "▾ "; }
.detalhe-eixo p { margin: 6px 0 0; font-size: 13.5px; }
@media (min-width: 900px) {
  .grade-eixos { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1280px) {
  .grade-eixos { grid-template-columns: repeat(3, 1fr); }
}

/* ---- P21: /biblioteca e /monitor no celular ----
 * As duas serviam tabela larga sem alternativa de cartão (848px e 401px de coluna atrás de
 * rolagem lateral contida). Ganharam o MESMO par da lista de clientes; `.so-desktop` é o lado
 * "tabela" desse par, para quem não usa a classe `.rolagem-casos`. */
@media (max-width: 639.98px) {
  .so-desktop { display: none; }
}

/* ---------- CUR-G9 (25/08/2026): passe final de enxugamento do detalhe da tese ----------
 * Reprovação da coordenação sobre `prova-g8/02-depois.png`: info pequena não ganha linha nem
 * seção dedicada. (1) NOME sai do modo leitura — já é o <h1>; (2) NOTA DO DONO vazia não
 * renderiza nada e, preenchida, vira texto corrido; (3) "renomear" vira ação inline ao lado do
 * identificador; (4) "arquivar" vira botão de rodapé e o aviso vai pro confirm(); (5) cabeçalho
 * de seção verboso vira rótulo discreto (`.rot-secao`); (6) o primeiro box se FUNDE ao
 * `.page-header` (sem borda/raio/sombra de cartão; margem negativa cancela o padding do
 * `.page-body` em cada breakpoint). Zero cor literal — só var() de tokens.css. */
.faixa-ficha { background: var(--panel); border-bottom: 1px solid var(--line);
  margin: -14px -14px 14px; padding: 7px 14px 8px; }
body:has(.faixa-ficha) .page-header { border-bottom: 0; }   /* sem hairline dupla título↔faixa */
.linha-ficha { display: flex; flex-wrap: wrap; align-items: baseline; gap: 5px 10px; }
.linha-ficha .meta-ficha { font-size: 12px; color: var(--muted); }
.linha-ficha .meta-ficha .mono { color: var(--ink-2); }
.nota-faixa { margin: 5px 0 0; }
.acao-inline { font-size: 12px; }
.acao-inline > summary { display: inline-flex; align-items: center; cursor: pointer;
  list-style: none; color: var(--muted); text-decoration: underline dotted;
  text-underline-offset: 2px; }
.acao-inline > summary::-webkit-details-marker { display: none; }
.acao-inline > summary:hover { color: var(--ink-2); }
/* aberto, o painel ocupa a linha inteira e vai pro FIM da faixa (order) — senão "origem: …"
 * cairia depois do painel de renomear. */
.acao-inline[open] { flex: 1 1 100%; order: 2; }
.acao-inline > .painel-inline { border: 1px solid var(--line); border-radius: var(--raio);
  background: var(--panel-2); padding: 10px 12px; margin: 8px 0 4px; max-width: 620px; }
.rot-secao { font-family: var(--mono); font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--muted); margin: 0 0 3px; }
.nota-dono { margin: 8px 0 0; font-style: italic; color: var(--ink-2); }
.acoes-rodape { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 10px; }
.btn-discreto { background: none; border: 0; padding: 4px 0; cursor: pointer;
  font-family: inherit; font-size: 12px; color: var(--muted);
  text-decoration: underline dotted; text-underline-offset: 2px; }
.btn-discreto:hover { color: var(--bad); }
@media (min-width: 640px) {
  .faixa-ficha { margin: -16px -18px 14px; padding: 7px 18px 8px; }
}
@media (min-width: 1024px) {
  .faixa-ficha { margin: -18px -22px 14px; padding: 6px 22px 8px; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   V2 — CHROME NOVO (sidebar navy COLAPSÁVEL + topbar com busca e trilha) e os componentes
   da maquete V1 aprovada. 25/08/2026.

   Escopo: as regras de CHROME são globais (o shell é um só, em toda tela); as regras de
   COMPONENTE ficam sob `.v2`, para que a tela piloto estreie o vocabulário novo sem vestir
   por acidente as 20 telas herdadas, que continuam nas classes antigas.
   ══════════════════════════════════════════════════════════════════════════════════════ */

/* ──────────────────────── ícone no item de navegação ──────────────────────── */
.item-nav { display: flex; align-items: center; gap: 10px; }
.item-nav .ic { width: 16px; height: 16px; flex: none; opacity: .75; }
.item-nav[aria-current="page"] .ic { opacity: 1; color: var(--marca-clara); }
.item-nav .rot-nav { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.item-nav .sinal { margin-left: auto; }

/* ──────────────────────── topbar (busca + trilha + colapsar) ────────────────────────
 * No celular a topbar NÃO existe como faixa própria: `display:contents` dissolve o wrapper e a
 * trilha volta a ser exatamente a faixa que a v1 já tinha (o chrome de celular é a `.topbar`
 * fixa lá em cima). Da faixa de desktop para cima ela vira a barra de topo da maquete V1. */
.topo-v2 { display: contents; }
.btn-colapsar, .busca-topo { display: none; }

@media (min-width: 1024px) {
  .topo-v2 {
    display: flex; align-items: center; gap: 14px;
    height: var(--topo-alt); padding: 0 22px;
    background: var(--sup-papel); border-bottom: 1px solid var(--fio);
    position: sticky; top: 0; z-index: 20;
  }
  /* a trilha deixa de ser uma faixa própria e passa a morar DENTRO da topbar */
  .topo-v2 .trilha {
    height: auto; min-height: 0; padding: 0; border: 0; background: none;
    flex-wrap: nowrap; gap: 8px; font-size: 12.5px; color: var(--txt-3);
  }
  .topo-v2 .trilha a { display: inline; min-height: 0; color: var(--txt-3); text-decoration: none; }
  .topo-v2 .trilha a:hover { color: var(--txt-1); text-decoration: underline; text-underline-offset: 3px; }
  .topo-v2 .trilha .sep { color: var(--fio-forte); }
  .topo-v2 .trilha [aria-current="page"] { color: var(--txt-1); font-weight: 500; }
  .topo-v2 .trilha a { min-height: 0; }

  .topo-dir { margin-left: auto; display: flex; align-items: center; gap: 8px; }
  .busca-topo {
    display: flex; align-items: center; gap: 8px; height: 32px; padding: 0 10px; width: 250px;
    border: 1px solid var(--fio); border-radius: var(--r-cartao); background: var(--sup-fundo);
    color: var(--txt-3); font: inherit; font-size: 12.5px;
    transition: border-color var(--t) var(--mola);
  }
  .busca-topo:hover { border-color: var(--fio-forte); }
  .busca-topo:focus-within { border-color: var(--foco); }
  .busca-topo .ic { width: 14px; height: 14px; flex: none; }
  .busca-topo input {
    border: 0; background: none; font: inherit; color: var(--txt-1); width: 100%; padding: 0;
    min-height: 0;
  }
  .busca-topo input::placeholder { color: var(--txt-3); }
  .busca-topo input:focus-visible { outline: none; }

  /* ─── o botão que colapsa a barra (pedido do dono junto do veredito F1) ─── */
  .btn-colapsar {
    display: inline-grid; place-items: center; width: 30px; height: 30px; flex: none;
    border: 1px solid var(--fio); border-radius: var(--r-cartao);
    background: var(--sup-papel); color: var(--txt-2); cursor: pointer;
    transition: background var(--t) var(--mola), border-color var(--t) var(--mola);
  }
  .btn-colapsar:hover { background: var(--sup-papel-2); border-color: var(--fio-forte); }
  .btn-colapsar .ic { width: 16px; height: 16px; transition: transform var(--t) var(--mola); }
  html.barra-colapsada .btn-colapsar .ic { transform: rotate(180deg); }

  /* ─── estado COLAPSADO: a largura vem do token; o miolo ganha a diferença ─── */
  html.barra-colapsada { --larg-sidebar: var(--barra-larg-colapsada); }
  .sidebar, aside.navbar-vertical { transition: flex-basis var(--t) var(--mola), width var(--t) var(--mola); }
  /* `overflow: visible` colapsada NÃO é enfeite: com `overflow-y:auto` (o padrão herdado) o
     `::after` do tooltip é RECORTADO pela própria barra e o rótulo não aparece em lugar nenhum
     — medido no 1º render, com o mouse parado em cima do item. Colapsada a lista é curta
     (no máximo 11 ícones de 34px, ~374px de 756px de janela), então nada precisa rolar. */
  html.barra-colapsada .sidebar section { padding-left: 6px; padding-right: 6px;
    overflow: visible; }
  html.barra-colapsada .sidebar header { padding: 16px 8px 14px; }
  html.barra-colapsada .marca-img,
  html.barra-colapsada .sidebar .marca small,
  html.barra-colapsada .grupo-nav,
  html.barra-colapsada .caso-nav,
  html.barra-colapsada .item-nav .rot-nav,
  html.barra-colapsada .item-nav .sinal,
  html.barra-colapsada .usuario-nav .quem,
  html.barra-colapsada .btn-sair .rot-nav { display: none; }
  /* colapsada, a marca vira o monograma; o `::before` mora no LINK (não em `.marca`) pra o
     monograma continuar clicável — regra 8 do DS vale nos dois estados da barra. */
  html.barra-colapsada .marca-link::before {
    content: "D"; display: block; font-family: var(--f-titulo); font-size: 22px; font-weight: 600;
    color: var(--marca); text-align: center; line-height: 1;
  }
  html.barra-colapsada .item-nav { justify-content: center; padding: 8px 0; gap: 0; }
  html.barra-colapsada .item-nav .ic { width: 18px; height: 18px; }
  html.barra-colapsada .usuario-nav { justify-content: center; }
  html.barra-colapsada .btn-sair { padding: 5px 8px; display: inline-grid; place-items: center; }
  .btn-sair { display: inline-flex; align-items: center; gap: 6px; }
  .btn-sair .ic { width: 14px; height: 14px; flex: none; }

  /* ZERA-BOLETIM / M-5 — saída de contexto no rail colapsado.
     A saída "sair" mora dentro do `.grupo-nav` "Acesso rápido", e o `.grupo-nav` é
     `display:none` colapsado (linha 971): o NOTA-FINAL §3.15 mediu 1 saída expandida → 0
     colapsada no hub e no /resultado. O gêmeo ícone-só de `base.html` só existe aqui, no
     estado colapsado; expandida ele fica fora do fluxo e do foco (`display:none`), pra não
     duplicar controle. Herda `.item-nav` (alvo de 44px, hover, tooltip por `data-rot`). */
  html.barra-colapsada .sair-rail { display: block; margin: 2px 0 4px; }
  html.barra-colapsada .item-sair-rail {
    width: 100%; appearance: none; background: transparent; cursor: pointer;
    border: 0; border-left: 2px solid transparent; color: var(--nav-ink); font: inherit;
  }
  html.barra-colapsada .item-sair-rail:hover { background: var(--nav-3); }
  html.barra-colapsada .item-sair-rail .ic { opacity: .75; }

  /* tooltip do estado colapsado — o rótulo não some, muda de lugar */
  html.barra-colapsada .item-nav[data-rot] { position: relative; }
  html.barra-colapsada .item-nav[data-rot]::after {
    content: attr(data-rot);
    position: absolute; left: calc(100% + 10px); top: 50%; transform: translateY(-50%);
    z-index: 60; white-space: nowrap; pointer-events: none;
    padding: 5px 10px; border-radius: var(--r-cartao);
    background: var(--sup-chrome); color: var(--txt-chrome); border: 1px solid var(--fio-chrome-forte);
    box-shadow: var(--sombra-2); font-size: 12px; font-weight: 500;
    opacity: 0; visibility: hidden; transition: opacity var(--t) var(--mola);
  }
  html.barra-colapsada .item-nav[data-rot]:hover::after,
  html.barra-colapsada .item-nav[data-rot]:focus-visible::after { opacity: 1; visibility: visible; }
}
@media (prefers-reduced-motion: reduce) {
  .sidebar, aside.navbar-vertical, .btn-colapsar .ic { transition: none; }
}

/* G-1 (boletim NOTA-FINAL 26/08, régua 2): no DESKTOP o par sem valor também não rende —
   a célula fica na grade (alinhamento de tabela), mas SEM conteúdo: nada de `—` nem
   sobrancelha órfã. O mobile já fazia isso no reflow de cartão (bloco CL-6); esta regra é a
   versão de tabela, fora de media query de propósito. */
.v2 .tabela-carteira td[data-vazio] > *,
.v2 .tabela-carteira td .p1[data-vazio],
.v2 .tabela-carteira td .p2[data-vazio] { display: none; }

/* ══════════════════════════ COMPONENTES DA MAQUETE V1 (escopo `.v2`) ══════════════════ */

.v2 { min-width: 0; }
.v2 h1, .v2 h2, .v2 h3 { font-family: var(--f-titulo); font-weight: 600; letter-spacing: -.012em; margin: 0; }
.v2 .num, .v2 td, .v2 th, .v2 .kpi-valor, .v2 .valor { font-variant-numeric: tabular-nums; }

/* ─── KPI: UMA família (navy) diferenciada por lavagem + fio + ícone fantasma ───
 * Resolve o risco que a própria FICHA-TAXRESEARCH §5 nomeia ("5 cores fortes na mesma tela
 * cansa") sem perder o código de cor: a cor entra no fio de 3px e no fantasma, não no fundo. */
.v2 .grade-kpi { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--e-4);
  margin-bottom: var(--e-4); }
.v2 .kpi {
  position: relative; overflow: hidden; min-height: var(--kpi-alt);
  padding: 15px 16px 14px; border-radius: var(--r-painel); color: var(--txt-chrome);
  background:
    radial-gradient(120% 130% at 100% 0%, var(--kpi-lavagem) 0%, transparent 62%),
    linear-gradient(158deg, var(--sup-chrome-2) 0%, var(--sup-chrome) 70%);
  box-shadow: var(--sombra-2); border: 1px solid var(--sup-chrome-borda);
  transition: transform var(--t) var(--mola), box-shadow var(--t) var(--mola);
}
.v2 .kpi::before { content: ""; position: absolute; inset: 0 0 auto 0; height: var(--kpi-fio);
  background: var(--kpi-cor); }
.v2 .kpi:hover { transform: translateY(-2px); box-shadow: var(--sombra-3); }
.v2 .kpi .rot { font-size: 9.5px; letter-spacing: .19em; text-transform: uppercase;
  color: var(--txt-chrome-2); font-weight: 600; margin: 0; }
.v2 .kpi-valor { font-family: var(--f-titulo); font-size: 34px; font-weight: 600; line-height: 1.05;
  letter-spacing: -.022em; margin: 9px 0 0; color: var(--txt-chrome); /* explícito: o cartão pode
  ser <a> (kpi-link) e regra direta no wrapper vence herança — não depender do pai */ }
/* CL-2 (25/08/2026): `.kpi-valor .un` era o SEGUNDO desenho do registro compacto no produto —
   "R$ 6,1" + a unidade em ouro 16px colada, só em `/clientes`, contra o texto corrido
   "R$ 1,3 mi" que o hub (`_kpis_caso.html` + `_brl_compacto`) já servia. §Números pede UM
   registro compacto: ficou o do hub, e `dados.kpis_da_carteira` deixou de emitir `un`. A regra
   sai do arquivo em vez de virar CSS morto. */
.v2 .kpi .pe { margin: 7px 0 0; font-size: 11.5px; color: var(--txt-chrome-2);
  display: flex; align-items: center; gap: 6px; }
.v2 .kpi .pe b { color: var(--txt-chrome); font-weight: 600; }
.v2 .kpi .fantasma { position: absolute; right: -14px; bottom: -20px; width: 104px; height: 104px;
  color: var(--kpi-cor); opacity: .20; pointer-events: none; }
.v2 .kpi-a { --kpi-cor: var(--dado-1); --kpi-lavagem: var(--p-lav-azul); }
.v2 .kpi-b { --kpi-cor: var(--dado-2); --kpi-lavagem: var(--p-lav-ouro); }
.v2 .kpi-c { --kpi-cor: var(--dado-3); --kpi-lavagem: var(--p-lav-laranja); }
.v2 .kpi-d { --kpi-cor: var(--dado-4); --kpi-lavagem: var(--p-lav-violeta); }

/* ─── cartão ─── */
.v2 .cartao-v2 { background: var(--sup-papel); border: 1px solid var(--fio);
  border-radius: var(--r-painel); box-shadow: var(--sombra-1); }
.v2 .cartao-v2 > header { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 11px 16px; border-bottom: 1px solid var(--fio); }
.v2 .cartao-v2 > header h2 { font-size: 15px; }
.v2 .cartao-v2 > header .dir { margin-left: auto; display: flex; align-items: center; gap: 6px; }
.v2 .legenda { font-size: 11.5px; color: var(--txt-3); }

/* ─── chips de filtro ─── */
.v2 .chips { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin: 0; }
.v2 .chips .chip {
  display: inline-flex; align-items: center; gap: 7px; height: auto;
  padding: 0 12px; border-radius: var(--r-pilula); border: 1px solid var(--fio);
  background: var(--sup-papel); color: var(--txt-2); text-decoration: none;
  transition: background var(--t) var(--mola), border-color var(--t) var(--mola),
              color var(--t) var(--mola);
}
/* a DENSIDADE do chip (29px, 12,5px) é do desktop. No celular vale o alvo de toque de 44px que
   a v1 garante — o `min-height: 29px` global reprovava `test_body_nunca_rola_de_lado_em_390px`
   em 3 chips (medido). Mobile-first: a regra do dedo é a de fora da media query. */
@media (min-width: 1024px) {
  .v2 .chips .chip { min-height: 29px; font-size: 12.5px; }
  .v2 .btn-v2 { min-height: 0; height: 32px; padding: 0 13px; font-size: 13px; }
}
.v2 .chips .chip:hover { border-color: var(--fio-forte); background: var(--sup-papel-2); }
.v2 .chips .chip .n { font-size: 11px; color: var(--txt-3); font-variant-numeric: tabular-nums; }
.v2 .chips .chip[aria-pressed="true"] { background: var(--sup-chrome); border-color: var(--sup-chrome);
  color: var(--txt-chrome); font-weight: 600; }
.v2 .chips .chip[aria-pressed="true"] .n { color: var(--marca-clara); }

/* ─── badge pastel por enum (canal de ESTADO, nunca o ouro) ───
 * Classe PRÓPRIA (`.badge-v2`) e não um override de `.badge`: a lista em cartão do celular é
 * markup herdado e usa `.badge.ok/.warn/.bad/.na`. Redefinir `.badge` dentro de `.v2` deixaria
 * aqueles sem `--b-tint` e eles renderizariam sem fundo. */
.v2 .badge-v2 {
  display: inline-flex; align-items: center; gap: 6px; height: 21px; padding: 0 9px;
  border: 0; border-radius: var(--r-pilula); font-size: 11.5px; font-weight: 600;
  white-space: nowrap; background: var(--b-tint); color: var(--b-cor);
}
.v2 .badge-v2::before { content: ""; width: 5px; height: 5px; border-radius: 50%;
  background: currentColor; flex: none; }
.v2 .badge-v2.sem-ponto::before { display: none; }
.v2 .b-neutro      { --b-cor: var(--est-neutro);      --b-tint: var(--est-neutro-tint); }
/* F-52: `--b-cor` é `color` do crachá (texto + ponto) sobre `--b-tint` — papel de TEXTO. */
.v2 .b-processando { --b-cor: var(--est-processando-txt); --b-tint: var(--est-processando-tint); }
.v2 .b-ok          { --b-cor: var(--est-ok);          --b-tint: var(--est-ok-tint); }
.v2 .b-negativo    { --b-cor: var(--est-negativo);    --b-tint: var(--est-negativo-tint); }
.v2 .b-terceiro    { --b-cor: var(--est-terceiro);    --b-tint: var(--est-terceiro-tint); }
.v2 .b-na          { --b-cor: var(--est-na);          --b-tint: var(--est-na-tint); }

/* ─── tabela densa: 7 colunas, DOIS níveis por célula, zero rolagem lateral ───
 * O defeito herdado era tabela de 9-10 colunas que empurrava o documento a 1585px numa janela
 * de 1536. Aqui o 2º nível desce para dentro da célula (p2) em vez de virar coluna nova.
 * CONSOLIDAÇÃO (Lote 0, 25/08/2026): esta gramática nasceu presa a `.v2` (só a tela piloto
 * `/clientes` a usava). Os tokens (`--fio`, `--txt-1`, `--f-mono`...) já são `:root` globais —
 * a amarra a `.v2` não tinha efeito nenhum além de IMPEDIR os outros 11 templates de usar
 * `.tabela` sem herdar o resto do vocabulário `.v2` (chips/badges/kpi), que é trabalho dos
 * Lotes 1-8, não deste. De-escopada: `.tabela` vira componente global, como `table.densa` era. */
.tabela { width: 100%; border-collapse: collapse; font-size: 13px; table-layout: fixed; }
.tabela thead th {
  text-align: left; padding: 8px 12px; background: var(--sup-papel-2);
  border-bottom: 1px solid var(--fio); font-size: 9.5px; letter-spacing: .15em;
  text-transform: uppercase; color: var(--txt-3); font-weight: 600; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.tabela thead th.dir, .tabela td.dir { text-align: right; }
/* a 1ª coluna é a única que quebra: reserva de largura para não ser espremida pelas
   colunas `nowrap` (defeito medido na 1ª rodada de render da maquete) */
.tabela th:first-child { width: 25%; }
.tabela tbody tr { border-bottom: 1px solid var(--fio);
  transition: background var(--t) var(--mola); }
.tabela tbody tr:hover { background: var(--sup-papel-2); }
.tabela tbody tr:last-child { border-bottom: 0; }
.tabela td { padding: 9px 12px; vertical-align: middle; min-height: var(--tabela-linha);
  overflow: hidden; }
/* numa tabela densa o 1º nível também é UMA linha: o CNPJ mascarado em mono partia no meio
   ("**.***.***/0001-" + "**") e virava duas linhas de cara (medido no render) */
.tabela td .p1 { font-weight: 600; color: var(--txt-1); line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* o 2º nível ocupa UMA linha e recorta: sem `nowrap` um campo de texto livre empurra a linha
   da tabela para 5 linhas de altura e a densidade da vista morre (medido no 1º render) */
.tabela td .p2 { font-size: 11.5px; color: var(--txt-3); line-height: 1.3; margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tabela td a.p1 { text-decoration: none; }
.tabela td a.p1:hover { text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: var(--marca); text-decoration-thickness: 2px; }
/* dinheiro nunca quebra entre "R$" e o número (defeito medido na 1ª rodada) */
.tabela td.dir .p1, .tabela td.dir .p2 { white-space: nowrap; }
/* F-52 (decisão 4 do dono, 27/08 ~10h44 BRT): "aumentar minimamente o espaço pra direita que a
   faixa ocupa pra destacar melhor o status dela". A faixa passou a ser o ÚNICO portador da cor
   de estado na listagem de teses (a coluna Semáforo saiu por decisão 3) — 3px de sliver não
   sustentam sozinhos o que antes tinha uma coluna inteira de texto ao lado.
   3px → 6px e a altura vai de `6px` para `3px` de folga: a faixa lê como barra, não como fio.
   Global de propósito: `.tabela` é componente do DS e faixa de 6px na biblioteca contra 3px em
   clientes/monitor seria a inconsistência que a régua do dia proíbe. Reverte em duas medidas. */
.tabela .marcador { position: relative; padding-left: 20px; }
.tabela .marcador::before { content: ""; position: absolute; left: 0; top: 3px; bottom: 3px;
  width: 6px; border-radius: 0 3px 3px 0; background: var(--m-cor, var(--fio)); }
.tabela .m-ok     { --m-cor: var(--est-ok); }
.tabela .m-proc   { --m-cor: var(--est-processando); }
.tabela .m-neutro { --m-cor: var(--est-neutro); }
.tabela .m-neg    { --m-cor: var(--est-negativo); }
.tabela .m-terc   { --m-cor: var(--est-terceiro); }
.tabela .m-na     { --m-cor: var(--est-na); }
/* variantes por NOME DE COR literal (verde/amarelo/vermelho/preto) — é o vocabulário que
   `teses_curadoria.py`/`dados.py` já usam (`SEMAFOROS`/`SEMAFOROS_DONO`) e que os templates
   herdados de `table.densa` passam direto pro marcador (`t.semaforo`, `g.cor`). Mesma cobertura
   que `table.densa td.marcador.*` tinha — inclusive o mesmo buraco: "cinza" não tem cor própria
   e cai no fio neutro (`var(--fio)`, o fallback do `::before` acima), igual já caía antes. */
.tabela .marcador.verde    { --m-cor: var(--est-ok); }
.tabela .marcador.amarelo  { --m-cor: var(--est-processando); }
.tabela .marcador.vermelho,
.tabela .marcador.preto    { --m-cor: var(--est-negativo); }
/* `.num`/`th.num` — nome antigo de `.dir`, mesma função (alinhamento à direita + mono +
   tabular-nums), preservado porque é o que os 11 templates herdados já escrevem. */
.tabela td.num, .tabela th.num { text-align: right; font-family: var(--f-mono);
  white-space: nowrap; font-variant-numeric: tabular-nums; }
/* mono sem o wrapper `.p1`/`.p2` (blocos técnicos de 2 colunas: rótulo | valor mono) — sem isto
   o `.mono` global (app.css:203) impõe 14px fixo e destoa da linha da tabela (13px). */
.tabela td.mono, .tabela td .mono { font-size: inherit; }
/* `.nowrap` puro (sem `.p1`) numa célula de `.tabela` herda `overflow:hidden` da regra base —
   sem `text-overflow:ellipsis` o corte é MUDO (medido: `_tabela_teses.html`, referência de
   431px cortada a 145px sem "…", achado no print de prova deste lote). Mesmo tipo de corte que
   `.p1`/`.p2` já sinalizam — aqui só faltava a mesma reticência. */
.tabela td.nowrap { text-overflow: ellipsis; }
/* `.acoes` — coluna de ações com chip(s); some a rolagem lateral que a v1 media entrando na
   coluna (P1/D3 do histórico do `table.densa`). Não usada pelos 11 templates deste lote (nenhum
   tinha `td.acoes`), portada porque o Lote 4/7 (biblioteca) é candidato natural a precisar dela
   e a gramática tem que cobrir a variante, não só o uso corrente. */
.tabela td.acoes { white-space: normal; width: 1%; min-width: 150px; }
.tabela td.acoes .chip { margin: 0 3px 3px 0; }
.tabela td.acoes .linha-atalhos { display: flex; flex-wrap: wrap; gap: 4px; margin: 0 0 8px; }
.tabela td.acoes .gerir-painel { min-width: 200px; }
@media (min-width: 640px) {
  .tabela td .chip { min-height: 32px; padding: 5px 9px; }
  .tabela td.acoes { min-width: 190px; }
}
@media (min-width: 1024px) {
  .tabela td .chip { padding: 2px 7px; min-height: 0; }
  .tabela td.acoes { min-width: 104px; }
}
.v2 .valor { font-family: var(--f-titulo); font-size: 15px; font-weight: 600;
  letter-spacing: -.015em; white-space: nowrap; }
.v2 .faixa { font-size: 11px; color: var(--txt-3); white-space: nowrap; }
.v2 .mono { font-family: var(--f-mono); }

/* ─── botão ─── */
/* 44px de altura é o piso do dedo (o mesmo que a v1 garante); os 32px da maquete são a
   densidade do DESKTOP e entram na media query abaixo. `test_body_nunca_rola_de_lado_em_390px`
   mediu o botão a 32px em 390px e reprovou — com razão. */
.v2 .btn-v2 {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  min-height: 44px; padding: 0 16px; border-radius: var(--r-cartao); font-size: 14px;
  font-weight: 500; white-space: nowrap; text-decoration: none;
  border: 1px solid transparent; background: var(--acao); color: var(--acao-txt);
  cursor: pointer; font-family: inherit;
  transition: background var(--t) var(--mola), transform var(--t) var(--mola),
              box-shadow var(--t) var(--mola);
}
.v2 .btn-v2:hover { background: var(--acao-forte); box-shadow: var(--sombra-2); }
.v2 .btn-v2:active { transform: translateY(1px); }
.v2 .btn-v2 .ic { width: 15px; height: 15px; }
.v2 .btn-2 { background: var(--sup-papel); color: var(--txt-1); border-color: var(--fio-forte); }
.v2 .btn-2:hover { background: var(--sup-papel-2); box-shadow: var(--sombra-1); }

/* ─── cabeçalho de página: o eyebrow com fio de marca e o título em Fraunces da maquete,
 *     aplicados ao `.page-header` que TODA tela já tem. Um <h1> por página, não dois. ─── */
.page-header .eyebrow { display: flex; align-items: center; gap: 7px;
  font-family: var(--f-corpo); font-size: 10px; letter-spacing: .19em; text-transform: uppercase;
  color: var(--marca-texto); font-weight: 600; margin: 0 0 4px; }
.page-header .eyebrow::before { content: ""; width: 14px; height: 2px; background: var(--marca); }
@media (min-width: 1024px) {
  .page-header h1 { font-size: 24px; line-height: 1.15; }
  .page-header .sub { font-family: var(--f-corpo); font-size: 13px; }
}

/* ─── utilitário: some da tela, continua no leitor ─── */
.so-leitor { position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; }

/* ─── empty state padronizado (padrão TaxResearch obrigatório, FORM-1 §4) ─── */
.v2 .vazio { display: grid; justify-items: center; text-align: center; gap: 5px;
  padding: 40px 24px; color: var(--txt-3); }
.v2 .vazio .anel { width: 52px; height: 52px; border-radius: 50%; display: grid;
  place-items: center; background: var(--sup-papel-2); border: 1px solid var(--fio);
  color: var(--marca-texto); margin-bottom: 7px; }
.v2 .vazio .anel .ic { width: 22px; height: 22px; }
.v2 .vazio h3 { font-size: 16px; color: var(--txt-1); }
.v2 .vazio p { font-size: 13px; max-width: 46ch; margin: 0; }

/* ─── aviso/erro: frase completa, com a consequência dita ─── */
.v2 .aviso-v2 { display: flex; gap: 10px; padding: 11px 13px; border-radius: var(--r-cartao);
  font-size: 12.5px; line-height: 1.45; border-left: 3px solid var(--n-cor);
  background: var(--n-tint); color: var(--txt-2); margin-bottom: var(--e-4); }
.v2 .aviso-v2 .ic { width: 16px; height: 16px; flex: none; color: var(--n-cor); margin-top: 1px; }
.v2 .aviso-v2 b { color: var(--txt-1); }
.v2 .aviso-piloto .aviso-corpo { display: block; width: 100%; min-width: 0; }
.v2 .aviso-piloto ul { margin: 6px 0; padding-left: 20px; }
.v2 .aviso-piloto p { margin: 6px 0 0; }
.v2 .n-info    { --n-cor: var(--est-neutro);      --n-tint: var(--est-neutro-tint); }
.v2 .n-atencao { --n-cor: var(--est-processando); --n-tint: var(--est-processando-tint); }
.v2 .n-ok      { --n-cor: var(--est-ok);          --n-tint: var(--est-ok-tint); }
.v2 .n-erro    { --n-cor: var(--est-negativo);    --n-tint: var(--est-negativo-tint); }

/* ─── degradação: a maquete degrada em 1360 e 1180; o celular fica com a lista em cartão ─── */
@media (max-width: 1360px) { .v2 .grade-kpi { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 900px) {
  .v2 .grade-kpi { grid-template-columns: 1fr; }
  .v2 .rolagem-v2 { overflow-x: auto; }
}

/* ─── larguras da tabela da carteira: somam 100% e `table-layout:fixed` as respeita, então o
 *     documento não fica mais largo que a janela por construção — e não por sorte de conteúdo.
 *     A 1ª coluna é a única que pode quebrar em duas linhas; as demais recortam com reticências. */
/* Somam 100% e `table-layout:fixed` as respeita. Calibradas contra o render, não no chute:
   a 9% e a 13% o par "Abrir + menu" da coluna Ação ainda quebrava em duas linhas, e a 14% o
   CNPJ mascarado em mono partia no meio. */
.v2 .tabela-carteira th:nth-child(1) { width: 22%; }   /* Cliente        */
.v2 .tabela-carteira th:nth-child(2) { width: 15%; }   /* CNPJ           */
.v2 .tabela-carteira th:nth-child(3) { width: 11%; }   /* Regime · UF    */
.v2 .tabela-carteira th:nth-child(4) { width:  5%; }   /* Casos          */
/* CL-3 alargou o 6º cabeçalho ("Crédito apurado" → "Crédito atualizado (SELIC)", o rótulo
   canônico): 15% recortava o texto com reticências a 1536px. O 1% vem de "Situação" e o outro
   de "Ação", que sobravam — a soma continua 100% e `table-layout:fixed` continua respeitando. */
.v2 .tabela-carteira th:nth-child(5) { width: 16%; }   /* Situação       */
.v2 .tabela-carteira th:nth-child(6) { width: 17%; }   /* Crédito atualizado (SELIC) */
.v2 .tabela-carteira th:nth-child(7) { width: 14%; }   /* Ação           */
/* a célula de ação abriga o botão e o menu lado a lado, alinhados à direita */
.v2 .tabela-carteira td.dir .gerir-caso { display: inline-block; margin-left: 6px;
  vertical-align: middle; }
.v2 .tabela-carteira td.dir .btn-v2 { vertical-align: middle; }

/* ─── larguras dos 11 templates herdados (Lote 0, 25/08/2026): mesma lógica da carteira acima —
 *     somam 100%, `table-layout:fixed` respeita, documento não passa da janela por construção.
 *     `.tabela-tec` é o par rótulo|valor dos blocos "Detalhes técnicos" (5 templates reusam o
 *     mesmo padrão de 2 colunas sem thead — table-layout:fixed sem largura própria cairia em
 *     50/50, largo demais pro rótulo). */
.tabela-tec td:first-child { width: 30%; color: var(--txt-2); }
.tabela-trilha th:nth-child(1) { width: 16%; }  /* Quando (mono) */
.tabela-trilha th:nth-child(2) { width: 14%; }  /* Quem */
.tabela-trilha th:nth-child(3) { width: 20%; }  /* Ação */
.tabela-trilha th:nth-child(4) { width: 50%; }  /* Motivo — texto livre */
.tabela-teses th:nth-child(1) { width: 12%; }   /* Referência */
.tabela-teses th:nth-child(2) { width: 26%; }   /* Tese */
.tabela-teses th:nth-child(3) { width: 13%; }   /* Semáforo */
.tabela-teses th:nth-child(4) { width: 13%; }   /* Curadoria */
.tabela-teses th:nth-child(5) { width: 18%; }   /* Setores */
.tabela-teses th:nth-child(6) { width:  6%; }   /* Eixos (num) */
.tabela-teses th:nth-child(7) { width:  6%; }   /* Pendências (num) */
.tabela-teses th:nth-child(8) { width:  6%; }   /* Prioridade (num) */
.tabela-monitor th:nth-child(1) { width: 14%; } /* Quando (mono nowrap) */
.tabela-monitor th:nth-child(2) { width: 12%; } /* Fonte */
.tabela-monitor th:nth-child(3) { width:  6%; } /* UF */
.tabela-monitor th:nth-child(4) { width: 16%; } /* Termo */
.tabela-monitor th:nth-child(5) { width: 20%; } /* Teses tocadas */
.tabela-monitor th:nth-child(6) { width: 32%; } /* Trecho — texto livre */
.tabela-cofre th:nth-child(1) { width: 40%; }   /* Arquivo (mono) */
.tabela-cofre th:nth-child(2) { width: 15%; }   /* Tamanho (num) */
.tabela-cofre th:nth-child(3) { width: 25%; }   /* Recebido */
.tabela-cofre th:nth-child(4) { width: 20%; }   /* Ações */
.tabela-leitura-arq th:nth-child(1) { width: 22%; } /* Arquivo enviado (mono) */
.tabela-leitura-arq th:nth-child(2) { width: 12%; } /* Competência */
.tabela-leitura-arq th:nth-child(3) { width: 20%; } /* Empresa */
.tabela-leitura-arq th:nth-child(4) { width:  8%; } /* Linhas (num) */
.tabela-leitura-arq th:nth-child(5) { width: 38%; } /* O que veio dentro — texto livre */

/* ─── .tabela-rolavel — mitigação C aprovada na tortura de volume (25/08/2026): container de
 *     altura contida com overflow interno + cabeçalho fixo. Fonte:
 *     despachos/design-system-25-08/extras/volume/{volume.html,RELATORIO-VOLUME.md} §Q1/Q3
 *     (`body.mit-scroll #casos-wrap`/`#ops-wrap`, medido funcionando com 180 e 300 linhas —
 *     `wrapClientH` estabiliza em 480px, thead continua visível rolando por baixo). Aqui vira
 *     variante OFICIAL da gramática, sempre ativa (não atrás de flag): adicionar na MESMA div
 *     `.rolagem` que já embrulha a tabela (`class="rolagem tabela-rolavel"`), nunca substituir.
 *     Aplicada em Lote 0 em 3 listas; F-14 (25/08/2026) migrou biblioteca e monitor para
 *     `.moldura-tabela` (abaixo) — a régua "lista de trabalho: sem teto" (DESIGN-SYSTEM.md
 *     §Réguas assinadas) cobre tela onde a lista É o conteúdo principal. `.tabela-rolavel`
 *     segue viva para lista SECUNDÁRIA dentro de tela composta (nenhuma tela usa hoje, 25/08).
 *     GATILHO DE TROCA (registrado, NÃO implementado aqui — decisão do coordenador/dono):
 *     a tortura mediu render linear (269ms/300 linhas, 75ms/180) — extrapola para >1s de render
 *     inicial na casa de milhares de linhas. Se uma lista real chegar lá, a resposta é paginação
 *     de verdade (opção A do RELATORIO-VOLUME.md), não esticar o `max-height` deste container. */
.tabela-rolavel { max-height: 480px; overflow-y: auto; border: 1px solid var(--fio);
  border-radius: var(--r-cartao); }
.tabela-rolavel .tabela thead th, .tabela-rolavel table.tabela thead th {
  position: sticky; top: 0; z-index: 2; background: var(--sup-papel-2);
  box-shadow: 0 1px 0 var(--fio);
}

/* ─── .moldura-tabela — régua "lista de trabalho: sem teto" (DESIGN-SYSTEM.md §Réguas
 *     assinadas 25/08, ds-fable-fila). Quando a lista É o conteúdo principal da tela (biblioteca
 *     de teses, monitor de alertas), ela não ganha altura travada nem thead sticky — só a mesma
 *     moldura visual (borda+raio) que `.tabela-rolavel` usa, sem `overflow-y`/sem `max-height`.
 *     A página rola; a lista não. F-14 (25/08/2026), aplicada primeiro por T3 em
 *     `resultado.html` (oportunidades) e agora em `_tabela_teses.html` (biblioteca) e
 *     `monitor.html` (alertas) — as três telas que a nota do T3 apontava (`resultado.html:187-193`). */
.moldura-tabela { border: 1px solid var(--fio); border-radius: var(--r-cartao); }

/* ══════════════════════════════════════════════════════════════════════════════════════════
 * LOTE 1 DA FASE B (25/08/2026) — HUB DO CASO (`/clientes/{id}`)
 *
 * Bloco NOVO, no fim do arquivo: nada acima daqui foi reescrito (o consolidado do Lote 0 fica
 * intacto). Todo seletor é escopado em `.v2` — telas ainda não portadas não sentem nada.
 * Referência de componente: `/root/design-system/showcase.html` (§coluna de contexto 383-386,
 * §chapéu 388-406, §stepper 418-458). Nenhuma cor literal: só var() de tokens.css (regra 7 do DS).
 * ═════════════════════════════════════════════════════════════════════════════════════════ */

/* ─── esqueleto de duas colunas: miolo + contexto sticky ───
 * É o padrão que as telas 2-6 do caso repetem. Nome próprio (`duas-colunas-v2`) para não
 * esbarrar na `.duas-colunas` herdada, que ainda veste tela não portada. */
/* `minmax(0, 1fr)` e não `1fr`: a pista `1fr` tem mínimo `auto`, e um filho largo (o stepper de
 * 7 etapas em 390px) ESTICA a pista em vez de rolar dentro do próprio trilho — medido em
 * 25/08 13h2x BRT, `test_body_nunca_rola_de_lado_em_390px` acusou `docScrollWidth 798` numa
 * janela de 390. Vale para as duas grades deste bloco. */
.v2 .duas-colunas-v2 { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--e-5);
  align-items: start; }
/* `grid-template-columns` explícito nas duas colunas pelo MESMO motivo: uma grade sem pista
 * declarada cria a pista implícita em `auto`, que é max-content — e volta a esticar. */
.v2 .coluna-miolo { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr);
  gap: var(--e-4); align-content: start; }
/* `align-items: start` porque abaixo de 1180px a coluna vira uma FAIXA de duas colunas: sem
 * isso o chapéu esticava até a altura do cartão de atalhos e sobrava um vazio de ~200px
 * embaixo dele (medido no print b1-04, 25/08 13h4x BRT). */
.v2 .coluna-contexto { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr);
  gap: var(--e-3); align-content: start; align-items: start; }

/* ─── chapéu do caso: navy com filete de ouro, âncora de contexto ───
 * A classe `chapeu-caso` continua no markup (dois testes a usam como prova de que a identidade
 * do caso está na página). A gramática que ela carregava é zerada aqui, ponto a ponto, e a pele
 * nova vem de `.chapeu` — mesma especificidade, e esta vem depois. */
.v2 .chapeu-caso { background: none; color: inherit; border-bottom: 0; border-radius: 0;
  padding: 0; }
.v2 .chapeu { border-radius: var(--r-painel); overflow: hidden; box-shadow: var(--sombra-2);
  border: 1px solid var(--sup-chrome-borda); }
.v2 .chapeu .capa { padding: 15px 16px 14px; color: var(--txt-chrome);
  border-top: 2px solid var(--marca);
  background: linear-gradient(158deg, var(--sup-chrome-2) 0%, var(--sup-chrome) 78%); }
.v2 .chapeu .capa .rot { font-size: 9.5px; letter-spacing: .19em; text-transform: uppercase;
  color: var(--marca-clara); font-weight: 600; margin: 0; }
.v2 .chapeu .capa h2 { font-family: var(--f-titulo); font-size: 19px; font-weight: 600;
  color: var(--txt-chrome); margin: 5px 0 0; line-height: 1.2; letter-spacing: -.012em;
  overflow-wrap: anywhere; }
.v2 .chapeu .capa .razao { font-size: 12px; color: var(--txt-chrome-2); margin: 3px 0 0;
  line-height: 1.35; overflow-wrap: anywhere; }
.v2 .chapeu .capa .cnpj { display: flex; align-items: center; gap: 7px; margin: 8px 0 0;
  font-size: 12px; color: var(--txt-chrome); }
.v2 .chapeu .capa .cnpj .cad { width: 13px; height: 13px; flex: none; color: var(--marca); }
.v2 .chapeu .base { background: var(--sup-papel); padding: 12px 16px 13px; }
/* par rótulo|valor em duas colunas: dado curto não ganha linha inteira sozinho (regra de
 * densidade do dono, §3 do GUIA-FASE-B) — vale no desktop e no celular, é o mesmo trilho. */
.v2 .chapeu .dados { display: grid; grid-template-columns: 1fr 1fr; gap: 9px 14px; margin: 0; }
.v2 .chapeu .dado dt { font-size: 9.5px; letter-spacing: .17em; text-transform: uppercase;
  color: var(--txt-3); font-weight: 600; }
.v2 .chapeu .dado dd { margin: 2px 0 0; font-size: 13px; color: var(--txt-1); font-weight: 500;
  line-height: 1.3; }
.v2 .chapeu .selos { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 11px;
  padding-top: 11px; border-top: 1px solid var(--fio); }
.v2 .chapeu .selo { display: inline-flex; align-items: center; gap: 5px; height: 21px;
  padding: 0 9px; border-radius: var(--r-pilula); background: var(--sup-papel-2);
  border: 1px solid var(--fio); font-family: var(--f-corpo); font-size: 11px;
  letter-spacing: 0; text-transform: none; color: var(--txt-2); }

/* ─── atalhos na coluna de contexto: lista vertical, ícone + dois níveis + seta ─── */
/* F-37 (26/08/2026) — sair do "Acesso rápido": discreto na LEITURA, mas alvo de toque de 44px
   (regra de mobile da casa — `test_mobile.py`) por padding, não por aumentar a letra. */
/* MOBILE-1 cluster A (26/08) — achado no caminho: `.link-sair-ctx` nasceu escopado a `.v2`
   (F-37), mas um SEGUNDO consumidor chegou depois direto no `<aside class="sidebar">`
   (CONSERTO-NOTURNO §4, "Acesso rápido" da navegação — `base.html`, fora de `.v2`; medido pelo
   mtime do arquivo: 05h08 UTC, 2min depois do meu baseline de suíte). Sem `.v2` a régua nunca
   alcançava esse segundo lugar — `test_body_nunca_rola_de_lado_em_390px` pegou o defeito
   (`button.link-sair-ctx` 37×21 em `/clientes/gole-frio` e `/…/resultado`). Tirar o prefixo
   `.v2` cobre os dois consumidores com a MESMA regra — não editei `base.html` (fronteira). */
.link-sair-ctx { display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; min-width: 44px; padding: 0 4px; background: none; border: 0; font: inherit;
  font-size: 12px; color: var(--txt-3); text-decoration: underline; text-underline-offset: 2px;
  cursor: pointer; }
.link-sair-ctx:hover { color: var(--txt-1); }
.v2 .atalhos-ctx { display: grid; }
.v2 .at-ctx { display: flex; align-items: center; gap: 10px; padding: 10px 14px;
  border-top: 1px solid var(--fio); text-decoration: none; color: inherit; min-height: 44px;
  transition: background var(--t) var(--mola); }
.v2 .atalhos-ctx > :first-child { border-top: 0; }
.v2 .at-ctx:hover { background: var(--sup-papel-2); }
.v2 .at-ctx .ic { width: 17px; height: 17px; flex: none; color: var(--marca-texto); }
.v2 .at-ctx .txt { display: grid; min-width: 0; }
.v2 .at-ctx .t { font-size: 13px; font-weight: 600; color: var(--txt-1); }
.v2 .at-ctx .s { font-size: 11.5px; color: var(--txt-3); line-height: 1.35; margin-top: 1px; }
.v2 .at-ctx .seta { width: 14px; height: 14px; flex: none; margin-left: auto;
  color: var(--marca-texto); }
/* destino que ainda não existe: fica na lista dizendo o que o destrava, sem virar link morto */
.v2 .at-ctx.mudo { opacity: .62; }
.v2 .at-ctx.mudo:hover { background: none; }


/* ─── andamento do caso: cartão colapsável em <details> nativo ───
 * F1 da FOLHA-VISUAL pede seções pesadas colapsáveis. O DS faz isso com JS + localStorage;
 * aqui é `<details>` nativo, porque criar arquivo .js está fora do território deste lote —
 * o estado não persiste entre telas, e isso está declarado no RELATORIO-FASE-B1. */
/* GB-1 (25/08/2026): estas regras vestiam o `<summary>` de um `<details>` cru. O cartão virou
 * `.disc` (disclosure próprio do DS, com motion), então a cabeça é um `<button class=
 * "disc-cabeca">` e o estado é `aria-expanded`, não o atributo `[open]`. Mesma pele. */
.v2 .andamento > .disc-cabeca { gap: 10px; flex-wrap: wrap; min-height: 44px; padding: 11px 16px; }
.v2 .andamento > .disc-cabeca h2 { font-size: 15px; }
.v2 .andamento > .disc-cabeca .legenda { font-size: 11.5px; color: var(--txt-3); }
.v2 .andamento > .disc-cabeca[aria-expanded="true"] { border-bottom: 1px solid var(--fio); }
.v2 .andamento > .disc-cabeca:hover .seta { color: var(--txt-1); }

/* ─── STEPPER-NAVEGADOR ───
 * A classe do container é `etapas` (gancho de teste). Tudo que a gramática antiga de `.etapas`
 * punha nela — painel com borda, cantos, lista vertical — é desfeito abaixo; `<fieldset>` ainda
 * traz `min-width:min-content` de fábrica, que estoura grid, e por isso vai a zero explícito. */
.v2 .etapas { display: block; border: 0; margin: 0; padding: 0; min-width: 0;
  background: none; border-radius: 0; list-style: none; }
.v2 .rolagem-stepper { max-width: 100%; }
.v2 .etapas .stepper { display: flex; gap: 0; padding: 16px 10px 12px; }
.v2 .etapas .passo { flex: 1; position: relative; display: flex; flex-direction: column;
  align-items: center; gap: 7px; padding: 0 4px; text-align: center; cursor: pointer;
  min-width: 0; }
.v2 .etapas .passo::before, .v2 .etapas .passo::after { content: ""; position: absolute;
  top: calc(var(--passo-diam) / 2 - 1px); height: 2px; background: var(--fio); }
.v2 .etapas .passo::before { left: 0; right: 50%;
  margin-right: calc(var(--passo-diam) / 2 + 6px); }
.v2 .etapas .passo::after { left: 50%; right: 0;
  margin-left: calc(var(--passo-diam) / 2 + 6px); }
.v2 .etapas .passo:first-of-type::before, .v2 .etapas .passo:last-of-type::after { display: none; }
.v2 .etapas .passo .bolha { width: var(--passo-diam); height: var(--passo-diam);
  border-radius: 50%; display: grid; place-items: center; position: relative; z-index: 2;
  font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums;
  background: var(--sup-papel); border: 1.5px solid var(--fio-forte); color: var(--txt-3);
  transition: transform var(--t) var(--mola), box-shadow var(--t) var(--mola),
              background var(--t) var(--mola), border-color var(--t) var(--mola); }
.v2 .etapas .passo .bolha .ck { width: 15px; height: 15px; }
.v2 .etapas .passo .rot { font-size: 10px; letter-spacing: .12em; text-transform: uppercase;
  font-weight: 600; color: var(--txt-3); line-height: 1.3; }
.v2 .etapas .passo .rot-estado { font-size: 10.5px; color: var(--txt-3); }
.v2 .etapas .passo:hover .bolha { transform: translateY(-2px); box-shadow: var(--sombra-2); }
/* estados — mapeados do dado em `_etapas.html`; 'atual' é PRÓXIMA PENDENTE, não "em curso" */
.v2 .etapas .passo[data-estado="feita"] .bolha { background: var(--sup-chrome);
  border-color: var(--sup-chrome); color: var(--marca-clara); }
.v2 .etapas .passo[data-estado="feita"]::before,
.v2 .etapas .passo[data-estado="feita"]::after { background: var(--sup-chrome-3); }
.v2 .etapas .passo[data-estado="feita"] .rot { color: var(--txt-2); }
.v2 .etapas .passo[data-estado="atual"] .bolha { background: var(--sup-chrome);
  border-color: var(--marca); color: var(--marca-clara);
  box-shadow: 0 0 0 3px var(--p-lav-ouro); }
.v2 .etapas .passo[data-estado="atual"] .rot { color: var(--txt-1); }
.v2 .etapas .passo[data-estado="atual"] .rot-estado { color: var(--marca-texto);
  font-weight: 600; }
.v2 .etapas .passo[data-estado="atual"]::before { background: var(--sup-chrome-3); }

/* painel da etapa escolhida */
.v2 .etapas .paineis { border-top: 1px solid var(--fio); }
.v2 .etapas .painel-passo { display: none; padding: 15px 18px 17px; }
.v2 .etapas .painel-passo .titulo { display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap; margin-bottom: 5px; }
.v2 .etapas .painel-passo h3 { font-size: 16px; }
.v2 .etapas .painel-passo .detalhe { margin: 0; font-size: 13.5px; color: var(--txt-2);
  line-height: 1.5; max-width: 74ch; }
.v2 .etapas .painel-passo .carimbo-linha { margin: 6px 0 0; font-size: 12px; color: var(--txt-3);
  font-variant-numeric: tabular-nums; }
/* CTA do passo em curso dentro do painel (ADENDO 2, 25/08) — herdou a régua do extinto
 * .passo-agora: mesma instrução, mesmo botão, agora um nível mais dentro do cartão. */
.v2 .etapas .painel-passo .instrucao { margin: 10px 0 0; font-size: 14px; color: var(--txt-1);
  line-height: 1.5; max-width: 70ch; }
.v2 .etapas .painel-passo .btn-v2 { margin-top: 13px; }

/* O rádio cobre a etapa inteira, transparente: o alvo de toque é a etapa, não um controle de
 * 1px — e o teclado continua tendo o grupo de rádio nativo (setas, Home/End, foco). */
.v2 .etapas .passo .et-radio { position: absolute; inset: 0; z-index: 3; margin: 0;
  opacity: 0; cursor: pointer; appearance: none; }
/* estado escolhido e foco: genéricos, sem uma regra por índice */
.v2 .etapas .passo:has(.et-radio:checked) .rot { color: var(--txt-1);
  text-decoration: underline; text-underline-offset: 4px;
  text-decoration-color: var(--marca); text-decoration-thickness: 2px; }
.v2 .etapas .passo:has(.et-radio:focus-visible) .bolha { outline: 2px solid var(--marca-texto);
  outline-offset: 3px; }
/* A troca de painel é CSS puro. Sete regras escritas à mão porque a jornada tem sete etapas
 * fixas (`dados.ETAPAS_CASO`) — se ela crescer, cresce aqui junto. */
.v2 .etapas:has(#et-01:checked) .paineis [data-painel="01"],
.v2 .etapas:has(#et-02:checked) .paineis [data-painel="02"],
.v2 .etapas:has(#et-03:checked) .paineis [data-painel="03"],
.v2 .etapas:has(#et-04:checked) .paineis [data-painel="04"],
.v2 .etapas:has(#et-05:checked) .paineis [data-painel="05"],
.v2 .etapas:has(#et-06:checked) .paineis [data-painel="06"],
.v2 .etapas:has(#et-07:checked) .paineis [data-painel="07"] { display: block; }

/* ─── KPI do caso: mesma família da tela piloto, cor SEMÂNTICA no fio ───
 * Desvio declarado do GUIA-FASE-B (que dizia `kpi-a..d`): aqui a cor quer dizer alguma coisa
 * (seguro/provável/condicionado/exposição), e o §12 do JULGAMENTO-REDESIGN manda o valor ficar
 * em tinta e a cor viver no filete. As variantes abaixo só trocam as duas custom properties
 * que a família já usa — o componente é o mesmo. */
.v2 .kpi-seguro    { --kpi-cor: var(--est-ok);        --kpi-lavagem: var(--est-ok-tint); }
.v2 .kpi-provavel  { --kpi-cor: var(--est-processando); --kpi-lavagem: var(--est-processando-tint); }
.v2 .kpi-cond      { --kpi-cor: var(--est-terceiro);  --kpi-lavagem: var(--p-lav-violeta); }
.v2 .kpi-exposicao { --kpi-cor: var(--est-negativo);  --kpi-lavagem: var(--est-negativo-tint); }
/* dinheiro é longo: 2 por linha, e o corpo cai de 34px para 28px. Medido contra o maior valor
 * real do caso de prova (`R$ 1.345.358,34`, gole-frio) — a 34px em 4 colunas ele passava da
 * caixa. */
.v2 .kpi-dinheiro { grid-template-columns: repeat(2, 1fr); }
.v2 .kpi-dinheiro .kpi-valor { font-size: 28px; }
/* P10: a faixa do condicionado sai em duas linhas NO MESMO corpo de tipo dos vizinhos. Os DOIS
 * números ficam a 28px — só as palavras de ligação ("de", "a") encolhem. Encolher o número era
 * exatamente o defeito: o maior valor da fileira aparecia como o menor da tela.
 * O nome é `faixa-valor` e NÃO `faixa` porque `.v2 .faixa` já existe (rodapé de célula da tela
 * piloto, `app.css` acima) e vem depois de `.v2 .kpi-valor` no arquivo: com o nome colidindo, o
 * valor do condicionado saía a `--txt-3` sobre o navy do cartão — medido em 25/08 13h5x BRT:
 * cor computada 85/100/106 contra 243/238/227 dos vizinhos (o mesmo `--txt-chrome`). */
.v2 .kpi-dinheiro .kpi-valor.faixa-valor { display: grid; line-height: 1.14; }
.v2 .kpi-dinheiro .kpi-valor.faixa-valor .lig { font-size: .46em; font-weight: 500;
  color: var(--txt-chrome-2); letter-spacing: .02em; }
.v2 .nota-kpi { margin: -6px 0 0; }

/* ─── detalhes técnicos: mesmo cartão do resto, no fim da página ─── */
.v2 details.tecnico { margin-top: var(--e-5); border-radius: var(--r-painel); }

/* ─── degraus ───
 * ≥1180: as duas colunas abrem e o contexto gruda. Abaixo disso a coluna de contexto vira uma
 * FAIXA no topo (chapéu | atalhos lado a lado) — a identidade do caso não pode cair para o pé
 * da página só porque a janela encolheu. */
@media (min-width: 1181px) {
  .v2 .duas-colunas-v2 { grid-template-columns: minmax(0, 1fr) var(--coluna-larg); }
  .v2 .coluna-contexto { position: sticky; top: calc(var(--topo-alt) + 20px); }
}
@media (max-width: 1180px) {
  .v2 .coluna-contexto { order: -1; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
@media (max-width: 900px) {
  .v2 .coluna-contexto { grid-template-columns: minmax(0, 1fr); }
  .v2 .kpi-dinheiro { grid-template-columns: minmax(0, 1fr); }
  /* o stepper de 7 etapas não cabe em 390px: rola DENTRO do próprio trilho, e o corpo da
     página continua sem rolagem lateral (é o que `test_mobile` mede). */
  .v2 .rolagem-stepper { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .v2 .etapas .passo { min-width: 106px; flex: none; }
  .v2 .chapeu .dados { grid-template-columns: 1fr 1fr; }
}

/* ═══ MOBILE-1 cluster E (26/08) · KPI em grid 2×2 compacto (clientes + resultado/hub) ═══
 * MEDIDO ANTES (`audit_mobile.py`, 26/08, instância 3096): `.grade-kpi`/`.kpi-dinheiro` caem
 * pra 1 COLUNA em ≤900px (regras acima, `:1244`/`:1556`) — 4 cartões de `--kpi-alt:118px`
 * empilhados = **520px = 61,6% da viewport 390×844** (RELATORIO-MOBILE-AUDIT.md #2 e #8).
 * `--kpi-alt` é medido pro desktop (rótulo+valor+pé+ícone fantasma decorativo, que não carrega
 * dado — só enfeite); no celular volta a 2 colunas com o miolo no tamanho do próprio conteúdo,
 * sem o fantasma. Escopo: só ≤639.98px — a régua de 900px acima (tablet) fica como estava. */
@media (max-width: 639.98px) {
  .v2 .grade-kpi, .v2 .kpi-dinheiro { grid-template-columns: repeat(2, 1fr);
    gap: var(--e-2); }
  .v2 .kpi { min-height: 0; padding: 10px 12px 9px; }
  .v2 .kpi .fantasma { display: none; }
  /* rot sem `white-space:nowrap` quebra em 2 linhas com texto mais longo ("Crédito atualizado
     (SELIC)", "Oportunidades apuradas") — MEDIDO: isso sozinho inflava o cartão de 62px pra
     94-96px (a única causa da diferença; confirmado por `scrollHeight` por cartão, 26/08). O
     título completo migrou pro `title` (`clientes.html`/`_kpis_caso.html`) — mesma régua do
     `.pe`, que já trunca assim (`clientes-v2-fix.css`). */
  .v2 .kpi .rot { white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    font-size: var(--fs-rotulo-m); }
  .v2 .kpi-valor, .v2 .kpi-dinheiro .kpi-valor { font-size: 22px; margin-top: 4px; }
  /* `.pe` da variante dinheiro ("nominal R$ 1.127.400,00 · atualizado pela SELIC") não tinha a
     mesma poda que `clientes-v2-fix.css` já dá ao `.pe` da tela `/clientes` (ali só se aplica
     porque só ela carrega aquela folha) — sem isto quebrava em 2 linhas (33px) em toda tela
     que usa `_kpis_caso.html` (hub/resultado). Título completo migrou pro `title` do `<p>`. */
  .v2 .kpi .pe { margin-top: 4px; display: block; white-space: nowrap; overflow: hidden;
    text-overflow: ellipsis; font-size: var(--fs-rotulo-m); }
}

/* ═══ MOBILE-1 cluster B (26/08) · escala tipográfica ≤640px (rótulo/sobrancelha → 12px,
 * corpo denso → 14px) — RELATORIO-MOBILE-AUDIT.md: "todas as telas têm nó <14px". Valores em
 * `tokens.css` (`--fs-rotulo-m`/`--fs-corpo-m`); aqui só a REFERÊNCIA, por seletor, sem duplicar
 * o número. Fora daqui (não mexido, por desenho): `<label>` de formulário (fora dos 6 padrões
 * do cluster A e fora do escopo de B, que é sobre DENSIDADE de leitura, não todo campo) e
 * `th`/`button.ord` dentro de `<thead>` visualmente oculto (clipado a 1×1px — o texto não é
 * lido por ninguém nessa largura; mudar o tamanho não muda a legibilidade real). */
@media (max-width: 639.98px) {
  .v2 .legenda { font-size: var(--fs-rotulo-m); }
  /* `.andamento > .disc-cabeca .legenda` (app.css:1439) é MAIS específico que `.v2 .legenda`
     acima — empate de especificidade não existe aqui, então a genérica nunca alcançava esta
     (hub, "clique numa etapa para ver o que ela diz", 11,5px). */
  .v2 .andamento > .disc-cabeca .legenda { font-size: var(--fs-rotulo-m); }
  .v2 .badge-v2 { font-size: var(--fs-rotulo-m); }
  .v2 .etapas .passo .rot { font-size: var(--fs-rotulo-m); }
  .v2 .etapas .passo .rot-estado { font-size: var(--fs-rotulo-m); }
  .tabela td .p2 { font-size: var(--fs-corpo-m); }
}

/* b2 — cofre + leitura + rodar (fase B, lote 2, 25/08/2026).
 * As três telas reusam o vocabulário do Lote 1 (`.cartao-v2`, `.badge-v2`/`b-*`, `.btn-v2`,
 * `.aviso-v2`) SEM redesenhar componentes que já são globais e token-bridged desde o Lote 0/0b
 * (`.tabela*`, `.tecnico`, `.chip`, `.nota`, `.task-list`, `.linha-etapas`, `.placar-leitura`,
 * `<progress>`) — só a casca muda de pele, o miolo herdado já pega a cor nova pela ponte de
 * compatibilidade de `tokens.css`. Único componente NOVO de fato: o corpo do `.cartao-v2`
 * genérico, que o hub não precisou (lá cada cartão tinha filho com padding próprio: `.vazio`,
 * `.etapas`). Aqui os cartões carregam prosa/formulário direto, então o corpo pede padding. */
.v2 .cartao-v2 > .corpo { padding: 14px 16px 16px; }
.v2 .cartao-v2 > .corpo > *:first-child { margin-top: 0; }
.v2 .cartao-v2 + .cartao-v2 { margin-top: var(--e-4, 14px); }

/* ─── modal (rodar): <dialog> nativo de vendor/basecoat, restilizado nos tokens ───
 * Decisão do gotcha (GUIA §2, tela 4): adaptar o `<dialog>` que já existia em vez de trocar
 * pelo modal do DS (que não existe fora de components.html — seria criar componente sem
 * necessidade). Antes desta regra o macro só tinha `dialog::backdrop` (app.css:412) — a caixa e
 * o botão de fechar caíam no default branco do navegador, medido antes da mudança. */
.v2 dialog.dialog { border: 1px solid var(--fio); border-radius: var(--r-painel);
  box-shadow: var(--sombra-2); padding: 0; max-width: 480px; width: calc(100% - 32px);
  background: var(--sup-papel); color: var(--txt-1); }
.v2 dialog.dialog > div { position: relative; }
.v2 dialog.dialog header { padding: 18px 40px 4px 18px; }
.v2 dialog.dialog header h2 { font-size: 16px; margin: 0 0 6px; }
.v2 dialog.dialog header p { font-size: 13px; color: var(--txt-2); line-height: 1.5; margin: 0; }
/* `display:flex` (não `grid`+`place-items`): medido que um SVG filho de `display:grid` sem
 * `grid-template-columns` explícito encolhia pro min-content ERRADO do replaced element
 * (16×16 declarado virava 2×16 renderizado, headless Chrome) — mesmo defeito que `.btn-v2`
 * (que já usa `inline-flex`) nunca teve. `flex: none` no svg trava contra o mesmo encolhimento
 * em flex (min-width:auto de item flex por padrão). */
.v2 dialog.dialog [data-variant="ghost"] { position: absolute; top: 10px; right: 10px;
  width: 30px; height: 30px; display: flex; align-items: center; justify-content: center;
  background: none; border: 0; border-radius: var(--r-pilula); color: var(--txt-3); cursor: pointer; }
.v2 dialog.dialog [data-variant="ghost"]:hover { background: var(--sup-papel-2); color: var(--txt-1); }
.v2 dialog.dialog [data-variant="ghost"] svg { width: 16px !important; height: 16px !important;
  min-width: 16px; min-height: 16px; flex: none; }

/* ─────────────────────────────────────── validações da etapa (painel do passo e da tela) ── */
/* Copiado de `apresentacao.css` (patch do hub, 25/08/2026): `hub.html` não carrega esse
 * arquivo, e o mesmo bloco serve dentro do `.painel-passo` do stepper do hub e dentro do
 * cartão da tela de apresentação — por isso não desenha moldura própria, só a régua de pares. */
.v2 .validacoes-apr { margin: var(--e-3) 0 0; }
.v2 .validacoes-apr .pares {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--e-2) var(--e-4); margin: 0;
}
.v2 .validacoes-apr .par { min-width: 0; }
.v2 .validacoes-apr .par dd { margin: 0; }   /* o recuo de `dd` do navegador quebra a régua */
.v2 .validacoes-apr .par .rot {
  display: block; font-family: var(--f-mono); font-size: 9.5px; letter-spacing: .17em;
  text-transform: uppercase; color: var(--txt-3);
}
.v2 .validacoes-apr .par .v {
  display: block; font-size: 13.5px; color: var(--txt-1); line-height: 1.35;
  overflow-wrap: anywhere;
}
.v2 .validacoes-apr .par .v.pendente { color: var(--txt-3); }
.v2 .validacoes-apr .nota-alcance {
  margin: var(--e-3) 0 0; font-size: 12.5px; line-height: 1.45; color: var(--txt-2);
  padding-left: var(--e-2); border-left: 2px solid var(--marca);
}

/* cofre-fix (25/08/2026): task-list do cofre em grid de 2 colunas — o defeito nomeado era
   cada tipo de documento ocupar uma linha inteira sozinho (5 itens = 5 linhas cheias) sendo
   que titulo+detalhe+badge cabem numa célula bem mais estreita. Escopado a `.cofre-v2` — o
   `.task-list` global (leitura/resultado/_progresso_ingestao) não muda. 1 coluna só abaixo de
   640px (regra "dado curto nunca ganha linha inteira" não se aplica aqui às avessas: em 390px
   o par titulo/badge já é a linha inteira que cabe). */
.cofre-v2 .task-list {
  display: grid; grid-template-columns: 1fr; gap: 0 20px; border-top: 1px solid var(--line);
}
.cofre-v2 .task-list li {
  border-bottom: 1px solid var(--line); padding: 9px 4px; gap: 6px 12px;
}
.cofre-v2 .task-list .titulo {
  display: flex; align-items: center; gap: 7px;
}
.cofre-v2 .task-list .ic-doc {
  width: 20px; height: 20px; flex: none; color: var(--marca-texto);
}
@media (min-width: 640px) {
  .cofre-v2 .task-list { grid-template-columns: repeat(2, 1fr); }
  .cofre-v2 .task-list li { flex-wrap: nowrap; padding: 10px 6px; }
  .cofre-v2 .task-list li > div:first-child { min-width: 0; }
  .cofre-v2 .task-list li > div:last-child { flex: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
 * CONSERTOS DO JULGAMENTO DE CONSISTÊNCIA (25/08/2026) — `JULGAMENTO-CONSISTENCIA.md`
 *
 * Bloco NOVO, no fim do arquivo: nada acima daqui foi reescrito além dos quatro pontos que os
 * próprios defeitos exigiam (comentados no lugar). Zero cor literal: só var() de tokens.css.
 * ═════════════════════════════════════════════════════════════════════════════════════════ */

/* ─────────────────────── GB-1 · disclosure próprio (`.disc`), portado ───────────────────────
 * O defeito medido: `grep -c 'grid-template-rows' app.css` → 0; 12 `<details>` crus em 6 telas,
 * enquanto a §Componentes manda "disclosure próprio — grid-template-rows: 0fr → 1fr com a
 * easing da casa. Nunca `<details>` cru". O componente JÁ EXISTIA pronto em
 * `static/css/biblioteca.css:15-34` (lote 4), mas aquela folha só é carregada por
 * `/biblioteca` e `/biblioteca/<tese>`. Aqui ele é PORTADO para o CSS global — mesmas regras,
 * mesmos tokens, para as sete telas do lote. A duplicata com `biblioteca.css` é a que o próprio
 * comentário de lá previu ("mesmo seletor, mesma regra"); consolidar (apagar de lá) é decisão
 * do coordenador, e `biblioteca.css` está fora do território deste conserto. */
.v2 .disc { border: 1px solid var(--fio); border-radius: var(--r-cartao); background: var(--sup-papel);
  overflow: hidden; min-width: 0; }
.v2 .disc + .disc { margin-top: 10px; }
.v2 .disc-cabeca { display: flex; align-items: center; gap: 9px; width: 100%; min-width: 0;
  padding: 10px 13px; text-align: left; font-size: 13px; font-weight: 500; color: var(--txt-1);
  background: none; border: 0; cursor: pointer; font-family: inherit;
  transition: background var(--t) var(--mola); }
.v2 .disc-cabeca > *:not(.ic):not(.seta) { min-width: 0; overflow-wrap: anywhere; }
.v2 .disc-cabeca:hover { background: var(--sup-papel-2); }
.v2 .disc-cabeca .ic { width: 15px; height: 15px; color: var(--txt-3); flex: none; }
.v2 .disc-cabeca .seta { width: 13px; height: 13px; margin-left: auto; color: var(--txt-3);
  flex: none; transition: transform var(--t) var(--mola); }
.v2 .disc-cabeca[aria-expanded="true"] .seta { transform: rotate(90deg); }
.v2 .disc-cabeca .pista { font-size: 11.5px; color: var(--txt-3); font-weight: 400; }
.v2 .disc-caixa { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--t) var(--mola); }
.v2 .disc-cabeca[aria-expanded="true"] ~ .disc-caixa { grid-template-rows: 1fr; } /* "~" e não "+": o lápis de edição (.cj-lapis) vive ENTRE a cabeça e a caixa no roadmap (F-35) — irmão imediato quebrava a abertura pra quem edita; bronca do dono 26/08 08h20 BRT */
.v2 .disc-caixa > div { overflow: hidden; }
.v2 .disc-corpo { padding: 2px 13px 13px; border-top: 1px solid var(--fio); font-size: 12.5px;
  color: var(--txt-2); }
.v2 .disc-caixa > div > .disc-corpo { padding-top: 11px; }
@media (prefers-reduced-motion: reduce) {
  .v2 .disc-caixa, .v2 .disc-cabeca .seta { transition: none; }
}

/* variante CARTÃO: o disclosure é a casca do cartão inteiro (hub "Andamento do cliente" e os
 * cinco "Detalhes técnicos"). O corpo não desenha padding próprio — quem tem padding é o filho
 * (o stepper, a tabela técnica). */
.v2 .disc-cartao { border-radius: var(--r-painel); }
.v2 .disc-cartao > .disc-cabeca { padding: 11px 16px; min-height: 44px; }
.v2 .disc-cartao > .disc-caixa > div > .disc-corpo { padding: 0; border-top: 1px solid var(--fio);
  font-size: inherit; color: inherit; }

/* "Detalhes técnicos": a pele que `details.tecnico` (seletor de ELEMENTO, acima no arquivo)
 * dava, agora para o `.disc`. A regra antiga fica onde está — as telas fora deste território
 * (resultado, oportunidade, _progresso_ingestao, triagem) ainda servem `<details class=
 * "tecnico">`, e derrubá-la ali seria estragar tela que este lote não julgou. */
.v2 .tecnico.disc { margin-top: var(--e-5); margin-bottom: var(--gap); }
.v2 .tecnico.disc > .disc-cabeca { font-size: 14px; color: var(--txt-2); }
.v2 .tecnico.disc > .disc-caixa > div > .disc-corpo { padding: 0 14px 12px; }
.v2 .tecnico.disc .rolagem { padding: 0; }
.v2 .tecnico.disc .log { margin: 10px 14px 12px; }

/* variante CHIP: o disclosure "Gerir" da coluna Ação de `/clientes`. A cabeça tem a pele do
 * `.chip` (é o que estava lá antes, como `<summary class="chip">`); a caixa abre embaixo. */
.v2 .disc-chip { display: inline-block; border: 0; background: none; overflow: visible;
  vertical-align: middle; text-align: left; }
.v2 .disc-chip > .disc-cabeca { display: inline-flex; width: auto; gap: 5px; min-height: 0;
  padding: 2px 7px; font-size: 13px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--panel); }
.v2 .disc-chip > .disc-cabeca .seta { width: 12px; height: 12px; margin-left: 0; }
.v2 .disc-chip > .disc-caixa > div > .disc-corpo { padding: 7px 0 0; border-top: 0;
  font-size: inherit; }
/* os atalhos do painel eram inline e cabiam em minúsculas curtas; com o rótulo longo (CL-6) a
 * linha vira faixa densa, que é o que a §Densidade pede para rótulo curto repetido */
.v2 .gerir-painel .linha-atalhos { display: flex; flex-wrap: wrap; gap: 4px; margin: 0 0 8px; }

/* ─────────────────────── GB-2 · ação do empty state (macro `vazio`) ───────────────────── */
/* O template canônico é anel + título + frase + AÇÃO; as três telas que só tinham `<p>` pelado
 * (cofre, leitura, rodar) e o deck (que tinha o vazio sem a ação, com o botão 70 linhas abaixo)
 * passam a servir a ação dentro do bloco. */
.v2 .vazio .acao-vazio { margin: 11px 0 0; }

/* ───────────────────── CL-6 · reflow de cartão da tabela de clientes ─────────────────────
 * §Mobile: "a MESMA `<table>` vira cartão via CSS (flex reflow); nunca HTML duplicado para
 * mobile". Abaixo de 640px cada `<tr>` vira um cartão e os pares rótulo/valor vão em GRADE DE
 * 2 COLUNAS (§Densidade: "dado curto nunca ganha linha inteira"), com o rótulo como sobrancelha
 * acima do valor. O rótulo sai do `data-rot` da célula — mesmo texto do `<th>`, escrito uma vez
 * só no HTML: é isso que torna impossível o "mesmo botão, dois nomes" que CL-6 nomeia. */
@media (max-width: 639.98px) {
  .v2 .tabela-carteira,
  .v2 .tabela-carteira tbody,
  .v2 .tabela-carteira tr,
  .v2 .tabela-carteira td { display: block; width: auto; }
  /* o `<thead>` não some do DOM: os rótulos continuam existindo para o leitor de tela */
  .v2 .tabela-carteira thead { position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap; }
  .v2 .tabela-carteira tr { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 10px 12px; align-items: start; border: 1px solid var(--fio);
    border-radius: var(--r-cartao); background: var(--sup-papel); box-shadow: var(--sombra-1);
    padding: 12px 13px 13px; margin-bottom: 10px; }
  .v2 .tabela-carteira tr:hover { background: var(--sup-papel); }
  .v2 .tabela-carteira td { padding: 0; min-height: 0; overflow: visible; text-align: left;
    vertical-align: baseline; }
  .v2 .tabela-carteira td.dir { text-align: left; }
  /* nome do cliente (com o filete de estado) e a faixa de ação ocupam a linha inteira */
  .v2 .tabela-carteira td.marcador { grid-column: 1 / -1; padding-left: 13px; }
  .v2 .tabela-carteira td.marcador .p1 { font-size: 16px; }
  /* MOBILE-1 cluster A (26/08): o nome do cliente é o ÚNICO link do cartão e media 66×21
     (RELATORIO-MOBILE-AUDIT.md #2a) — `linha-clicavel.js` já deixa o cartão INTEIRO clicável
     no toque (delegado em `.tabela-carteira`), mas o `<a>` real (foco/teclado/leitor de tela)
     continua pequeno. Aqui ele também vira o alvo físico: preenche a largura da célula com
     44px de altura mínima, sem mudar o texto nem o layout de 2 colunas ao lado. */
  .v2 .tabela-carteira td.marcador a.p1 { display: flex; align-items: center; min-height: 44px; }
  .v2 .tabela-carteira td:nth-child(5) { grid-column: 1 / -1; }   /* Situação */
  .v2 .tabela-carteira td.acoes-cliente { grid-column: 1 / -1; display: flex; flex-wrap: wrap;
    gap: 8px; align-items: center; }
  /* sobrancelha: o rótulo da coluna, acima do valor (§Mobile) */
  .v2 .tabela-carteira td[data-rot]::before { content: attr(data-rot); display: block;
    font-size: var(--fs-rotulo-m); letter-spacing: .15em; text-transform: uppercase; color: var(--txt-3);
    font-weight: 600; margin-bottom: 2px; }
  /* no cartão há largura: o 2º nível pode quebrar em vez de virar reticências */
  .v2 .tabela-carteira td .p1, .v2 .tabela-carteira td .p2 { white-space: normal;
    overflow: visible; text-overflow: clip; }
  .v2 .tabela-carteira td.dir .p1, .v2 .tabela-carteira td.dir .p2 { white-space: nowrap; }
  .v2 .tabela-carteira td.dir .gerir-caso { margin-left: 0; }
  /* alvo de toque de 44px vale no cartão inteiro, inclusive no chip do disclosure */
  .v2 .tabela-carteira .disc-chip > .disc-cabeca { min-height: 44px; padding: 6px 12px; }
  .v2 .tabela-carteira .disc-chip { display: block; }
  .v2 .tabela-carteira .disc-chip > .disc-cabeca { display: flex; width: 100%;
    justify-content: center; }
}

/* ───────────────────────── RD-5 · duas ações na MESMA linha ─────────────────────────────
 * Medido em headless: "Rodar agora" e "O que o levantamento faz" ocupavam duas faixas de
 * 1210px, uma embaixo da outra (`ocupa=0.17`), enquanto o deck faz certo o mesmo par no
 * cabeçalho do cartão. §Densidade: "botão de ação compacto", não faixa de ação própria. */
.v2 .linha-acoes { display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin: var(--e-4) 0 0; }
.v2 .linha-acoes form { margin: 0; }

/* ───────────────────────── DK-4 · `dl.pares` não ocupa faixa larga ──────────────────────
 * "14 prontos" ocupava 11% de uma célula de 597px. Acima de 1100px a régua de pares passa a 4
 * colunas — o dado curto deixa de nadar na banda, e a grade continua sendo a de 2 colunas nas
 * larguras em que 4 não caberiam. */
@media (min-width: 1100px) {
  .v2 .validacoes-apr .pares { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ───────────────────────── LG-1 · o botão do login entra no vocabulário ─────────────────
 * `login.html` era a única tela do produto com `class="btn"` (herança v1) e não tinha wrapper
 * `.v2` — trocar só a classe não pegaria folha nenhuma, porque as 6 regras de `.btn-v2` são
 * prefixadas por `.v2`. O wrapper entrou no template; aqui fica a largura cheia que a caixa de
 * login já dava ao botão herdado. */
.v2 .caixa-login .btn-v2 { width: 100%; }

/* ─────────────────── LE-4 · ícone de domínio nos tipos de documento ─────────────────────
 * A leitura servia UM ícone no conteúdo inteiro (o do cabeçalho do cartão) enquanto a tela
 * irmã — o cofre, sobre os MESMOS arquivos — já tinha os dela. §Ícones: os do catálogo usados
 * "onde a régua manda: nav, tipos de documento, ações", sempre com o rótulo por perto (aqui o
 * rótulo é o próprio nome do documento, ao lado). As duas regras abaixo generalizam o que
 * `cofre-fix` tinha escrito só para `.cofre-v2`. */
.v2 .ic-cab { width: 17px; height: 17px; flex: none; color: var(--marca-texto); }
.v2 .task-list .titulo { display: flex; align-items: center; gap: 7px; }
.v2 .task-list .ic-doc { width: 20px; height: 20px; flex: none; color: var(--marca-texto); }

/* ═══ MOBILE-1 cluster B (26/08) · escala tipográfica ≤640px — ACHADOS DA 2ª RODADA
 * (sonda dedicada `achar_menor.py`, que varre TODO nó de texto visível excluindo `<thead>`
 * clipado, não só os 30 primeiros do `audit_mobile.py`). CONSOLIDADO NO FIM DO ARQUIVO de
 * propósito (lição de `.link-sair-ctx`/`.legenda`/`.conta-disc`: empate de especificidade
 * perde por ordem de fonte, não por estar dentro de `@media`). */
@media (max-width: 639.98px) {
  .v2 .chips .chip .n { font-size: var(--fs-rotulo-m); }
  .v2 .chapeu .dado dt { font-size: var(--fs-rotulo-m); }
  .v2 .validacoes-apr .par .rot { font-size: var(--fs-rotulo-m); }
  .v2 .validacoes-apr .par .v { font-size: var(--fs-corpo-m); }
  .v2 .at-ctx .s { font-size: var(--fs-rotulo-m); }
  /* `.tabela thead th` a 9,5px é global (`.tabela` de-escopada) — nas 4 tabelas de reflow o
     `<thead>` fica clipado a 1×1px (não é defeito real ali, é invisível); mas `.tabela-trilha`
     (dentro de "Trilha desta tese", tese69) usa `.rolagem` (rola, não reflui) e o cabeçalho
     FICA visível — 9,5px real ali. Achado na 2ª rodada, `<details>` fechado por padrão (a
     sonda mede mesmo fechado: `grid-template-rows:0fr` não é `display:none`). */
  .v2 .chapeu .capa .rot { font-size: var(--fs-rotulo-m); }
  .tabela thead th { font-size: var(--fs-rotulo-m); }
}

/* ═══ MOBILE-2 · cluster C (26/08) — VOLUME DE ROLAGEM DAS LISTAS ═══════════════════════════
 * Cluster C do `RELATORIO-MOBILE-AUDIT.md`: quatro listas viravam 4,6 a 23,2 viewports de
 * rolagem contínua porque o reflow honesto empilha TODA célula da linha, inclusive metadado que
 * já vive no filtro logo acima. Duas frentes, as duas só ≤639,98px (aceite 3: desktop intocado):
 * (1) cartão enxuto — 1 linha-título + 2 pares, o resto na ficha; (2) exibição paginada.
 * CONSOLIDADO NO FIM DO ARQUIVO de propósito (lição da MOBILE-1 cluster B: empate de
 * especificidade se resolve por ORDEM DE FONTE, não por estar dentro de `@media`). */
@media (max-width: 639.98px) {
  /* ── exibição paginada (`js/paginar-lista.js`) ─────────────────────────────────────────────
   * O `!important` é a mesma necessidade que `tr[hidden]` já tinha em `biblioteca.css`: o
   * reflow declara `display: grid` na `<tr>` e `display: block` no `<tbody>`, e as duas vencem
   * o `display:none` que um atributo sozinho traria. `[data-pag-oculta]` só existe onde o JS o
   * põe — nenhuma tela sem paginação enxerga esta regra. */
  tr[data-pag-oculta], tbody[data-pag-oculta] { display: none !important; }

  /* ── gatilho "carregar mais" ───────────────────────────────────────────────────────────────
   * Nasce no JS (sem JS não há paginação e o gatilho não faria nada). Alvo de 44px como todo
   * gatilho do produto (§Mobile) e o contador na mesma gramática do `.chip .n`: o cabeçalho da
   * lista promete "87 de 90" e o contador diz quantos desses estão EXIBIDOS agora. */
  .carregar-mais { display: flex; justify-content: center; margin: 12px 0 2px; }
  .carregar-mais > .btn-v2 { min-height: 44px; display: inline-flex; align-items: center;
    gap: 8px; }
  .carregar-mais .n { font-size: var(--fs-rotulo-m); color: var(--txt-3);
    font-variant-numeric: tabular-nums; }
}
/* fora da `@media`: o gatilho é escondido pelo JS acima do breakpoint, e `display:flex` na
   regra acima venceria o `[hidden] { display: none }` da folha do navegador (mesma armadilha
   de `.tabela-teses tr[hidden]`). */
.carregar-mais[hidden] { display: none !important; }

/* ── /clientes · cartão enxuto (cluster C, DECISÃO 1) ────────────────────────────────────────
 * Sete células empilhadas = 417px por cliente (medido 26/08 03h32 BRT, sonda `medir_c.py`).
 * O que SAI, e por quê — universo = as sete colunas do desktop, subtraindo nesta ordem:
 *   · SITUAÇÃO (5ª) — régua 5 de 26/08: "com levantamento"/"sem levantamento"/"arquivados" são
 *     três dos seis chips desta tela (`dados.py:436 CHIPS`), servidos 200px acima. O estado não
 *     some do cartão: ele continua no FILETE DE COR do `.marcador` (`.m-ok`/`.m-proc`/`.m-na`,
 *     `.tabela .marcador::before` — regra global, vale no reflow), que é a régua da casa "a cor
 *     entra no fio, nunca no texto".
 *   · NATUREZA (`.p2.nat` da célula do CNPJ) — mesma régua: "dados do cliente"/"exemplo" são
 *     chips. Sai só ESSE ramo do 2º nível; "+N estabelecimentos"/"+N filiais" continuam, que é
 *     dado do cliente e não existe como filtro (por isso a classe no template: CSS não sabe
 *     distinguir ramos de um `{% if %}`).
 *   · CASOS (4ª) e CRÉDITO ATUALIZADO (6ª) — não são filtro; são os dois primeiros dados que a
 *     conta de "1 título + 2 pares" deixa de fora, e os dois vivem na FICHA: o hub do cliente
 *     abre com os KPIs `_kpis_caso.html`, onde o crédito atualizado é o cartão principal.
 *   · AÇÃO (7ª) quando é "Abrir" — régua 3: `linha-clicavel.js` já faz o cartão INTEIRO abrir o
 *     mesmo cliente, e o link do nome tem os 44px do cluster A. Dois gatilhos para um destino é
 *     o mesmo gesto duas vezes. O `:has()` é o que preserva o único caso em que a ação NÃO é
 *     duplicata: na vista "arquivados" a célula traz o form POST "Restaurar", que não tem outro
 *     caminho no cartão — esse fica.
 * FICA: título (nome + razão social/código interno) + CNPJ + Regime · UF — as duas primeiras
 * colunas do desktop depois do título, na ordem do desktop. */
@media (max-width: 639.98px) {
  .v2 .tabela-carteira td:nth-child(4),
  .v2 .tabela-carteira td:nth-child(5),
  .v2 .tabela-carteira td:nth-child(6) { display: none; }
  .v2 .tabela-carteira td:nth-child(2) .p2.nat { display: none; }
  .v2 .tabela-carteira td.acoes-cliente:has(a.btn-v2) { display: none; }
  /* régua 2 de 26/08 — o par sem valor não rende nem a sobrancelha (o `data-vazio` do
     template mede o valor BRUTO; ver o comentário em `_tabela_casos.html`). Com o cartão
     enxuto isso deixa de ser um detalhe: CNPJ e Regime · UF são os DOIS pares que restam. */
  .v2 .tabela-carteira td[data-vazio],
  .v2 .tabela-carteira td .p1[data-vazio],
  .v2 .tabela-carteira td .p2[data-vazio] { display: none; }
  /* sem a faixa de ação embaixo, o cartão fecha no par — o respiro de baixo volta pro padding */
  .v2 .tabela-carteira tr { padding-bottom: 12px; }
}

/* ── ACHADO NO CAMINHO (MOBILE-2, 26/08 04h05 BRT) — O FILTRO NÃO FILTRAVA NO CELULAR ────────
 * Mesmo defeito que o CONSERTO-NOTURNO (item 1, 26/08 02h05) consertou em `.tabela-teses`, vivo
 * nos IRMÃOS que nasceram do mesmo piloto: `display: grid` na `<tr>` do reflow tem
 * especificidade maior que o `[hidden] { display: none }` da folha do navegador, então TODA
 * linha que o servidor/filtro mandou oculta voltava a aparecer abaixo de 640px. Medido a 390px,
 * instância 3097, antes do conserto:
 *   · `/clientes?filtro=arquivados` — 6 de 7 linhas `hidden`, **as 6 com altura** (a tela
 *     mostrava a carteira inteira embaixo de um chip que diz "arquivados");
 *   · `/clientes?filtro=com-resultado` — 4 `hidden`, as 4 com altura;
 *   · `/clientes` (padrão) — o cliente ARQUIVADO aparecia na lista de trabalho;
 *   · `/resultado?filtro=aceitas` — 10 de 11 `hidden`, as 10 com altura.
 * A 1536px as mesmas páginas medem `hiddenComAltura: 0` — era defeito só do reflow.
 * Isto entra nesta frente porque a DECISÃO 2 da missão ("filtro reaplica sobre o conjunto
 * completo, exibição pagina") não tem sentido sobre um filtro que não filtra: o paginador
 * governa `tr:not([hidden])`, e sem esta regra ele pagina um conjunto errado.
 * Guardado por teste: `test_filtro_esconde_de_verdade_no_celular` (as 4 tabelas). */
@media (max-width: 639.98px) {
  .v2 .tabela-carteira tbody tr[hidden] { display: none !important; }
}

/* ═══ MOBILE-3 (26/08) · residuais da re-varredura final ═════════════════════════════════════
 * Fonte: `RELATORIO-MOBILE-AUDIT.md` §4.1 (linhas 1, 2, 5) + §"Residuais agrupados" (E', B').
 * NO FIM DO ARQUIVO pela mesma lição de MOBILE-1/2 — as regras abaixo DESFAZEM decisões que
 * MOBILE-1 tomou 5 horas antes, e desfazer por ordem de fonte é o único jeito que não depende
 * de contar especificidade. */

/* ── E' · O RÓTULO E O PÉ DO KPI VOLTAM A QUEBRAR EM LINHA (o ellipsis sai) ─────────────────
 * MEDIDO pelo julgador (390×844): num cartão de 151px de miolo, "Crédito atualizado (SELIC)"
 * pede 224px (perde 33% do texto), "Oportunidades apuradas" pede 210, "Sem levantamento" 154;
 * o pé "nominal R$ 1.127.400,00 · atualizado pela SELIC" pede 259px — 4 de 4 cartões cortados
 * no hub e no resultado. O grid 2×2 do cluster E comprou altura pagando com o texto.
 *
 * POR QUE ISSO É ERRADO E NÃO É TROCA JUSTA. Régua do dono de 25/08, reforçada em 26/08:
 * **dado não vira reticências**. O pé do KPI é dado (é o valor NOMINAL, mais a base de
 * correção); o rótulo é o que diz de que número se trata — "Crédito atualizado (SELIC)" cortado
 * em "Crédito atualizado" e "Crédito atualiza…" são duas coisas diferentes na cabeça de quem
 * lê. O `title` que MOBILE-1 pôs no lugar é hover: no celular ele não existe.
 *
 * O QUE CUSTA, declarado: o rótulo em 2 linhas devolve os ~32px por cartão que MOBILE-1 tinha
 * economizado (medido lá: 62px → 94-96px). É o preço do texto inteiro, e o grid 2×2 continua
 * de pé — a economia grande do cluster E veio de 4 cartões em coluna virarem 2×2 (520px →
 * ~190px), não do corte do rótulo. `line-height` curto e o `--fs-rotulo-m` seguram a segunda
 * linha; nenhuma altura fixa entra aqui (`--kpi-alt` continua desligado no celular). */
@media (max-width: 639.98px) {
  .v2 .kpi .rot { white-space: normal; overflow: visible; text-overflow: clip;
    line-height: 1.25; }
  .v2 .kpi .pe { white-space: normal; overflow: visible; text-overflow: clip;
    line-height: 1.3; }
}

/* ── STEPPER · a etapa corrente aparece, e a faixa DIZ que rola ──────────────────────────────
 * O auto-scroll é do `js/stepper-rolagem.js` (só o hub o carrega). Aqui fica a afordância que
 * faltava: a faixa de 832px dentro de 360px não tinha nem seta, nem sombra, nem corte visível —
 * parecia uma linha de 3 etapas que acaba ali.
 *
 * ESMAECIMENTO DE BORDA, e não seta: seta seria um 2º controle sobre um trilho que já navega
 * com o dedo, e o produto tem a régua de não repetir gatilho para o mesmo gesto (P22). O corte
 * suave na borda é o que o próprio DS usa para dizer "tem mais depois daqui" — e ele só aparece
 * do LADO em que de fato sobra conteúdo (`data-rolavel`, escrito pelo JS a cada rolagem), senão
 * a borda esmaeceria por decoração numa faixa que já acabou.
 * `mask-image` no PRÓPRIO rolador dispensa elemento novo (o fade acompanha a rolagem de graça).
 * Sem JS o atributo nunca aparece, nenhuma máscara é aplicada, e o trilho fica como era.
 * A parada OPACA vem de `--p-mascara-opaca`, e não de um hexadecimal escrito aqui: literal de
 * cor só existe no `tokens.css` (§R7), e o `test_tokens_css_e_o_unico_lugar_com_cor` reprovou a
 * 1ª versão deste bloco — inclusive quando o hexadecimal ficou só no COMENTÁRIO, porque a
 * varredura é por linha, não por sintaxe. Numa máscara a tinta nunca chega a ser pintada: o que
 * trabalha é o canal alfa. */
.v2 .rolagem-stepper[data-rolavel="dir"] {
  mask-image: linear-gradient(to right, var(--p-mascara-opaca) calc(100% - 34px),
                              transparent 100%); }
.v2 .rolagem-stepper[data-rolavel="esq"] {
  mask-image: linear-gradient(to right, transparent 0, var(--p-mascara-opaca) 34px); }
.v2 .rolagem-stepper[data-rolavel="ambos"] {
  mask-image: linear-gradient(to right, transparent 0, var(--p-mascara-opaca) 34px,
                              var(--p-mascara-opaca) calc(100% - 34px), transparent 100%); }

/* ── A' · os 2 alvos do hub que ficaram abaixo de 44px ──────────────────────────────────────
 * "Revisar" (`a.acao-titulo`, 68×20) é a ação da etapa no título do painel — a porta do passo
 * corrente. "Manutenção do cliente" (`button.disc-cabeca` do `.disc-chip`, 166×23) é o
 * gatilho do bloco de manutenção. Mesma receita do cluster A: alvo cresce por caixa, não por
 * corpo de letra. */
@media (max-width: 639.98px) {
  .v2 .painel-passo .acao-titulo { min-height: 44px; }
  /* ACHADO NO CAMINHO (26/08 08h1x BRT, ao re-medir a tese69 depois do conserto dos 7 chips de
     eixo): a cabeça do disclosure da casa mede **37px** — e 26px na variante `.eixo-editar` —
     em TODA tela que usa `.disc`, não só nas duas que a auditoria nomeou. Ela não entrou na
     lista de residuais porque a sonda grava só os 40 menores alvos por tela e, na tese69, os 40
     foram consumidos por `<label>` de formulário e pelos chips de eixo (a própria §4.3 do
     relatório do julgador avisa que o corte saiu da amostra, não do total).
     A régua vale para a família inteira: gatilho de disclosure é gatilho. Uma linha aqui cobre
     `.disc-chip`, `.eixo-chip`, `.eixo-editar`, `.cj-apoio`, `.ficha-renomear` e os disclosures
     soltos de curadoria — as regras específicas que MOBILE-3 escreveu em `biblioteca.css` ficam
     onde estão: elas dizem o mesmo, e apagar uma regra medida por causa de outra mais nova é o
     jeito de reintroduzir o defeito quando a mais nova mudar. */
  .v2 .disc > .disc-cabeca { min-height: 44px; }
}

/* ── B' · POR QUE A ESCALA DE ≤640px NÃO CHEGOU AO `/login` (a causa, não o sintoma) ─────────
 * O julgador mediu a legenda "recuperação administrativa" em **9,5px** e registrou: é a única
 * das 12 telas onde o piso não subiu de 8,5/9,5 para 12,0.
 *
 * A CAUSA: o cluster B foi escrito como uma LISTA DE CLASSES (`.legenda`, `.rot`, `.pe`,
 * `.badge-v2`, `th`…), e a família "eyebrow" — mono + versalete + `letter-spacing` largo — tem
 * TRÊS implementações neste produto que não usam nenhuma dessas classes:
 *   `.eyebrow`                  (:96)   10,5px — genérica, o nome da família
 *   `.sidebar .marca small`     (:141)   9,5px — gaveta de navegação (invisível fechada, que é
 *                                                por que a auditoria não a pegou: ela mede o
 *                                                que está na tela)
 *   `.caixa-login .marca small` (:386)   9,5px — o que o julgador viu
 * Nenhuma das três é `.legenda`. O `/login` não é caso especial: é a única em que essa família
 * fica visível sozinha, sem `.legenda` por perto que disfarçasse a falta.
 * O conserto vale para as três de uma vez — corrigir só a do login deixaria a mesma armadilha
 * armada para a próxima tela que usasse `.eyebrow`. (`login.html` NÃO foi tocado: ele já
 * carrega `tokens.css` + `app.css`, que é tudo o que a escala precisa.) */
@media (max-width: 639.98px) {
  .eyebrow,
  .sidebar .marca small,
  .caixa-login .marca small { font-size: var(--fs-rotulo-m); }
}

/* ═══════════════════════════════════════════════════════════════════════════════════════════
 * F-40 (26/08/2026, ordem 2 do dono) · COLUNA DE CONTEXTO COLAPSÁVEL
 *
 * Mesma mecânica da barra navy (`.barra-colapsada`, `nav.js` §"barra lateral colapsável"):
 * classe no `<html>` posta pelo script inline do `<head>` ANTES da primeira pintura, e o mesmo
 * `nav.js` a alterna depois. Um estado de verdade só, e nada de coluna larga que encolhe na
 * frente do usuário a cada navegação.
 *
 * TUDO aqui é escopado em `[data-colapsavel]`: a classe do `<html>` é global e atravessa
 * páginas, e a `.coluna-contexto` do hub (`hub.html:111`) NÃO tem alça — sem o escopo, recolher
 * na biblioteca sumiria com a coluna do hub sem jeito de trazê-la de volta.
 * ═══════════════════════════════════════════════════════════════════════════════════════════ */

/* O conteúdo herda a grade que era da própria coluna (o wrapper `.ctx-conteudo` entrou entre as
 * duas), senão os dois cartões colariam um no outro. */
.v2 .coluna-contexto[data-colapsavel] > .ctx-conteudo { display: grid;
  grid-template-columns: minmax(0, 1fr); gap: var(--e-3); align-content: start;
  align-items: start; }

/* A alça nasce ESCONDIDA e só aparece quando o `nav.js` marca `[data-pronto]` na coluna. Sem JS
 * ela não teria o que fazer — e botão que não faz nada é pior que botão nenhum (mesma régua do
 * campo de busca da biblioteca, `biblioteca.html` §bf-busca). */
.v2 .coluna-contexto[data-colapsavel] .ctx-alca { display: none; }
.v2 .coluna-contexto[data-colapsavel][data-pronto] .ctx-alca {
  display: inline-flex; align-items: center; gap: 5px; justify-self: end;
  background: none; border: 1px solid transparent; border-radius: var(--r-cartao);
  color: var(--txt-3); font: inherit; font-size: var(--fs-rotulo-m); letter-spacing: .04em;
  padding: 2px 6px; min-height: 24px; cursor: pointer; }
.v2 .coluna-contexto[data-colapsavel] .ctx-alca:hover {
  color: var(--txt-1); border-color: var(--fio-forte); background: var(--sup-papel); }
.v2 .coluna-contexto[data-colapsavel] .ctx-alca:focus-visible {
  outline: 2px solid var(--foco); outline-offset: 2px; }
.v2 .coluna-contexto[data-colapsavel] .ctx-alca .ic { width: 13px; height: 13px; flex: none; }
/* aberta, a alça é só o chevron apontando para onde a coluna vai (para fora, à direita) */
.v2 .coluna-contexto[data-colapsavel] .ctx-alca .rot { display: none; }

/* ─── recolhida ─── */
:root.contexto-colapsado .v2 .coluna-contexto[data-colapsavel] > .ctx-conteudo { display: none; }
:root.contexto-colapsado .v2 .coluna-contexto[data-colapsavel][data-pronto] .ctx-alca {
  justify-self: stretch; justify-content: center; padding: 12px 3px;
  border-color: var(--fio); background: var(--sup-papel); color: var(--txt-2); }
/* o filete: rótulo em pé, para a aba dizer o que devolve — recolhido não vira retângulo mudo */
:root.contexto-colapsado .v2 .coluna-contexto[data-colapsavel] .ctx-alca .rot {
  display: inline; writing-mode: vertical-rl; text-orientation: mixed; }
:root.contexto-colapsado .v2 .coluna-contexto[data-colapsavel] .ctx-alca .ic {
  transform: rotate(180deg); }

/* A largura só volta ao conteúdo onde a coluna É uma coluna (≥1181px, o mesmo degrau do
 * esqueleto de duas colunas acima). `:has()` porque a grade é a MÃE do aside — é a única forma
 * de a grade saber que a coluna dela é a colapsável, sem marcar o wrapper no `base.html` (que é
 * arquivo compartilhado por toda tela com aside). Mesma feature já usada em `biblioteca.css`
 * (`tr:has(td.tese-nome a[href])`). */
@media (min-width: 1181px) {
  :root.contexto-colapsado .v2 .duas-colunas-v2:has(> .coluna-contexto[data-colapsavel][data-pronto]) {
    grid-template-columns: minmax(0, 1fr) 30px; }
}
/* Abaixo de 1181px a coluna é uma FAIXA no topo (`order: -1`): recolher é encolher a faixa, e a
 * alça volta a ser horizontal — filete em pé no topo de um bloco deitado não é filete, é enfeite. */
@media (max-width: 1180px) {
  /* a FAIXA de duas colunas (chapéu | atalhos) que a coluna tinha desce um nível: quem é a grade
     agora é `.ctx-conteudo`, porque o `<aside>` passou a ter a alça como primeiro filho. Sem
     isto os dois cartões empilhariam e a faixa dobraria de altura entre 900 e 1180px. */
  .v2 .coluna-contexto[data-colapsavel] { grid-template-columns: minmax(0, 1fr); }
  .v2 .coluna-contexto[data-colapsavel] > .ctx-conteudo {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  :root.contexto-colapsado .v2 .coluna-contexto[data-colapsavel][data-pronto] .ctx-alca {
    justify-self: start; padding: 4px 8px; min-height: 28px; }
  :root.contexto-colapsado .v2 .coluna-contexto[data-colapsavel] .ctx-alca .rot {
    writing-mode: horizontal-tb; }
  :root.contexto-colapsado .v2 .coluna-contexto[data-colapsavel] .ctx-alca .ic {
    transform: rotate(-90deg); }
}
@media (max-width: 900px) {
  .v2 .coluna-contexto[data-colapsavel] > .ctx-conteudo {
    grid-template-columns: minmax(0, 1fr); }
}
/* Régua da casa (o gotcha que mordeu três vezes em 26/08): `[hidden]` é `display:none` da folha
   do NAVEGADOR e perde para qualquer `display:` de autor — o `display: grid` acima seria
   exatamente isso. Quem esconde por `hidden` declara a linha. */
.v2 .coluna-contexto[data-colapsavel] > .ctx-conteudo[hidden] { display: none; }

/* ═══════════════════════════════════════════════════════════════════════════════════════════
 * F-40 (26/08/2026, ordem 3b do dono) · BUSCA DA TOPBAR COM ESCOPO DECLARADO
 *
 * O dropdown é a gramática de cartão da casa (papel + fio + `--r-painel` + `--sombra-3`), não um
 * componente novo: é o mesmo desenho do menu de faceta da biblioteca, um degrau acima na
 * elevação porque flutua sobre a topbar sticky (`z-index: 20`).
 * Toda regra vive no degrau ≥1024px porque é lá que `.busca-topo` deixa de ser `display:none`.
 * ═══════════════════════════════════════════════════════════════════════════════════════════ */
@media (min-width: 1024px) {
  /* o campo é a âncora do painel; e 250px não cabiam o placeholder novo, que agora DIZ o escopo */
  .busca-topo { position: relative; width: 292px; }

  .busca-painel {
    position: absolute; top: calc(100% + 6px); right: 0; z-index: 40;
    min-width: 100%; width: 372px; max-height: 62vh; overflow-y: auto;
    background: var(--sup-papel); border: 1px solid var(--fio);
    border-radius: var(--r-painel); box-shadow: var(--sombra-3);
    padding: 5px; color: var(--txt-1); text-align: left;
  }
  /* o gotcha de 26/08: `[hidden]` perde para `display:` de autor — a linha é explícita */
  .busca-painel[hidden] { display: none; }

  .bt-grupo + .bt-grupo { margin-top: 3px; border-top: 1px solid var(--fio); padding-top: 4px; }
  .bt-grupo-rot {
    display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
    padding: 5px 8px 3px; font-size: var(--fs-rotulo-m); letter-spacing: .1em;
    text-transform: uppercase; color: var(--txt-3);
  }
  .bt-grupo-n { letter-spacing: 0; text-transform: none; font-size: 11px; color: var(--txt-3); }

  .bt-item {
    display: block; padding: 6px 8px; border-radius: var(--r-cartao);
    text-decoration: none; color: var(--txt-1);
  }
  .bt-item .t { display: block; font-size: 13px; line-height: 1.3;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .bt-item .s { display: block; font-size: 11.5px; color: var(--txt-3); line-height: 1.35;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* UMA classe para o realce, escrita pelo teclado E pelo mouse (`mouseenter` no JS): com
     `:hover` numa ponta e classe na outra, o item sob o cursor e o item que o Enter abre podiam
     ser dois diferentes — e a pessoa abriria o que não estava olhando. */
  .bt-item.em-foco { background: var(--sup-papel-2); }
  .bt-item.em-foco .t { color: var(--txt-1); font-weight: 500; }

  .bt-vazio { margin: 0; padding: 10px 9px; font-size: 12.5px; color: var(--txt-2); }
}
