/* GABRIEL SEAL — estética inspirada na identidade Anthropic/Claude
   Paleta: creme quente, terracota (#CC785C), grafite quente. Serifa nos títulos. */
:root {
  --bg:        #F5F4EE;   /* creme quente de fundo */
  --surface:   #FBFAF7;   /* cartões */
  --surface-2: #F0EEE6;   /* realces suaves */
  --ink:       #1A1915;   /* texto principal */
  --ink-soft:  #57534B;   /* texto secundário */
  --muted:     #8A857A;   /* legendas */
  --line:      #E4E0D5;   /* bordas */
  --line-2:    #D8D3C5;
  --accent:    #CC785C;   /* terracota Claude */
  --accent-d:  #B5634A;
  --accent-bg: #F4E5DD;
  --ok:        #5B7A52;
  --ok-bg:     #E8EFE2;
  --warn:      #B07B2E;
  --warn-bg:   #F4ECDB;
  --near:      #8A857A;
  --danger:    #B23B3B;   /* alerta — "A conferir" */
  --danger-bg: #F4E1E1;
  --radius:    14px;
  --shadow:    0 1px 2px rgba(40,33,20,.04), 0 6px 24px rgba(40,33,20,.05);
  --serif: "Tiempos Text", "Georgia", "Times New Roman", serif;
  --sans: -apple-system, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: "Cascadia Code", ui-monospace, "SF Mono", "Consolas", "Roboto Mono", monospace;
  --steel: #A9A294;       /* metal / hachura de seção */
  --steel-bg: #ECE8DF;
  --accent-line: #E7CDC1;
}
/* ---------- Modo escuro (segue o sistema, ou escolha manual via #themeToggle) ---------- */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:        #232019;
    --surface:   #2B2721;
    --surface-2: #34302A;
    --ink:       #ECE7DD;
    --ink-soft:  #B8B0A2;
    --muted:     #8C8577;
    --line:      #423C33;
    --line-2:    #4D463C;
    --accent:    #E08F6F;
    --accent-d:  #EDA688;
    --accent-bg: #4A3529;
    --ok:        #8FB081;
    --ok-bg:     #2E3A28;
    --warn:      #D9A85C;
    --warn-bg:   #3D3222;
    --near:      #8C8577;
    --danger:    #E08080;   /* alerta — "A conferir" */
    --danger-bg: #3D2626;
    --shadow:    0 1px 2px rgba(0,0,0,.25), 0 6px 24px rgba(0,0,0,.3);
    --steel:     #8D8676;
    --steel-bg:  #38332B;
    --accent-line: #5A4438;
  }
}
:root[data-theme="dark"] {
  --bg:        #232019;
  --surface:   #2B2721;
  --surface-2: #34302A;
  --ink:       #ECE7DD;
  --ink-soft:  #B8B0A2;
  --muted:     #8C8577;
  --line:      #423C33;
  --line-2:    #4D463C;
  --accent:    #E08F6F;
  --accent-d:  #EDA688;
  --accent-bg: #4A3529;
  --ok:        #8FB081;
  --ok-bg:     #2E3A28;
  --warn:      #D9A85C;
  --warn-bg:   #3D3222;
  --near:      #8C8577;
  --danger:    #E08080;   /* alerta — "A conferir" */
  --danger-bg: #3D2626;
  --shadow:    0 1px 2px rgba(0,0,0,.25), 0 6px 24px rgba(0,0,0,.3);
  --steel:     #8D8676;
  --steel-bg:  #38332B;
  --accent-line: #5A4438;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;   /* rede de segurança: nenhum elemento deve empurrar a página pros
                            lados, mas se algo escapar isso trava o "arrasto" horizontal
                            indesejado no celular em vez de deixar a tela deslizar */
}
h1,h2,h3 { font-family: var(--serif); font-weight: 500; letter-spacing: -.01em; }

/* ---------- Cabeçalho ---------- */
header {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px 20px; padding: 16px 28px; flex-wrap: wrap;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 20;
}
.brand { display: flex; align-items: center; gap: 13px; }
.brand .logo { width: 40px; height: 40px; flex: none; }
.brand .name { font-family: var(--serif); font-size: 22px; line-height: 1.1; white-space: nowrap; }
.brand .name b { font-weight: 600; }
.brand .name span { color: var(--accent); font-weight: 600; }
.brand .tag { font-size: 11.5px; color: var(--muted); letter-spacing: .14em; text-transform: uppercase; margin-top: 3px; }

/* min-width:0 aqui é o que impede o app inteiro de rolar na horizontal no
   celular: um <select> dimensiona pela opção MAIS LARGA (aqui ~650px, por causa
   dos nomes longos de catálogo). Como item flex ele nasce com min-width:auto =
   min-content, então se recusava a encolher e virava o piso de largura do
   header — e, por tabela, do documento (306px de overflow em tela de 375px).
   Mesmo motivo do min-width:0 em .field select, mais abaixo. */
.ref-box { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; min-width: 0; }
.ref-box #refCat { min-width: 0; max-width: 100%; }
.ref-box label { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .08em; }
select, input, button { font-family: inherit; font-size: 14px; color: var(--ink); }
select {
  background: var(--surface); border: 1px solid var(--line-2); border-radius: 9px;
  padding: 8px 11px; cursor: pointer;
}
.maxbadge {
  background: var(--accent-bg); color: var(--accent-d); border: 1px solid var(--accent-line);
  border-radius: 999px; padding: 6px 13px; font-size: 12px; font-weight: 600; white-space: nowrap;
  font-family: var(--mono); letter-spacing: -.01em;
}
.theme-toggle {
  width: 36px; height: 36px; flex: none; border-radius: 999px; cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--line-2); font-size: 17px;
  display: flex; align-items: center; justify-content: center; line-height: 1; padding: 0;
  transition: background .15s, border-color .15s;
}
.theme-toggle:hover { border-color: var(--accent); }

/* No celular o cabeçalho vira duas faixas empilhadas: marca em cima, seletor de
   catálogo ocupando a linha inteira embaixo. O .maxbadge perde o nowrap — o
   texto ("Ø máx. haste: … · Ø máx. camisa: …") tem ~510px e sozinho já
   estouraria a tela; quebrando em duas linhas ele cabe e continua legível. */
@media (max-width: 560px) {
  header { padding: 14px 16px; gap: 12px 14px; }
  .ref-box { width: 100%; }
  .ref-box #refCat { flex: 1 1 100%; order: 2; }
  .ref-box label { order: 1; flex: 1 1 100%; }
  .maxbadge { order: 3; white-space: normal; line-height: 1.45; flex: 1 1 auto; }
  .theme-toggle { order: 4; }
}

/* ---------- Layout ---------- */
.wrap { max-width: 1080px; margin: 0 auto; padding: 26px 24px 80px; }
/* ---------- Abas: dois grupos, sem rolagem lateral em largura nenhuma ----------
   Histórico curto (o longo está no CLAUDE.md): a faixa já rolou na horizontal
   (o usuário chamou de "rolagem descontrolada" e o app abria com a aba ativa
   fora da tela) e já quebrou em linhas soltas com `flex-wrap`. Com a 6ª aba,
   o wrap virou 3 linhas desalinhadas (3/2/1) de 123px de altura, e a 6ª ficava
   SOZINHA ocupando a largura inteira — o sublinhado dela encostava na divisória
   e lia como barra quebrada.
   Agora as abas são uma GRADE de dois grupos: "Consulta" (dependem do catálogo)
   e "Cálculo" (matemática pura). Nenhuma aba fica sozinha numa linha, nada rola
   lateralmente, e as 6 ficam sempre visíveis. */
.tabs {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px 20px;
  margin-bottom: 24px; padding-bottom: 6px; border-bottom: 1px solid var(--line);
}
.tabgroup { display: flex; align-items: stretch; gap: 10px; min-width: 0; }
.tabgroup-label {
  flex: none; display: flex; align-items: center;
  font-size: 9.5px; letter-spacing: .13em; text-transform: uppercase;
  color: var(--muted); font-weight: 600;
}
.tabgroup-cells { display: flex; gap: 3px; min-width: 0; }
.tab {
  display: flex; align-items: center; gap: 7px; min-width: 0; white-space: nowrap;
  background: none; border: 1px solid transparent; border-radius: 10px;
  padding: 9px 13px; cursor: pointer; font-family: inherit; font-size: 15px;
  color: var(--ink-soft); position: relative;
}
.tab-ico { width: 17px; height: 17px; flex: none; }
.tab-short { display: none; }
.tab:hover { color: var(--ink); background: var(--surface-2); }
.tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.tab.active {
  color: var(--accent-d); font-weight: 600;
  background: var(--accent-bg); border-color: var(--accent-line);
}

/* CELULAR (≤620px): cada grupo vira uma LINHA de 3 células iguais, com o rótulo
   do grupo na vertical à esquerda (custa ~20px de largura, que sobra, em vez de
   altura, que é o recurso escasso aqui). Rótulo curto no texto visível; o nome
   inteiro continua no aria-label/title. Célula ~51px de altura — acima do
   mínimo de toque que o resto do app já usa (dedo com luva na oficina).
   Acima de 620px NÃO vale a pena empilhar: a célula esticava pra ~230px com um
   ícone de 15px perdido no meio. Lá os grupos ficam na linha compacta e, se não
   couberem lado a lado, quebram um por linha (o `flex-wrap` da .tabs) — cada
   grupo inteiro por vez, nunca uma aba solta. */
@media (max-width: 620px) {
  .tabs { flex-direction: column; align-items: stretch; gap: 5px; margin-bottom: 18px; }
  .tabgroup { gap: 8px; }
  .tabgroup-label {
    writing-mode: vertical-rl; transform: rotate(180deg);
    justify-content: center; padding-right: 7px;
    border-right: 1px solid var(--line); font-size: 8.5px;
  }
  .tabgroup-cells { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; flex: 1; }
  /* Grupo com 4 abas (Cálculo, depois que a aba Peso entrou) NUNCA pode cair em
     3+1 — a 4ª sozinha na linha é exatamente o defeito que a grade veio
     corrigir. Acima de 400px cabem as 4 numa linha só (célula ~72px, medido:
     nenhum rótulo trunca); abaixo disso vira 2×2, que é mais alto porém legível.
     Regra por CONTAGEM, vale pra qualquer grupo que chegue a 4. */
  .tabgroup-cells:has(> :nth-child(4)) { grid-template-columns: repeat(4, 1fr); }
  @media (max-width: 360px) {
    .tabgroup-cells:has(> :nth-child(4)) { grid-template-columns: repeat(2, 1fr); }
  }
  .tab {
    flex-direction: column; justify-content: center; gap: 2px;
    padding: 7px 3px 8px; font-size: 12px; border-radius: 9px; text-align: center;
  }
  .tab-ico { width: 15px; height: 15px; }
  .tab-full { display: none; }
  .tab-short { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
  /* na célula empilhada o contador não cabe na linha do rótulo — vai pro canto */
  .tab .cart-count { position: absolute; top: 3px; right: 5px; margin-left: 0; }
}
.panel { display: none; animation: fade .25s ease; }
.panel.active { display: block; }
@keyframes fade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

.lead { color: var(--ink-soft); margin: 0 0 22px; max-width: 70ch; }
.card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 22px;
}
.card + .card { margin-top: 18px; }

/* ---------- Formulários ---------- */
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 16px; }
.field { display: flex; flex-direction: column; gap: 6px; }
/* Rótulo que quebra em duas linhas ("Aplicação no equipamento") empurrava só o
   input dele para baixo, desalinhando a fileira. Com subgrid, rótulo / campo /
   dica de todos os .field da mesma fileira dividem as MESMAS faixas de altura —
   vale em qualquer largura de janela, e não só nos rótulos longos de hoje.
   A 3ª faixa é a dica (.hint), que em alguns campos vem depois do input. */
@supports (grid-template-rows: subgrid) {
  .grid > .field {
    display: grid; grid-template-rows: subgrid; grid-row: span 3; align-content: start;
  }
}
.field label { font-size: 12.5px; color: var(--muted); font-weight: 600; letter-spacing: .02em; }
/* Checkbox "incluir no relatório" (Cabeçalho da OS, 2026-09-07) — o rótulo vira uma
   linha flex pra caber o checkbox sem empurrar o campo; some quando não marcado
   ajuda a enxergar rápido o que ficará de fora sem ter que abrir o relatório. */
.field label:has(.head-inc) { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.head-inc { width: 15px; height: 15px; accent-color: var(--accent); cursor: pointer; flex: none; }
.field:has(.head-inc:not(:checked)) input[type="text"] { opacity: .55; }
.field .hint { font-size: 11.5px; color: var(--muted); font-weight: 400; }
/* select dentro de .field NÃO tinha width:100% (só os <input> tinham, na regra
   de baixo) — passava despercebido porque nenhum <select> anterior tinha opção
   comprida o bastante pra estourar a coluna. "Estilo de corte" (Anéis-Guia) tem
   opção de 26 caracteres ("Ângulo · passagem de carga"): o <select> ignora
   width:100% do pai em flex/grid quando o conteúdo é mais largo (min-width:auto
   vira o tamanho do CONTEÚDO pra controles de formulário, não zero) -- sem o
   min-width:0 aqui, a coluna INTEIRA da grade era empurrada mais larga que a
   tela, cortando a borda esquerda de tudo (cabeçalho incluso) num scroll
   horizontal indevido. Escopado a .field (não select cru) pra não afetar o
   dropdown do cabeçalho, que fica numa linha flex, não numa coluna. */
.field select { width: 100%; min-width: 0; }
/* `min-width: 0` pelo MESMO motivo já explicado no .field select acima — que na
   época foi aplicado só ao <select> e deixou o <input> de fora. Controle de
   formulário tem `min-width: auto` = largura INTRÍNSECA (o tamanho padrão do
   campo), não zero, e `width: 100%` não vence esse piso: dentro de uma coluna
   de grade estreita o input se recusa a encolher e empurra a coluna pra fora
   da tela.
   Só aparecia no iPhone (2026-08-25, vídeo do usuário: "Ø externo do canal" e
   "polegada" cortados na borda direita) porque a largura intrínseca padrão do
   input no Safari do iOS é maior que a do Chromium — no emulador de mobile do
   navegador desta máquina cabia, e a medição dava 0 de transbordo.
   ATENÇÃO ao medir isso: `body` tem `overflow-x: hidden` (mais acima), então o
   conteúdo largo demais é CORTADO em vez de gerar barra — e
   `scrollWidth - clientWidth` dá 0 mesmo com o defeito presente. Medir pelos
   RETÂNGULOS dos elementos (getBoundingClientRect), que ignoram esse corte. */
input[type="number"], input[type="text"] {
  background: var(--bg); border: 1px solid var(--line-2); border-radius: 9px; padding: 10px 12px;
  width: 100%; min-width: 0;
}
input:focus, select:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent); }
.seg { display: inline-flex; background: var(--surface-2); border-radius: 10px; padding: 3px; gap: 2px; }
.seg button {
  border: 1px solid transparent; background: none; padding: 7px 13px; border-radius: 7px; cursor: pointer; color: var(--ink-soft);
}
.seg button.on { background: var(--surface); color: var(--ink); border-color: var(--accent); box-shadow: 0 1px 2px rgba(0,0,0,.06); font-weight: 600; }
/* alternador mm/polegada: 32px de altura é pouco pra dedo na oficina — no
   celular ganha altura, que é o eixo onde sobra espaço (a largura já é boa). */
@media (max-width: 560px) {
  .seg button { padding: 10px 13px; }
}

.actions { display: flex; gap: 12px; align-items: center; margin-top: 18px; flex-wrap: wrap; }
.btn {
  background: var(--accent); color: #fff; border: none; border-radius: 10px; padding: 11px 20px;
  font-size: 14.5px; font-weight: 600; cursor: pointer; transition: background .15s;
}
.btn:hover { background: var(--accent-d); }
.btn.ghost { background: var(--surface); color: var(--ink); border: 1px solid var(--line-2); }
.btn.ghost:hover { background: var(--surface-2); }

/* ---------- Fluxo em passos ---------- */
/* flex-wrap sempre ligado (não só no celular): o título, o hint descritivo e o
   seletor de unidade competiam pela mesma linha e já quebravam feio a partir de
   ~750px de largura (bem antes de virar "mobile") — não só em telas de celular,
   também em janela de desktop estreita. Sem forçar largura, cada bloco que não
   couber vira sua própria linha por inteiro (comportamento padrão do flex-wrap:
   um item não cabendo desce inteiro, nunca fragmenta palavra por palavra). */
.step { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; row-gap: 6px; font-family: var(--serif); font-size: 17px; color: var(--ink); margin-bottom: 12px; }
/* agrupa "digitar em" + o seletor mm/polegada — assim os dois viajam juntos pra uma
   linha própria (larga ou estreita) em vez de espalhar cada um pra um canto */
.step-unit { display: flex; align-items: center; gap: 10px; margin-left: auto; }
/* Só abaixo de 560px força CADA bloco a ocupar a linha inteira: sem isso, a largura
   estreita do celular deixa o step-unit "flutuando" alinhado à direita na própria
   linha (por causa do margin-left:auto) em vez de esticar por baixo do título —
   a raiz do "arrasto" lateral indesejado que o usuário via ("polegada" cortado). */
@media (max-width: 560px) {
  .step > .hint { flex: 1 0 100%; margin-left: 0 !important; font-size: 13px; }
  .step-unit { flex: 1 0 100%; margin-left: 0; justify-content: space-between; }
}
.step-n {
  display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px;
  border-radius: 50%; background: var(--accent); color: #fff; font-family: var(--sans); font-size: 13px; font-weight: 700; flex: none;
}
.seg.big { display: flex; width: 100%; }
.seg.big button { flex: 1; padding: 11px 14px; font-size: 14.5px; }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }

/* grade de tipos de vedação */
.type-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 9px; }
.type-btn {
  display: flex; flex-direction: column; align-items: flex-start; gap: 3px; text-align: left;
  padding: 11px 13px; border: 1px solid var(--line-2); border-radius: 11px; background: var(--surface);
  cursor: pointer; transition: border-color .12s, background .12s; color: var(--ink);
}
.type-btn:hover { border-color: var(--accent); }
.type-btn.on { border-color: var(--accent); background: var(--accent-bg); box-shadow: 0 0 0 1px var(--accent-bg); }
.type-btn .t-name { font-weight: 600; font-size: 14px; }
.type-btn .t-count { font-family: var(--mono); font-size: 10.5px; color: var(--muted); letter-spacing: -.02em; }
.type-btn.empty { opacity: .5; cursor: not-allowed; }
.type-btn.on .t-count { color: var(--accent-d); }

/* ---------- Corpo da busca: medidas + desenho ---------- */
.search-body { display: block; }
.search-inputs { min-width: 0; }
.draw-wrap {
  margin: 0; padding: 16px; border: 1px solid var(--line); border-radius: 12px;
  background:
    linear-gradient(var(--surface-2), var(--surface-2)) padding-box,
    repeating-linear-gradient(0deg, transparent 0 19px, rgba(169,162,148,.10) 19px 20px),
    repeating-linear-gradient(90deg, transparent 0 19px, rgba(169,162,148,.10) 19px 20px);
  background-color: var(--surface-2);
}
.draw-wrap svg { width: 100%; height: auto; display: block; }
/* figura real do catálogo */
.catalog-fig { display: flex; flex-direction: column; gap: 8px; margin-bottom: 10px; }
.catalog-fig .fig-cell { background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: 8px; text-align: center; }
.catalog-fig img { max-width: 100%; height: auto; display: block; margin: 0 auto; }
.catalog-fig .fig-tag { font-family: var(--mono); font-size: 9px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; margin-bottom: 4px; text-align: left; }
.catalog-fig .fig-style { font-family: var(--mono); font-size: 10px; color: var(--accent-d); margin-top: 2px; }
/* quantidade no resultado */
.qty-add { display: flex; align-items: center; gap: 6px; margin-top: 8px; justify-content: flex-end; }
.qty-add input { width: 48px; padding: 6px 6px; font-size: 13px; text-align: center; font-family: var(--mono);
  background: var(--bg); border: 1px solid var(--line-2); border-radius: 8px; }
.qty-add label { font-size: 11px; color: var(--muted); }
/* atalho "↗ relatório" do card de resultado: apagado enquanto a peça não foi
   escolhida, aceso quando ela já está no relatório.
   LINHA PRÓPRIA no desktop, de propósito: dentro da .qty-add ele ora cabia ao
   lado do "+ Escolher", ora quebrava, porque a largura daquela coluna muda de
   card para card conforme o texto das cotas — a lista saía irregular. No mobile
   a faixa de ação é uma linha só e ele volta para junto dos outros controles.
   Seletor com .go-report-row na frente porque `.btn.ghost` é declarado depois
   no arquivo e ganharia de `.go-report` sozinho. */
.go-report-row { margin-top: 6px; }
.go-report-row .btn.go-report { padding: 5px 9px; font-size: 11.5px; color: var(--accent-d); border-color: var(--accent-line); }
.go-report-row .btn.go-report:disabled,
.go-report-row .btn.go-report:disabled:hover { color: var(--muted); border-color: var(--line); background: var(--surface); opacity: .6; cursor: default; }
.draw-wrap figcaption {
  font-family: var(--mono); font-size: 10.5px; color: var(--muted); text-align: center;
  margin-top: 10px; letter-spacing: -.01em; text-transform: lowercase;
}

/* ---------- Resultados ---------- */
.results { margin-top: 26px; }
.results h3 { margin: 0 0 4px; font-size: 18px; }
.results .sub { color: var(--muted); font-size: 13px; margin-bottom: 14px; }
.groove-filter { display: flex; gap: 10px; align-items: center; margin: -4px 0 12px; }
/* os demais inputs usam `background: var(--bg)` porque moram dentro de um .card
   (fundo --surface) — ali o --bg CONTRASTA. Este fica solto em #grooveResults,
   direto sobre a página, onde --bg é exatamente a cor do fundo e o campo some;
   por isso ele inverte a relação e usa --surface + borda mais firme. */
.groove-filter input { flex: 1; max-width: 420px; background: var(--surface); border-color: var(--line-2); }
/* --ink-soft, não --muted: o placeholder aqui é a única instrução do campo e em
   --muted dá 4,05:1 sobre --surface (abaixo de 4,5); --ink-soft dá 6,91:1 e
   continua secundário perto do --ink do texto digitado. opacity:1 porque o
   Firefox rebaixa a opacidade do placeholder por conta própria. */
.groove-filter input::placeholder { color: var(--ink-soft); opacity: 1; }
/* aviso de conferência (rastreabilidade) */
.tol-note {
  background: var(--accent-bg); border: 1px solid var(--accent-line); color: var(--accent-d);
  border-radius: 9px; padding: 9px 13px; font-size: 12.5px; line-height: 1.45; margin-bottom: 16px;
}
.seal {
  display: grid; grid-template-columns: auto 1fr auto; gap: 16px; align-items: center;
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 14px 18px; margin-bottom: 10px;
  transition: border-color .15s, transform .1s;
}
.seal:hover { border-color: var(--line-2); transform: translateX(2px); }
.seal.best { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent-bg); }

/* As 3 colunas do card (identificação | cotas | selo+quantidade) somam ~466px de
   min-content e NÃO encolhem — `auto` nunca passa do min-content. Em tela de
   375px isso estourava 166px pra fora e espremia as cotas numa tira de 41px de
   largura. No celular o card vira uma coluna só: identificação, cotas, e por
   último a faixa de ação (selo à esquerda, "+ Escolher" à direita). */
@media (max-width: 560px) {
  .seal { grid-template-columns: 1fr; gap: 10px; align-items: stretch; padding: 14px; }
  .seal > * { min-width: 0; }
  .seal > div:last-child {
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px;
    text-align: left !important; border-top: 1px solid var(--line); padding-top: 10px;
  }
  .seal > div:last-child .score { margin-top: 0; text-align: left; }
  .seal > div:last-child .qty-add { margin-top: 0; margin-left: auto; }
  .seal .mat-sel { max-width: 100%; min-height: 36px; }

  /* Alvos de toque. O app é usado na oficina, com o celular numa mão e muitas
     vezes com a mão suja ou de luva — controle de 18px vira loteria. Aqui só a
     ÁREA CLICÁVEL cresce; o desenho continua igual, senão o card incharia.
     O ⓘ ganha área por pseudo-elemento (ele é inline no meio do texto: aumentar
     a caixa de verdade empurraria a linha inteira). */
  .seal .meta .cat-ref-info { position: relative; }
  .seal .meta .cat-ref-info::after {
    content: ''; position: absolute; top: 50%; left: 50%;
    transform: translate(-50%, -50%); width: 34px; height: 40px;
  }
  .qty-add input { min-height: 38px; }
  /* `.seal` na frente só pra ganhar de `.btn.add` (mesma especificidade, porém
     declarado DEPOIS neste arquivo — sem isso o padding menor vence). */
  .seal .btn.add { padding: 10px 16px; }
  .seal > div:last-child .go-report-row { margin-top: 0; margin-left: 6px; }
  .seal .btn.go-report { padding: 9px 12px; font-size: 12px; min-height: 38px; }   /* mesmo alvo de toque do resto do card */
}
.seal-id { display: flex; gap: 12px; align-items: flex-start; }
.prof-icon { flex: none; width: 62px; padding: 4px; background: #fff; border: 1px solid var(--line); border-radius: 8px; display: flex; align-items: center; justify-content: center; }
.prof-svg { width: 40px; height: auto; display: block; }
.prof-img { width: 100%; height: auto; display: block; border-radius: 3px; }
.prof-icon.zoomable { cursor: zoom-in; transition: border-color .12s, box-shadow .12s; }
.prof-icon.zoomable:hover { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-bg); }

/* lightbox de ampliação da figura do catálogo */
.img-lightbox { display: none; position: fixed; inset: 0; z-index: 300; background: rgba(40,33,20,.6);
  align-items: center; justify-content: center; padding: 24px; }
.img-lightbox.open { display: flex; }
.img-lightbox .lb-card { background: var(--surface); border-radius: 14px; box-shadow: 0 20px 60px rgba(0,0,0,.4);
  max-width: min(940px, 94vw); max-height: 92vh; overflow: auto; padding: 22px 24px; position: relative; }
.img-lightbox .lb-close { position: absolute; top: 12px; right: 12px; width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid var(--line-2); background: var(--surface); color: var(--ink); font-size: 16px; cursor: pointer; }
.img-lightbox .lb-close:hover { background: var(--surface-2); }
.img-lightbox .lb-title { font-family: var(--mono); font-size: 12.5px; color: var(--accent-d); text-transform: uppercase;
  letter-spacing: .04em; margin-bottom: 16px; padding-right: 40px; }
.img-lightbox .lb-imgs { display: flex; flex-wrap: wrap; gap: 18px; justify-content: center; }
.img-lightbox figure { margin: 0; background: #fff; border: 1px solid var(--line); border-radius: 10px; padding: 12px; }
.img-lightbox figcaption { font-family: var(--mono); font-size: 10px; color: var(--muted); text-transform: uppercase;
  letter-spacing: .04em; margin-bottom: 8px; }
.img-lightbox img { max-width: 100%; max-height: 64vh; height: auto; display: block; }

/* Visualizador de PDF do catálogo (só aparece no app INSTALADO — ver
   openPdfViewer em app.js). Ocupa quase a tela toda porque é uma página de
   catálogo cheia de tabela: num card pequeno não dá pra ler cota nenhuma.
   O `overflow:hidden` no card evita barra de rolagem dupla (a do modal e a do
   visualizador de PDF); quem rola é o próprio PDF, dentro do iframe. */
.pdf-modal { padding: 12px; }
.pdf-modal .lb-card {
  max-width: 96vw; width: 96vw; max-height: 94vh; height: 94vh;
  display: flex; flex-direction: column; overflow: hidden; padding: 16px 18px 12px;
}
.pdf-modal .lb-title { margin-bottom: 10px; }
.pdf-modal .pdf-frame {
  flex: 1; width: 100%; min-height: 0; border: 1px solid var(--line);
  border-radius: 8px; background: #fff;
}
.pdf-modal .lb-note { color: var(--muted); font-size: 11.5px; margin-top: 8px; text-align: center; }
@media (max-width: 560px) {
  .pdf-modal { padding: 6px; }
  .pdf-modal .lb-card { width: 99vw; max-width: 99vw; height: 96vh; max-height: 96vh; padding: 12px 10px 8px; }
}
/* popup "origem da medida" — reusa a casca do lightbox (.img-lightbox), só o miolo muda */
.src-modal .src-list { display: grid; grid-template-columns: auto 1fr; gap: 8px 18px; margin: 0; align-items: baseline; }
.src-modal .src-list dt { color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: .04em; }
.src-modal .src-list dd { margin: 0; font-family: var(--mono); font-size: 13.5px; color: var(--ink); }
.src-modal .src-note { margin: 18px 0 0; padding-top: 14px; border-top: 1px solid var(--line);
  color: var(--muted); font-size: 12.5px; max-width: 46ch; }
/* telas estreitas: rótulo em cima do valor — em 2 colunas o nome do catálogo
   (longo, ex. o da Parker) fica espremido em ~4 caracteres por linha */
@media (max-width: 560px) {
  .src-modal .src-list { grid-template-columns: 1fr; gap: 2px; }
  .src-modal .src-list dd { margin-bottom: 10px; word-break: break-word; }
}
.seal .pn { font-family: var(--mono); font-weight: 600; font-size: 15px; letter-spacing: -.02em; }
/* nome do perfil (a Freudenberg chama de "Design") antes do part number —
   fonte normal (não monoespaçada) pra não competir com o código em si */
.seal .pn .pn-profile { font-family: var(--sans, inherit); font-weight: 500; color: var(--ink-soft); }
.seal .meta { color: var(--ink-soft); font-size: 13px; margin-top: 3px; }
/* referência do catálogo — <a> quando existe PDF-fonte pra abrir na página exata
   (pdfLinkFor em app.js), <button> (abre o popup de origem) quando não existe */
.seal .meta .cat-ref, .cart-item .meta .cat-ref { font-family: var(--mono); font-size: 12px; color: var(--accent-d); cursor: pointer;
  background: var(--accent-bg); border: 1px solid var(--accent-line); border-radius: 6px; padding: 2px 7px;
  white-space: nowrap; text-decoration: none; display: inline-block; }
.seal .meta .cat-ref:hover, .cart-item .meta .cat-ref:hover { background: var(--surface-2); border-color: var(--accent); }
.seal .meta .cat-ref:focus-visible, .cart-item .meta .cat-ref:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* ⓘ — só aparece ao lado do link direto pro PDF, abre o popup de origem completa */
.seal .meta .cat-ref-info { font-size: 12px; color: var(--ink-soft); cursor: pointer; background: transparent;
  border: 1px solid var(--line-2); border-radius: 999px; width: 18px; height: 18px; line-height: 1;
  padding: 0; vertical-align: middle; }
.seal .meta .cat-ref-info:hover { background: var(--surface-2); color: var(--accent-d); border-color: var(--accent); }
.seal .meta .cat-ref-info:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.seal .mat-sel { margin-top: 7px; max-width: 190px; padding: 6px 8px; font-size: 12px; font-family: var(--mono);
  background: var(--surface-2); border: 1px solid var(--line-2); border-radius: 8px; color: var(--ink); cursor: pointer; }
.seal .mat-sel:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.seal .dims { font-family: var(--mono); font-size: 12px; color: var(--muted); margin-top: 5px; font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.seal .dims b { color: var(--accent-d); font-weight: 600; }
.canal-tol { font-size: 11px; color: var(--muted); margin-top: 3px; font-style: italic; cursor: help; }
.badge { padding: 4px 10px; border-radius: 6px; font-size: 10.5px; font-weight: 700; white-space: nowrap; text-align: center; font-family: var(--mono); text-transform: uppercase; letter-spacing: .04em; }
.badge.exact { background: var(--ok-bg); color: var(--ok); }
.badge.compat { background: var(--warn-bg); color: var(--warn); }
.badge.near { background: var(--surface-2); color: var(--danger); }
.badge.kit { background: var(--accent-bg); color: var(--accent-d); padding: 2px 7px; font-size: 9.5px; vertical-align: middle; cursor: help; }
.score { font-family: var(--mono); font-size: 10.5px; color: var(--muted); margin-top: 5px; text-align: right; letter-spacing: -.02em; }
.empty { color: var(--muted); padding: 28px; text-align: center; border: 1px dashed var(--line-2); border-radius: 12px; }
.alert { background: var(--warn-bg); color: var(--warn); border: 1px solid #E8D9B6; border-radius: 10px; padding: 11px 14px; font-size: 13.5px; margin-top: 14px; }

/* ---------- Catálogos ---------- */
.cat-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px 16px; border: 1px solid var(--line); border-radius: 11px; margin-bottom: 10px; background: var(--surface);
}
.cat-row .info b { font-size: 15px; }
.cat-row .info div { color: var(--muted); font-size: 12.5px; margin-top: 2px; }
.cat-row.is-ref { border-color: var(--accent); background: var(--accent-bg); }
.pill { font-size: 11px; font-weight: 700; color: var(--accent-d); background: var(--surface); border: 1px solid var(--accent-line); border-radius: 999px; padding: 3px 9px; }
code, .mono { font-family: ui-monospace, "SF Mono", "Consolas", monospace; font-size: 12.5px; }
.foot { text-align:center; color: var(--muted); font-size: 12px; margin-top: 40px; }
a { color: var(--accent-d); }
.link { background:none;border:none;color:var(--accent-d);cursor:pointer;text-decoration:underline;font-size:13px;padding:0; }

/* ---------- Carrinho ---------- */
.cart-count {
  display: inline-block; min-width: 18px; padding: 1px 6px; margin-left: 4px; border-radius: 999px;
  background: var(--accent); color: #fff; font-size: 11px; font-weight: 700; text-align: center; vertical-align: middle;
}
.cart-count.zero { background: var(--line-2); color: var(--muted); }
.btn.add { padding: 8px 14px; font-size: 13px; }
/* Cada item é um cartão fechado: cabeçalho em faixa (onde começa) + corpo sobre o
   fundo do painel. Antes a borda do item tinha o mesmo peso do divisor interno
   tracejado e não dava pra ver onde um item terminava e o próximo começava. */
.cart-item {
  border: 1px solid var(--line-2); border-radius: 12px; margin-bottom: 18px;
  background: var(--surface); box-shadow: var(--shadow); overflow: hidden;
}
.cart-item:last-child { margin-bottom: 4px; }
.cart-item:focus-within { border-color: var(--accent-line); box-shadow: 0 0 0 3px rgba(204,120,92,.10), var(--shadow); }
/* item apontado pelo atalho do resultado — sem o destaque, cair numa lista de 20
   itens não é melhor que procurar à mão, que é o que o atalho existe para evitar.
   Espelha o :focus-within acima (é como o relatório já diz "é este aqui"), com
   mais peso porque aqui ninguém está com o cursor no campo. */
/* ---------- dado de serviço (pressão / temperatura / velocidade) ----------
   Linha discreta sob as cotas: informa sem competir com o part number, que é o
   que o olho procura primeiro. O alerta usa a cor de perigo do app porque é o
   único caso em que o resultado pode estar ERRADO para a aplicação, não só
   distante dimensionalmente. */
.duty-note { font-size: 12px; color: var(--ink-soft); margin-top: 4px; }
.duty-note b { color: var(--muted); font-weight: 600; }
.duty-note.sem { color: var(--muted); font-style: italic; }
.duty-alerta {
  font-size: 12px; margin-top: 4px; padding: 4px 8px; border-radius: 8px;
  color: var(--danger); background: var(--danger-bg); border: 1px solid var(--danger);
}
/* COMPATIBILIDADE COM O FLUIDO (Fase 3) — mesma família visual da linha de
   serviço: nota discreta quando serve, âmbar quando a tabela diz "limitada",
   vermelha quando diz "não recomendado". Os dois lados usam token de tema
   (fundo E texto), nunca cor fixa de um lado só. */
.fluid-note { font-size: 12px; color: var(--ink-soft); margin-top: 4px; }
.fluid-note b { color: var(--muted); font-weight: 600; }
.fluid-note.aviso {
  color: var(--warn); background: var(--warn-bg); border: 1px solid var(--warn);
  padding: 4px 8px; border-radius: 8px;
}
.fluid-note.aviso b { color: var(--warn); }
.fluid-alerta {
  font-size: 12px; margin-top: 4px; padding: 4px 8px; border-radius: 8px;
  color: var(--danger); background: var(--danger-bg); border: 1px solid var(--danger);
}
.fluid-alerta b { font-weight: 600; }
/* FOLGA DE EXTRUSÃO (Fase 5) — mesma família visual das linhas de serviço e
   fluido, pelos mesmos motivos: token dos DOIS lados, nunca cor fixa. */
.gap-note { font-size: 12px; color: var(--ink-soft); margin-top: 4px; }
.gap-note b { color: var(--muted); font-weight: 600; }
.gap-note.aviso {
  color: var(--warn); background: var(--warn-bg); border: 1px solid var(--warn);
  padding: 4px 8px; border-radius: 8px;
}
.gap-note.aviso b { color: var(--warn); }
.gap-alerta {
  font-size: 12px; margin-top: 4px; padding: 4px 8px; border-radius: 8px;
  color: var(--danger); background: var(--danger-bg); border: 1px solid var(--danger);
}
.gap-alerta b { font-weight: 600; }
/* quantas cotas a peça confirmou — vive junto do selo, porque é o selo que ele qualifica */
.conf-cotas { font-family: var(--mono); font-size: 10.5px; color: var(--muted); margin-top: 3px; }
.tol-note.aviso { color: var(--warn); background: var(--warn-bg); border-color: var(--warn); }
.tol-note.servico { color: var(--ink-soft); background: var(--surface-2); border-color: var(--line-2); }
#svResumo { font-family: var(--mono); color: var(--muted); }
#svResumo.on { color: var(--accent-d); font-weight: 600; }

.cart-item.destacado { border-color: var(--accent); box-shadow: 0 0 0 4px rgba(204,120,92,.22), var(--shadow); }
.cart-item .top {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  padding: 9px 12px; background: var(--surface-2); border-bottom: 1px solid var(--line);
}
.cart-item .top .meta { flex: 1; min-width: 0; color: var(--muted); font-size: 12.5px; }
.cart-item .top .icon-del { margin-left: auto; }
/* celular: nome do perfil e ✕ na primeira linha, procedência na segunda — senão a
   faixa vira quatro linhas com o texto espremido numa coluna de 40px */
@media (max-width: 560px) {
  .cart-item .top { row-gap: 3px; }
  .cart-item .pn-edit { flex: 1 1 auto; min-width: 0; }
  .cart-item .top .icon-del { order: 2; }
  .cart-item .top .meta { flex: 1 0 100%; order: 3; font-size: 11.5px; }
}
.cart-item .ci-body { padding: 2px 14px 14px; }
.cart-item .idx {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  min-width: 23px; height: 23px; padding: 0 5px; border-radius: 7px;
  background: var(--accent-bg); color: var(--accent-d); font-weight: 700; font-size: 12.5px;
}
/* alça de arraste — arrastar pelo card inteiro brigaria com a seleção de texto */
.drag-handle {
  flex: none; background: none; border: none; cursor: grab; color: var(--muted);
  font-size: 15px; line-height: 1; padding: 4px 3px; border-radius: 6px;
  touch-action: none; user-select: none; -webkit-user-select: none;
}
.drag-handle:hover { color: var(--accent); background: var(--accent-bg); }
.drag-handle:active { cursor: grabbing; }
.cart-item.dragging {
  opacity: .65; border-color: var(--accent); border-style: dashed;
  box-shadow: 0 10px 26px rgba(40,33,20,.16);
}
#cartList.is-dragging { cursor: grabbing; }
#cartList.is-dragging .cart-group-head { display: none; }
#cartList.is-dragging .cart-item:not(.dragging) { opacity: .9; }
/* faixa de grupo (só na tela — o relatório PDF/Excel não muda) */
.cart-group-head {
  display: flex; align-items: center; gap: 10px; margin: 22px 0 9px;
  font-family: var(--serif); font-size: 12.5px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--accent-d);
}
.cart-group-head::after { content: ''; flex: 1; height: 1px; background: var(--accent-line); }
.cart-group-head:first-child { margin-top: 2px; }
.cart-group-head.sem { color: var(--muted); }
.cart-group-head.sem::after { background: var(--line); }
.cart-item .pn-edit {
  font-family: var(--mono); font-weight: 700; font-size: 14.5px; border: 1px solid transparent;
  background: transparent; padding: 4px 6px; border-radius: 6px; min-width: 80px; width: auto;
}
.cart-item .pn-edit:hover { border-color: var(--line-2); background: var(--surface); }
.cart-item .pn-edit:focus { border-color: var(--accent); background: var(--surface); outline: none; }
.cart-item .row2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px,1fr)); gap: 10px; margin-top: 12px; }
.cart-item .row2 .field label { font-size: 11px; }
.cart-item input, .cart-item select { padding: 7px 9px; font-size: 13px; }
.cart-item .med-row { margin-top: 14px; padding-top: 12px; border-top: 1px dashed var(--line); }
.cart-item .med-seg button { font-size: 12.5px; padding: 6px 12px; }
.cart-item .med-fields { margin-top: 10px; }
.alt-letter { color: var(--accent-d); font-weight: 600; }
.icon-del { background: none; border: none; color: var(--accent-d); cursor: pointer; font-size: 18px; line-height: 1; padding: 2px 6px; }
.icon-del:hover { color: var(--accent); }
.toast {
  /* fundo FIXO (não var(--ink)) de propósito: --ink troca de quase-preto (claro)
     pra quase-branco (escuro), e o texto do toast é branco fixo — no tema
     escuro isso virava branco sobre creme claro, quase ilegível. O toast
     contrasta com a página nos dois temas, não segue a paleta ativa. */
  position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
  background: #2A2622; color: #fff; padding: 11px 20px; border-radius: 10px; font-size: 14px;
  box-shadow: 0 8px 30px rgba(0,0,0,.35); z-index: 100; opacity: 0; transition: opacity .25s, transform .25s; pointer-events: none;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(-4px); }

/* ---------- Alojamento do O'Ring (tabelas Vedabrás) ---------- */
.oring-segs { display: flex; gap: 26px; flex-wrap: wrap; }
.oring-segs .seg-label {
  display: block; font-size: 12px; font-weight: 600; color: var(--ink-soft); margin-bottom: 6px;
}
.oring-segs .hint { display: block; margin-top: 5px; max-width: 340px; }
/* corte do alojamento — eixo × furo */
.oring-fig-wrap { margin-top: 16px; }
.oring-fig { display: block; width: 100%; max-width: 540px; height: auto; }
.ordg-hit { fill: transparent; }
.ordg.on .ordg-hit { fill: var(--surface-2); stroke: var(--accent-line); }
.ordg:hover .ordg-hit { fill: var(--surface-2); }
.ordg { opacity: .5; transition: opacity .15s; }
.ordg.on { opacity: 1; }
.ordg:hover { opacity: .85; }
.ordg.on:hover { opacity: 1; }
.ordg-metal path { fill: url(#orHach); stroke: var(--steel); stroke-width: 1.4; }
.ordg-lisa rect { fill: var(--steel-bg); stroke: var(--steel); stroke-width: 1.1; opacity: .75; }
.ordg-hach { stroke: var(--steel); stroke-width: 1; opacity: .55; }
.ordg-seta { fill: var(--muted); }
.ordg-anel { fill: var(--accent); stroke: var(--accent-d); stroke-width: 1; }
/* anel antiextrusão: mesma família de cor do o'ring (é o mesmo conjunto de vedação),
   mas rebaixado, pra não competir com o anel em si. Derivado de --accent de propósito:
   um valor fixo aqui inverteria de leitura entre os temas claro/escuro. */
.ordg-backup { fill: var(--accent); fill-opacity: .34; stroke: var(--accent-d); stroke-width: 1; }
.ordg-centro { stroke: var(--muted); stroke-width: .9; stroke-dasharray: 12 3 2 3; opacity: .85; }
.ordg-cota line { stroke: var(--muted); stroke-width: .9; }
.ordg-cota .ordg-ext { stroke-width: .7; opacity: .75; }   /* linha de chamada, mais leve que a de cota */
.ordg-tapa { fill: var(--surface-2); }   /* respiro atrás do "G", que fica sobre a hachura */
.ordg.on .ordg-tapa { fill: var(--surface-2); }
.ordg-cota text { fill: var(--ink-soft); font-family: var(--mono); font-size: 9.5px; text-anchor: middle; }
/* desvio de tolerância suspenso ao lado do nominal (formato bilateral), em fonte menor.
   Precisa de `.ordg-cota text.ordg-tol`: só `.ordg-tol` PERDE pra `.ordg-cota text`,
   que já fixa 9,5px — mesma armadilha de especificidade já documentada neste projeto
   (regra de mesma especificidade perde pra quem vem depois; aqui é menor mesmo). */
.ordg-cota text.ordg-tol { font-size: 6.5px; }
.ordg-tt { fill: var(--accent-d); font-family: var(--serif); font-size: 13px; text-anchor: middle; letter-spacing: .08em; }
.ordg-sub { fill: var(--muted); font-size: 10px; text-anchor: middle; }

.oring-out {
  margin-top: 16px; border: 1px solid var(--accent-line); border-radius: 12px;
  background: var(--surface-2); padding: 14px 16px;
}
.oring-hd {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding-bottom: 10px; border-bottom: 1px solid var(--line);
}
.oring-hd b { font-family: var(--mono); font-size: 15px; color: var(--accent-d); }
.oring-hd span { color: var(--muted); font-size: 12.5px; }
.oring-hd .oring-fonte { margin-left: auto; font-size: 11.5px; font-style: italic; }
/* referência clicável da fonte (Hercules/Vedabrás) -- abre a página exata do
   PDF, mesma ideia do .cat-ref dos resultados de vedação */
.oring-hd .oring-fonte-link { margin-left: auto; font-size: 11.5px; font-style: italic;
  color: var(--accent-d); text-decoration: none; }
.oring-hd .oring-fonte-link:hover { text-decoration: underline; }
.oring-sub .oring-fonte-link { font-size: 10.5px; font-style: italic; color: var(--accent-d); text-decoration: none; }
.oring-sub .oring-fonte-link:hover { text-decoration: underline; }
.oring-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(165px, 1fr));
  gap: 10px 18px; margin-top: 12px;
}
.oring-grid div { display: flex; flex-direction: column; gap: 2px; }
.oring-grid span { font-size: 11.5px; color: var(--muted); }
.oring-grid b { font-family: var(--mono); font-size: 13.5px; }
.oring-grid .oring-sub { font-size: 10.5px; font-style: italic; }
.oring-faixa {
  margin-top: 12px; padding-top: 11px; border-top: 1px dashed var(--line); font-size: 13.5px;
}
.oring-faixa b { font-family: var(--mono); color: var(--accent-d); }
.oring-faixa span { display: block; color: var(--muted); font-size: 12px; margin-top: 3px; }
.oring-note {
  margin-top: 10px; font-size: 12.5px; color: var(--ink-soft);
  background: var(--surface); border: 1px solid var(--line); border-radius: 9px; padding: 8px 11px;
}
.oring-note.warn { color: var(--warn); background: var(--warn-bg); border-color: transparent; }
.oring-acao { margin-top: 12px; }

/* ---------- Anéis-Guia (glândula) — desenho técnico portado do protótipo
   Faberium Guide (conjunto montado + detalhe ampliado), só recolorido:
   navy/cobre/ciano da Faberium -> --steel/--accent/--muted do GABRIEL SEAL. */
.gd-fig { display: block; width: 100%; max-width: 880px; max-height: 405px; height: auto; margin: 0 auto; }
.gd-fig pattern line { stroke: var(--steel); stroke-width: 4; }
.gd-fig #gdFineHatch line { stroke: var(--steel); stroke-width: 3; }
.gd-sectioned { fill: url(#gdHatch); stroke: var(--steel); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.gd-component { fill: var(--steel-bg); stroke: var(--steel); stroke-width: 1.6; vector-effect: non-scaling-stroke; }
.gd-rod-body { fill: var(--steel-bg); }
.gd-ring { fill: var(--accent); stroke: var(--accent-d); stroke-width: 1.3; vector-effect: non-scaling-stroke; }
.gd-ref-surface { fill: none; stroke: var(--ink-soft); stroke-width: 1.3; vector-effect: non-scaling-stroke; }
.gd-centerline { fill: none; stroke: var(--muted); stroke-width: 1; stroke-dasharray: 12 7; vector-effect: non-scaling-stroke; }
.gd-view-label { fill: var(--ink-soft); font-family: var(--mono); font-size: 12px; font-weight: 650; letter-spacing: .08em; }
.gd-dim path { fill: none; stroke: var(--muted); stroke-width: 1.4; }
.gd-dim .gd-ext-line { stroke-width: 1; opacity: .72; }
.gd-dim .gd-arrow-line { marker-start: url(#gdArrow); marker-end: url(#gdArrow); }
.gd-dim text { fill: var(--ink-soft); font-family: var(--mono); font-size: 11px; letter-spacing: .015em; }
.gd-dim-note { fill: var(--ink-soft); font-family: var(--mono); font-size: 10px; letter-spacing: .015em; }
.gd-leader .gd-leader-line { marker-end: url(#gdLeaderArrow); stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; }
.gd-callout-label { font-weight: 600; paint-order: stroke; stroke: var(--surface); stroke-width: 4px; stroke-linejoin: round; }
.gd-fig marker path { fill: var(--muted); }
.gd-detail-frame { fill: var(--surface-2); stroke: var(--line); stroke-width: 1; }
.gd-detail-divider { fill: none; stroke: var(--line); stroke-width: 1; }
.gd-profile-label { fill: var(--muted); font-family: var(--mono); font-size: 10px; font-weight: 600; letter-spacing: .06em; }
.gd-profile-caption { fill: var(--ink-soft); font-family: var(--mono); font-size: 11px; font-weight: 540; }
.gd-profile-ring { fill: var(--accent); stroke: var(--accent-d); stroke-width: 1.2; }
.gd-profile-joint { fill: none; stroke: var(--surface); stroke-width: 3; }
.gd-scale-caption { fill: var(--accent-d); font-family: var(--mono); font-size: 9px; font-weight: 600; letter-spacing: .06em; }
.gd-invalid path { stroke: var(--danger); stroke-width: 1; stroke-dasharray: 8 6; }
.gd-invalid text:first-of-type { fill: var(--danger); font-family: var(--mono); font-size: 14px; font-weight: 650; letter-spacing: .08em; }
.gd-invalid text:last-of-type { fill: var(--muted); font-family: var(--sans); font-size: 12px; }
.gd-formula { margin: 0; padding-left: 22px; color: var(--ink-soft); }
.gd-formula li { font-family: var(--mono); font-size: 12.5px; margin-bottom: 8px; line-height: 1.5; }
#gdDrawCard #gdFig { min-height: 260px; }

/* Veredito dos cálculos de VERIFICAÇÃO (flambagem, intensificação) — o
   resultado aqui não é um número, é um "passa / não passa", e precisa ser
   lido de longe na bancada. Cor semântica dos tokens já existentes. */
.cy-veredito {
  display: inline-block; margin: 4px 0 10px; padding: 7px 16px; border-radius: 999px;
  font-weight: 700; font-size: 14px; letter-spacing: .06em;
}
.cy-veredito.ok  { background: var(--ok-bg);     color: var(--ok);     border: 1px solid var(--ok); }
.cy-veredito.nao { background: var(--danger-bg); color: var(--danger); border: 1px solid var(--danger); }

/* ---------- Aba Peso (cylinder_mass.js) ----------
   Duas colunas no desktop: formulário à esquerda, card de resultado GRUDADO
   (sticky) à direita — o spec pede o resultado principal sempre visível. No
   celular vira coluna única com o resultado ANTES do formulário, que é onde
   ele é útil sem precisar rolar de volta. */
.mass-layout { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 18px; align-items: start; }
.mass-result { position: sticky; top: 16px; }
@media (max-width: 900px) {
  .mass-layout { grid-template-columns: 1fr; }
  .mass-result { position: static; order: -1; }
}
/* Condições de trabalho (Fase 4/3/5) — mesmo componente recolhível de baixo,
   reaproveitado aqui: nasce FECHADO (só abre sozinho quando já há condição
   salva do localStorage) e o resumo fica visível no próprio cabeçalho, para o
   usuário nunca precisar abrir só para conferir o que está em uso. */
#servicoCard > summary { flex-wrap: wrap; }
#servicoCard > summary .sec-kg { flex: 1 0 100%; margin-left: 0; font-weight: 600; }
#servicoCard > summary .sec-kg.on { color: var(--accent-d); }

/* seção recolhível — mesma casca do .card, com o <summary> como cabeçalho */
.mass-sec {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 0 18px; margin-bottom: 12px;
}
.mass-sec > summary {
  cursor: pointer; padding: 14px 0; font-family: var(--serif); font-size: 15.5px;
  display: flex; align-items: center; gap: 10px; list-style: none;
}
.mass-sec > summary::-webkit-details-marker { display: none; }
.mass-sec > summary::before {
  content: "▸"; color: var(--muted); font-family: var(--sans); font-size: 12px; transition: transform .15s;
}
.mass-sec[open] > summary::before { transform: rotate(90deg); }
.mass-sec > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }
.mass-sec .sec-kg { margin-left: auto; font-family: var(--mono); font-size: 12.5px; color: var(--accent-d); font-weight: 600; }
.mass-sec .sec-body { padding: 2px 0 18px; }
.mass-sec .sec-nota { color: var(--muted); font-size: 12px; margin: 0 0 12px; line-height: 1.5; }

/* card de resultado */
.mass-total {
  background: var(--surface); border: 1px solid var(--accent-line); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 16px 18px;
}
.mass-total h3 { margin: 0 0 2px; font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.mass-total .big { font-family: var(--mono); font-size: 30px; font-weight: 700; color: var(--accent-d); line-height: 1.1; }
.mass-total .big small { font-size: 15px; font-weight: 600; margin-left: 3px; }
.mass-total .sub { font-family: var(--mono); font-size: 12px; color: var(--ink-soft); margin-top: 5px; }
.mass-badge {
  display: inline-block; margin-top: 10px; font-size: 10.5px; letter-spacing: .07em; text-transform: uppercase;
  font-weight: 700; padding: 3px 9px; border-radius: 999px;
}
.mass-badge.estimado { background: var(--warn-bg); color: var(--warn); }
.mass-badge.comercial { background: var(--accent-bg); color: var(--accent-d); }
.mass-badge.real { background: var(--ok-bg); color: var(--ok); }
.mass-badge-desc { display: block; font-size: 11.5px; color: var(--muted); margin-top: 6px; line-height: 1.5; }

/* decomposição por componente */
.mass-break { margin-top: 14px; border-top: 1px solid var(--line); padding-top: 12px; }
.mass-break-row { display: grid; grid-template-columns: 1fr auto auto; gap: 8px 10px; align-items: center; font-size: 12.5px; padding: 3px 0; }
.mass-break-row .nm { color: var(--ink-soft); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mass-break-row .kg { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.mass-break-row .pc { font-family: var(--mono); font-size: 11px; color: var(--muted); min-width: 42px; text-align: right; }
.mass-break-row.tot { border-top: 1px solid var(--line); margin-top: 6px; padding-top: 8px; font-weight: 700; }
.mass-break-row.tot .nm { color: var(--ink); }
/* barra de proporção — SVG à mão, o projeto não usa biblioteca de gráfico */
.mass-bar { width: 100%; height: 22px; display: block; margin: 10px 0 4px; border-radius: 5px; overflow: hidden; }
.mass-legend { display: flex; flex-wrap: wrap; gap: 4px 12px; font-size: 11px; color: var(--muted); margin-top: 6px; }
.mass-legend i { width: 9px; height: 9px; border-radius: 2px; display: inline-block; margin-right: 4px; vertical-align: -1px; }

/* linha de peça repetível (olhais, buchas, pinos...) e features do modo engenharia */
.mass-rows { display: flex; flex-direction: column; gap: 8px; }
.mass-row {
  display: grid; gap: 8px; align-items: end;
  grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); padding: 10px;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 10px;
}
.mass-row .field label { font-size: 10.5px; }
.mass-row .rm {
  background: none; border: 1px solid var(--line-2); color: var(--muted); border-radius: 8px;
  cursor: pointer; font-size: 16px; line-height: 1; padding: 7px 10px; align-self: center; font-family: inherit;
}
.mass-row .rm:hover { border-color: var(--danger); color: var(--danger); }
.mass-add {
  background: none; border: 1px dashed var(--line-2); color: var(--ink-soft); border-radius: 10px;
  padding: 9px 14px; cursor: pointer; font-family: inherit; font-size: 13px; align-self: start;
}
.mass-add:hover { border-color: var(--accent); color: var(--accent-d); }
.mass-op { font-family: var(--mono); font-weight: 700; }

/* ---------- Overlay do relatório ---------- */
.report-overlay { display: none; position: fixed; inset: 0; background: rgba(40,33,20,.45); z-index: 200; overflow: auto; padding: 24px; }
.report-overlay.open { display: block; }
.report-bar { max-width: 1040px; margin: 0 auto 14px; display: flex; gap: 12px; justify-content: flex-end; }
.report-paper { max-width: 1040px; margin: 0 auto; background: #fff; color: #111; padding: 28px 30px; border-radius: 6px; box-shadow: 0 10px 40px rgba(0,0,0,.3); }
.report-paper h1 { font-family: var(--sans); font-size: 17px; text-align: center; margin: 0 0 4px; letter-spacing: .02em; }
.report-paper .rsub { text-align: center; color: #555; font-size: 12px; margin-bottom: 16px; }
.rhead { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 28px; font-size: 12.5px; margin-bottom: 14px; border: 1px solid #ccc; padding: 12px 14px; border-radius: 4px; break-inside: avoid; }
.rhead b { color: #000; }
table.rtable { width: 100%; border-collapse: collapse; font-size: 11px; }
table.rtable tr { break-inside: avoid; }
table.rtable th, table.rtable td { border: 1px solid #bbb; padding: 4px 6px; text-align: center; }
table.rtable th { background: #efece4; font-weight: 600; font-size: 10px; }
table.rtable td.l { text-align: left; }
table.rtable tr.canal td { background: #fff; }
table.rtable tr.catalogo td { background: #F4E5DD; }
table.rtable tr.peca td { background: #faf9f5; color: #444; }
.report-brand { display:flex;align-items:center;gap:8px;justify-content:center;margin-bottom:6px; }
.report-brand .name { font-family: var(--serif); font-size: 18px; }
.report-brand .name span { color: var(--accent); }
.report-warn {
  margin-top: 12px; padding: 9px 12px; font-size: 11px; line-height: 1.5;
  background: #F4E5DD; border: 1px solid #E7CDC1; border-radius: 6px; color: #8A4A34;
  -webkit-print-color-adjust: exact; print-color-adjust: exact;
}
.report-warn b { color: #6B3D2A; }
/* Corte cotado do O'ring DENTRO do papel impresso (oringPrintoutHTML, app.js).
   As classes `ordg-*` pintam por token de tema: no tema ESCURO o traço é claro e
   sumiria na página branca. Aqui elas são forçadas pra preto-no-branco — regra
   normal (não dentro de `@media print`) porque a pré-visualização na tela é o
   mesmo papel, e tem que sair igual ao que vai imprimir.
   ATENÇÃO à especificidade: onde o original usa `.ordg.on .X` (0,0,3,0), o
   override precisa de `.report-paper .ordg.on .X` — só `.report-paper .X` perde. */
.report-paper .oring-fig { max-width: 470px; margin: 12px auto 0; break-inside: avoid; }
.report-paper .ordg { opacity: 1; }
.report-paper .ordg.on .ordg-hit { fill: none; stroke: #ddd; }
.report-paper .ordg.on .ordg-tapa { fill: #fff; }
.report-paper .ordg-hach { stroke: #9a9a9a; }
.report-paper .ordg-metal path { stroke: #333; }
.report-paper .ordg-lisa rect { fill: #f1f1f1; stroke: #333; opacity: 1; }
.report-paper .ordg-anel { fill: #d2d2d2; stroke: #222; }
/* cinza mais presente que o #f0f0f0 da 1ª tentativa: contra papel branco um cinza de
   6% costuma sair como branco na impressora, e aí o antiextrusão viraria só o contorno */
.report-paper .ordg-backup { fill: #e6e6e6; fill-opacity: 1; stroke: #222; }
.report-paper .ordg-seta { fill: #222; }
.report-paper .ordg-cota line { stroke: #333; }
.report-paper .ordg-cota text { fill: #111; }
.report-paper .ordg-centro { stroke: #777; }
.report-paper .ordg-sub { fill: #666; }
/* memória de cálculo do Anéis-Guia (openGuidePrintPreview, app.js) — mesmo
   papel branco do relatório de canais, só que o conteúdo aqui é fórmula/lista
   em vez de tabela larga; `break-inside:avoid` em cada linha evita cortar uma
   fórmula ou aviso ao meio entre duas páginas. */
.gd-print-formula, .gd-print-warnings { margin: 0 0 4px; padding-left: 20px; font-size: 11.5px; color: #222; }
.gd-print-formula li, .gd-print-warnings li { margin-bottom: 6px; line-height: 1.5; break-inside: avoid; }
.gd-print-formula li { font-family: var(--mono); }

/* ---------- Lista de sugestões (substitui o <datalist>, que o webview não abre) ---------- */
.combo-pop {
  position: fixed; z-index: 120; max-height: 240px; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--line-2);
  border-radius: 10px; box-shadow: var(--shadow); padding: 4px;
}
.combo-opt {
  padding: 8px 11px; border-radius: 7px; cursor: pointer;
  color: var(--ink); font-size: 14px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.combo-opt:hover, .combo-opt.on { background: var(--accent-bg); color: var(--accent-d); }

/* ---------- Calculadora de Ajustes e Tolerâncias ISO 286 ---------- */
/* font-size >= 16px só nesses 3 campos: evita zoom involuntário no iOS ao
   focar, sem mudar o padrão de 14px usado no resto do site */
#isoD, #isoShaftIn, #isoHoleIn { font-size: 16px; }
.iso-out-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin-top: 16px;
}
.iso-out-item {
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px;
}
.iso-out-item label { display: block; font-size: 11.5px; color: var(--muted); font-weight: 600; letter-spacing: .01em; margin-bottom: 4px; }
.iso-out-item .v { font-family: var(--mono); font-size: 16px; font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.iso-out-item .v.empty { color: var(--muted); font-weight: 400; }
.iso-out-item .v .badge { white-space: normal; line-height: 1.4; display: inline-block; }
.iso-preset {
  background: var(--surface); border: 1px solid var(--line-2); color: var(--ink-soft);
  border-radius: 999px; padding: 6px 13px; font-size: 12.5px; font-family: var(--mono); cursor: pointer;
}
.iso-preset:hover { border-color: var(--accent); color: var(--accent-d); }
.badge.folga { background: var(--ok-bg); color: var(--ok); }
.badge.interferencia { background: var(--danger-bg); color: var(--danger); }
.badge.incerto { background: var(--warn-bg); color: var(--warn); }
.iso-disclaimer { color: var(--muted); font-size: 12px; margin-top: 26px; max-width: 70ch; }
.iso-explain { margin-top: 16px; border: 1px solid var(--line); border-radius: 12px; padding: 4px 16px; background: var(--surface); }
.iso-explain summary { cursor: pointer; padding: 12px 0; font-weight: 600; color: var(--ink); }
.iso-explain p { color: var(--ink-soft); font-size: 13.5px; line-height: 1.6; max-width: 74ch; }
.iso-explain code { background: var(--surface-2); border-radius: 4px; padding: 1px 5px; }
/* Ilustração do ajuste (images_iso/) — 7 desenhos isométricos, um por linha da
   tabela de referência. Vão em cartão BRANCO pelo mesmo motivo das figuras de
   catálogo (.catalog-fig .fig-cell): a arte tem fundo branco próprio, então
   sem o cartão ela vira um bloco claro solto no meio do tema escuro. */
.iso-fit-fig { margin: 0 0 18px; padding: 14px 16px 10px; }
.iso-fit-fig #isoFitFig { background: #fff; border: 1px solid var(--line); border-radius: 10px;
  padding: 8px; max-width: 268px; margin: 0 auto; }
.iso-fit-fig img { width: 100%; height: auto; display: block; }
.iso-fig-nome { font-family: var(--mono); font-size: 11px; font-weight: 700; color: #B5634A;
  text-transform: uppercase; letter-spacing: .05em; text-align: center; margin-top: 6px; }
/* .draw-wrap figcaption força lowercase (serve pras legendas curtas do catálogo);
   aqui a legenda é frase com pontuação, então volta ao texto normal */
.iso-fit-fig figcaption { text-transform: none; font-size: 12px; line-height: 1.55; max-width: 46ch; margin-left: auto; margin-right: auto; }

@media print {
  /* Tentativa anterior usava `visibility:hidden` no resto da página +
     `#reportOverlay` em `position:absolute`/`fixed` pra "flutuar por cima".
     Isso PIOROU o problema (testado e confirmado pelo usuário: 3 páginas
     bagunçadas, título repetido) -- `visibility:hidden` mantém o elemento
     ocupando espaço no layout, só fica invisível; com o resto do app
     (header + `.wrap` inteiro, com todos os resultados de busca) ainda
     ocupando várias telas de altura ANTES do relatório no fluxo do
     documento, o Chrome paginava esse espaço fantasma primeiro (páginas em
     branco), e o posicionamento absolute/fixed do overlay por cima disso
     ainda causava recorte/duplicação do conteúdo entre páginas.
     Fix de verdade: tirar o resto do app do FLUXO com `display:none`
     (não só invisível — removido de verdade), daí `#reportOverlay` fica
     como o ÚNICO conteúdo do body e o Chrome pagina só pela altura real da
     tabela do relatório, sem nada fantasma antes. */
  .combo-pop { display: none; }
  body > *:not(#reportOverlay) { display: none !important; }
  #reportOverlay { display: block !important; position: static; inset: auto; overflow: visible; height: auto; background: #fff; padding: 0; }
  .report-bar { display: none; }
  .report-paper { box-shadow: none; max-width: none; margin: 0; padding: 10px; border-radius: 0; height: auto; min-height: 0; }
  @page { size: A4 landscape; margin: 10mm; }
}

/* ============================================================
   iOS: impedir o zoom automático ao focar um campo
   ============================================================
   O iOS DÁ ZOOM SOZINHO em qualquer input/select com fonte menor que 16px — e,
   depois do zoom, a página fica mais larga que a tela e o usuário tem que
   arrastar de lado pra alcançar o resto do formulário. Foi o que o vídeo de uso
   no celular mostrou (2026-08-25): ao tocar em "Ø interno — haste", os campos da
   coluna direita saíram pra fora da tela.

   16px é o LIMIAR do iOS, não uma escolha de estética — abaixo disso ele sempre
   amplia. Por isso esta regra fica no FIM da folha: várias declarações de 13/14px
   (.qty-add input, .cart-item input, .pn-edit) vêm depois no arquivo e ganhavam
   da primeira versão desta regra, que eu tinha posto no meio.
   Só no celular — no desktop não há esse zoom e as fontes menores continuam. */
@media (max-width: 560px) {
  input, select, textarea { font-size: 16px; }
  .qty-add input, .cart-item input, .cart-item select,
  .cart-item .pn-edit, .seal .mat-sel, .groove-filter input { font-size: 16px; }
}

/* popup do Nº da OS — QUARTO cliente da casca .img-lightbox (depois do lightbox de
   figura, do popup de origem e do visualizador de PDF). Só o miolo é próprio; não
   criar outra casca de modal. */
.os-modal .lb-card { max-width: 420px; width: min(420px, 92vw); }
.os-modal .os-modal-body { margin-top: 4px; }
.os-modal .os-modal-body .oring-note { margin: 0 0 14px; }
.os-modal .os-modal-body .field { margin-bottom: 16px; }
.os-modal .os-modal-body .actions { display: flex; gap: 8px; flex-wrap: wrap; }
.os-modal .os-modal-body .actions .btn { flex: 1 1 auto; }
/* Referência de página no item do carrinho. O estilo do chip vem da MESMA regra do
   resultado de busca (o seletor lá em cima cobre os dois contextos) — aqui só o
   tamanho é ajustado. Antes, a regra estava presa a `.seal .meta` e no carrinho o
   chip ficava SEM estilo nenhum: no navegador comum ainda passava, porque é um <a>,
   mas no PWA `refPaginaCarrinho` rende um <button> e sobrava o botão cru do
   navegador — caixa cinza ilegível. Ao estilizar `.cat-ref`/`.cat-ref-info` num
   contexto novo, cobrir as DUAS variantes de tag. */
.cart-item .meta .cat-ref { font-size: 11.5px; padding: 1px 6px; }

/* "Canal (catálogo)" é só leitura: a cota é da FONTE, não do usuário (pedido de
   2026-09-02). O campo continua visível e copiável — só não aceita edição. */
.cart-item .med-fields input[readonly] {
  background: var(--surface-2); color: var(--muted); cursor: default;
}
.cart-item .med-nota {
  margin-top: 8px; font-size: 12px; color: var(--muted); line-height: 1.45;
}

/* ---------------------------------------------------------------------------
   GERADOR DE ROSCAS. Aparência de ferramenta de engenharia: o desenho é o
   elemento central, dado técnico em monoespaçada, nada de card decorativo.
   Usa só os tokens de tema já existentes — nenhuma cor fixa, senão o desenho
   inverteria de legibilidade entre claro e escuro (ver a regra do .toast).
   --------------------------------------------------------------------------- */
/* IDENTIFICAÇÃO DE ROSCA — bloco de entrada e cartões de candidato. Cada cartão
   é um botão: a ação principal é CARREGAR aquela rosca na calculadora. O que o
   app não sabe calcular (Whitworth 55°, trapezoidal 30°) aparece igual, mas
   desabilitado e dizendo o porquê — some-lo esconderia a identificação certa. */
.th-ident { border: 1px solid var(--line); border-radius: 12px; padding: 14px;
  background: var(--surface-2); margin-bottom: 18px; }
.th-ident-hd { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.th-ident-hd strong { font-size: 14px; }
/* Grade PRÓPRIA da identificação: os 4 campos numa linha só. Antes eram 5 itens
   numa .grid-4 — o quinto (os botões, num campo-fantasma com label vazio) caía
   sozinho numa segunda linha e desalinhava o bloco inteiro. Os botões saíram
   para uma faixa própria. */
/* As duas grades do painel de rosca têm COLUNA FIXA, não auto-fit. Com auto-fit
   a contagem por linha muda com a largura: em 1180px os 8 campos do formulário
   abriam 6 + 2, deixando dois órfãos na segunda linha. Fixo em 4, sempre dá
   2 linhas cheias. */
.th-ident-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1fr;
  gap: 12px 14px; align-items: start; }
#cyThreadHead > .grid { grid-template-columns: repeat(4, 1fr); align-items: start; }
.th-ident-btns { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; }

/* TROCA DE PERFIL de um item do carrinho. A faixa fica no topo da busca porque é
   ali que o usuário age — sem ela, escolher uma peça substituiria um item em
   silêncio, o oposto do que o resto da tela faz. */
.edit-banner { display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  border: 1px solid var(--accent-line); background: var(--accent-bg);
  border-radius: 10px; padding: 10px 14px; margin-bottom: 14px; font-size: 13px; }
.edit-banner span { flex: 1 1 260px; }
.icon-edit { background: none; border: 0; cursor: pointer; color: var(--muted);
  font-size: 15px; line-height: 1; padding: 4px 6px; border-radius: 6px; }
.icon-edit:hover { color: var(--accent-d); background: var(--accent-bg); }
/* Rótulo de altura fixa em TODO o painel de rosca: o alternador de unidade mora
   dentro de um dos rótulos e o deixava mais alto que os vizinhos, jogando aquele
   campo fora de linha. */
#cyThreadHead .field > label { display: flex; align-items: center; min-height: 25px; }
.seg.seg-mini button { line-height: 1; }
/* dica com duas linhas reservadas — sem isso a altura da dica muda por campo e
   as linhas da grade saem irregulares */
#cyThreadHead .field > .hint { display: block; min-height: 2.5em; }
@media (max-width: 860px) {
  .th-ident-grid, #cyThreadHead > .grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
  .th-ident-grid, #cyThreadHead > .grid { grid-template-columns: 1fr; }
  #cyThreadHead .field > .hint { min-height: 0; }
}
/* alternador de unidade DE ENTRADA, dentro do próprio rótulo do campo. Miúdo de
   propósito: é conveniência de digitação, não uma escolha de engenharia — a
   unidade do RESULTADO continua sendo a da norma da rosca. */
.seg.seg-mini { display: inline-flex; margin-left: 8px; vertical-align: middle; }
.seg.seg-mini button { padding: 1px 7px; font-size: 10.5px; min-height: 0; height: 19px; }
.th-cands { display: grid; grid-template-columns: repeat(auto-fill, minmax(258px, 1fr)); gap: 10px; }
.th-cand { display: flex; flex-direction: column; gap: 3px; text-align: left; cursor: pointer;
  padding: 10px 12px; border: 1px solid var(--line-2); border-radius: 10px;
  background: var(--surface); color: inherit; font: inherit; }
.th-cand:hover:not(:disabled) { border-color: var(--accent); background: var(--accent-bg); }
.th-cand-nome { font-family: var(--mono); font-weight: 700; font-size: 15px; color: var(--accent-d); }
.th-cand-norma { font-size: 11.5px; color: var(--ink-soft); }
.th-cand-erro { font-family: var(--mono); font-size: 11px; color: var(--muted); }
.th-cand-acao { font-size: 11.5px; color: var(--accent-d); margin-top: 3px; }
/* veredito de tolerância no próprio cartão: verde dentro, âmbar fora, apagado
   quando não há tabela para julgar (polegada, Whitworth, trapezoidal). */
.th-cand-tol { font-size: 11.5px; line-height: 1.35; margin-top: 4px; }
.th-cand-tol.ok { color: var(--ok); }
.th-cand-tol.fora { color: var(--danger); }
.th-cand-tol.semtab { color: var(--muted); }
.th-cand.semcalc { opacity: 1; cursor: pointer; }
.th-cand[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-bg); }
.th-cand.semcalc .th-cand-nome { color: var(--ink); }
.th-cand.semcalc .th-cand-acao { color: var(--muted); }
@media (max-width: 560px) { .th-cands { grid-template-columns: 1fr; } }
.report-paper .th-ident { display: none; }

.th-hero { display: flex; flex-direction: column; gap: 12px; }
.th-desig { font-family: var(--mono); font-size: 24px; font-weight: 700; color: var(--accent-d); letter-spacing: .01em; }
.th-kvs { display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); gap: 10px 18px; margin: 0; }
.th-kv dt { color: var(--muted); font-size: 11.5px; letter-spacing: .04em; }
/* SEM text-transform: uppercase aqui, ao contrário do resto do app. Em rosca a
   caixa da letra é a informação — d/d2/d3 é externa, D/D2/D1 é interna (ISO
   965-1). Maiusculizar o rótulo apagava justamente essa distinção. */
.th-kv dd { margin: 2px 0 0; font-family: var(--mono); font-size: 14px; color: var(--ink); }
.th-sec { color: var(--muted); font-size: 11.5px; }
.th-norm { font-size: 12.5px; color: var(--muted); border-top: 1px solid var(--line); padding-top: 10px; }
.th-norm.ok { color: var(--ok); }

/* desenho técnico */
.thread-fig { margin: 18px 0 0; padding: 0; }
.thread-fig figcaption { margin-top: 8px; color: var(--muted); font-size: 12px; }
/* max-height: o desenho mantém a proporção REAL da peça (uma rosca M36×40 é quase
   quadrada), o que em tela cheia dava 670px de altura só de desenho. O viewBox
   preserva o aspecto ao encolher, então limitar a altura não distorce nada. */
.thread-svg { width: 100%; height: auto; max-height: 500px; display: block; background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 10px; }
.thread-svg .th-eixo { stroke: var(--muted); stroke-width: .8; stroke-dasharray: 8 3 2 3; }
.thread-svg .th-material { stroke: var(--ink); stroke-width: 1.6; fill: none; }
.thread-svg .th-corpo { fill: var(--steel-bg, var(--surface)); stroke: var(--ink); stroke-width: 1.4; }
.thread-svg .th-perfil { stroke: var(--accent); stroke-width: 1.2; fill: none; }
.thread-svg .th-diaMaior { stroke: var(--ink-soft); stroke-width: .8; }
.thread-svg .th-diaFlanco { stroke: var(--muted); stroke-width: .7; stroke-dasharray: 6 3; }
.thread-svg .th-diaMenor { stroke: var(--ink-soft); stroke-width: .8; stroke-dasharray: 3 3; }
.thread-svg .th-saida { stroke: var(--accent); stroke-width: 2.2; fill: none; }
/* camadas do DETALHE DO PERFIL. Derivadas de token de tema — cor fixa aqui
   inverteria de legibilidade entre claro e escuro (ver a regra do .toast). */
.thread-svg .th-triangulo { stroke: var(--muted); stroke-width: .6; stroke-dasharray: 5 2 1 2; fill: none; }
.thread-svg .th-zona { fill: var(--accent); fill-opacity: .15; stroke: none; }
.thread-svg .th-zonatxt { font-family: var(--mono); font-size: 10.5px; fill: var(--accent-d); }
.thread-svg .th-raio { stroke: var(--accent-d); stroke-width: 1.8; }
.thread-svg .th-tangente { fill: var(--accent-d); }
.thread-svg .th-chamada { stroke: var(--muted); stroke-width: .6; }
.thread-svg .th-quebra { stroke: var(--ink-soft); stroke-width: 1.1; fill: none; }
.thread-svg .th-ref { font-family: var(--mono); font-size: 11px; fill: var(--ink-soft); }
/* CORTE hachurado: no detalhe do perfil a peça está seccionada, e é assim que o
   desenho técnico representa material cortado. A hachura é um <pattern> nos
   <defs> de cada SVG — mesmo padrão dos <defs> do o'ring e do Anéis-Guia. */
.thread-svg .th-secao { fill: url(#thHach); stroke: var(--ink); stroke-width: 1.4; }
/* VISTA 3D. Sem z-buffer e sem biblioteca: o volume vem da ordem de pintura das
   fitas de flanco, e a leitura depende delas terem contorno próprio — sem o
   stroke, a hélice vira um borrão de polígonos colados. */
/* SÓLIDO. A casca opaca fecha o corpo (sem ela o fundo aparecia entre as faces
   e virava vitral); as faces por cima levam fill-opacity variável, calculada
   por orientação — é o sombreamento. Cor vem de token, nunca fixa. */
.thread-svg .th-solido3d { fill: var(--steel-bg, var(--surface)); stroke: none; }
.thread-svg .th-topo3d { fill: var(--accent-d); fill-opacity: .55; stroke: var(--ink); stroke-width: 1; }
.thread-svg .th-nucleo3d { fill: var(--accent-d); stroke: none; }
.thread-svg .th-flanco3d { fill: var(--accent); stroke: var(--accent-d); stroke-width: .3; }
.thread-svg .th-crista3d { stroke: var(--accent-d); stroke-width: 1.5; fill: none; }
.thread-svg .th-raiz3d { stroke: var(--muted); stroke-width: .8; fill: none; }
.thread-svg .th-boca3d { stroke: var(--ink); stroke-width: 1.2; fill: none; }
/* controles da vista 3D */
.th-workspace-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-top: 28px; }
.th-workspace-head h3 { margin: 0 0 12px; }
.th-view-tools { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding-bottom: 12px; }
.th-view-tools .btn { min-height: 42px; }
.th-view-tools label { display: flex; gap: 8px; align-items: center; min-height: 42px; }
.th-viewer { height: clamp(300px, 46vw, 520px); width: 100%; overflow: hidden; border: 1px solid var(--line); border-radius: 12px; background: #f4f7f9; }
.th-canvas { display: block; width: 100%; height: 100%; touch-action: none; cursor: grab; }
.th-canvas:active { cursor: grabbing; }
.th-canvas:focus-visible { outline: 3px solid var(--accent); outline-offset: -4px; }
.th-view-help { display: block; margin: 10px 0 6px; }
#thRunoutLengthField[hidden] { display: none; }
#cyThreadHead [hidden], #cyThreadBody [hidden] { display: none; }
#thDraw { overflow-x: auto; }
#thDraw .thread-svg { min-width: 660px; max-height: 660px; }
#thDrawRunout { overflow-x: auto; }
#thDrawRunout .thread-svg { min-width: 660px; }
.thread-svg .th-contorno { stroke: var(--ink); stroke-width: 1.3; fill: none; }
@media (max-width: 560px) { .th-view-tools { gap: 6px; } .th-view-tools .btn { padding: 8px 10px; } }
.th-3d-ctl { display: grid; grid-template-columns: auto 1fr auto 1fr; gap: 8px 12px;
  align-items: center; margin: 16px 0 0; }
.th-3d-ctl label { font-size: 11.5px; color: var(--muted); letter-spacing: .04em; white-space: nowrap; }
.th-3d-ctl output { font-family: var(--mono); color: var(--ink); }
.th-3d-ctl input[type=range] { width: 100%; accent-color: var(--accent); min-width: 0; }
@media (max-width: 560px) { .th-3d-ctl { grid-template-columns: auto 1fr; } }
/* halo atrás do texto de cota: sem ele, rótulo sobre a hachura fica ilegível.
   Mesma técnica do .gd-callout-label do Anéis-Guia — o "corte" é a cor do
   fundo do card (--surface), não uma cor fixa (ver a regra do .toast). */
.thread-svg .th-cotatxt, .thread-svg .th-texto, .thread-svg .th-ref,
.thread-svg .th-zonatxt { paint-order: stroke; stroke: var(--surface-2); stroke-width: 3.5px; stroke-linejoin: round; }
.thread-svg .th-hachura { stroke: var(--muted); stroke-width: .55; }
.thread-svg .th-cota { stroke: var(--muted); stroke-width: .7; }
.thread-svg .th-seta { fill: var(--muted); }
/* o SVG é reduzido pelo max-height, então a fonte precisa nascer maior pra
   continuar legível depois da escala */
.thread-svg .th-cotatxt, .thread-svg .th-texto { font-family: var(--mono); font-size: 15px; fill: var(--ink-soft); }
.thread-svg .th-titulo { font-family: var(--mono); font-size: 17px; font-weight: 700; fill: var(--accent-d); }

/* tabela dimensional — rola sozinha em tela estreita, a PÁGINA nunca rola na horizontal */
.thread-tablewrap { overflow-x: auto; }
.thread-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.thread-table th, .thread-table td { border-bottom: 1px solid var(--line); padding: 7px 8px; text-align: center; vertical-align: top; }
.thread-table th { color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: .04em; font-weight: 600; }
.thread-table td.l { text-align: left; }
.thread-table .th-sym, .thread-table .th-val { font-family: var(--mono); }
.thread-table .th-val { font-weight: 600; }
.thread-table .th-eq { font-family: var(--mono); font-size: 11px; color: var(--muted); }
.thread-table .th-src { font-size: 10.5px; color: var(--muted); }
.th-badge { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: .05em;
  padding: 2px 6px; border-radius: 5px; border: 1px solid var(--line-2); color: var(--muted); white-space: nowrap; }
.th-b-in { color: var(--ink-soft); }
.th-b-calc { color: var(--accent-d); border-color: var(--accent-line); background: var(--accent-bg); }
.th-b-norm { color: var(--ok); border-color: var(--ok); background: var(--ok-bg); }
.th-b-est { color: var(--danger); border-color: var(--danger); background: var(--danger-bg); }

/* impresso: o SVG tem de sair legível em papel branco (mesmo motivo já
   documentado para o desenho do o'ring) */
.report-paper .thread-svg { background: #fff; border: 1px solid #ccc; }
.report-paper .thread-svg .th-material { stroke: #222; }
.report-paper .thread-svg .th-corpo { fill: #f2f2f2; stroke: #222; }
.report-paper .thread-svg .th-perfil, .report-paper .thread-svg .th-saida { stroke: #c0392b; }
.report-paper .thread-svg .th-quebra { stroke: #444; }
.report-paper .thread-svg .th-eixo, .report-paper .thread-svg .th-diaFlanco,
.report-paper .thread-svg .th-cota { stroke: #777; }
.report-paper .thread-svg .th-diaMaior, .report-paper .thread-svg .th-diaMenor { stroke: #444; }
.report-paper .thread-svg .th-triangulo, .report-paper .thread-svg .th-chamada { stroke: #999; }
.report-paper .thread-svg .th-zona { fill: #c0392b; fill-opacity: .13; }
.report-paper .thread-svg .th-zonatxt, .report-paper .thread-svg .th-ref { fill: #444; }
.report-paper .thread-svg .th-raio { stroke: #c0392b; }
.report-paper .thread-svg .th-tangente { fill: #c0392b; }
.report-paper .thread-svg .th-secao { stroke: #222; }
.report-paper .thread-svg .th-hachura { stroke: #999; }
.report-paper .thread-svg .th-solido3d { fill: #e9e4df; }
.report-paper .thread-svg .th-topo3d { fill: #c0392b; stroke: #222; }
.report-paper .thread-svg .th-nucleo3d { fill: #c0392b; }
.report-paper .thread-svg .th-flanco3d { fill: #c0392b; stroke: #c0392b; }
.report-paper .thread-svg .th-crista3d { stroke: #c0392b; }
.report-paper .thread-svg .th-raiz3d { stroke: #999; }
.report-paper .thread-svg .th-boca3d { stroke: #222; }
.report-paper .th-3d-ctl { display: none; }
.report-paper .thread-svg .th-cotatxt, .report-paper .thread-svg .th-texto,
.report-paper .thread-svg .th-ref, .report-paper .thread-svg .th-zonatxt { stroke: #fff; }
.report-paper .thread-svg .th-seta { fill: #777; }
.report-paper .thread-svg .th-cotatxt, .report-paper .thread-svg .th-texto,
.report-paper .thread-svg .th-titulo { fill: #222; }

@media (max-width: 560px) {
  .th-desig { font-size: 19px; }
  .th-kvs { grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); }
}

#thReliefFields .form-grid, #thProjectFields .form-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:12px; }
