/* A casca da plataforma. Reusa os tokens de /static/style.css — um segundo
   visual para a mesma empresa seria o pior resultado possível.

   Regras de CLAUDE.md §3/§4 aplicadas aqui:
   - nenhuma largura fixa de layout: `auto-fit`/`minmax` + `min(100%, …)`;
   - `dvh` (não `vh`): a barra do navegador no celular muda a altura viva;
   - `:hover` só dentro de `@media (hover:hover)` — em toque ele fica grudado;
   - alvo ≥44px sob `pointer:coarse`;
   - `env(safe-area-inset-*)` no padding do corpo. */

body { padding: 0 env(safe-area-inset-right) env(safe-area-inset-bottom)
               env(safe-area-inset-left); }

/* ------------------------------------------------------------------ login */
.sh-centro { min-height: 100dvh; display: grid; place-items: center; padding: 20px; }
.sh-login { width: min(100%, 380px); text-align: center; }
.sh-logo { width: clamp(48px, 12vw, 72px); height: auto; margin-bottom: 10px; }
.sh-h1 { margin: 0; font-size: clamp(22px, 5vw, 28px); font-weight: 600; letter-spacing: -.02em; }
.sh-sub { margin: 2px 0 18px; color: var(--ink-500); }
/* Espresso (02/10/2026): rótulo sans cinza em caixa normal; campo PREENCHIDO,
   sem contorno, e no foco branco com anel NEUTRO — o anel vermelho competia
   com o "Login inválido" logo abaixo, que é o vermelho que significa algo. */
.sh-login label { display: block; text-align: left; font-size: var(--t-sm);
  font-weight: 500; color: var(--ink-500); margin: 12px 0 4px; }
.sh-login input { width: 100%; box-sizing: border-box; font-size: var(--t-base);
  padding: 8px 10px; min-height: 40px;
  border: 1px solid transparent; border-radius: var(--r-xs);
  background: var(--ink-100); color: var(--ink-800); }
.sh-login input:focus { outline: none; background: var(--surface);
  border-color: var(--ink-300); box-shadow: 0 0 0 3px var(--ink-100); }

/* 🔴 VER A SENHA QUE SE ESTA DIGITANDO. Pedido do Juan em 03/09/2026,
   depois de a Fernanda ficar sem conseguir entrar: MEDIDO, a senha
   guardada dela era `MUDAR@1234` — a inicial digitada com Caps Lock por
   quem cadastrou — e ela tentava `Mudar@1234`. Um campo mascarado nao
   deixa ninguem ver a diferenca, nem quem cadastra nem quem entra.
   Medido no mesmo dia: espaco no fim tambem e' aceito e tambem e'
   invisivel. O olho e' o que torna os dois visiveis.

   O botao fica DENTRO do campo, e o `padding-right` do input abre o lugar
   dele — sem isso o texto passa por baixo do icone justamente quando a
   senha e' longa, que e' quando se quer olhar. */
.sh-senha { position: relative; }
.sh-senha input { padding-right: 52px; }
.sh-olho { position: absolute; right: 4px; bottom: 4px; top: 4px;
  width: 44px; display: grid; place-items: center; padding: 0;
  background: none; border: 0; border-radius: var(--r-sm);
  color: var(--ink-500); cursor: pointer; }
.sh-olho svg { width: 22px; height: 22px; fill: none;
  stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.sh-olho:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--ink-100); }
/* o corte do olho aparece so' quando a senha esta VISIVEL — o icone diz o
   que vai acontecer se apertar, nao o estado atual */
.sh-olho .sh-olho-corte { display: none; }
.sh-olho[aria-pressed="true"] .sh-olho-corte { display: inline; }
@media (hover: hover) {
  /* `--surface-2` nem sempre existe; o fallback é o mesmo de `.pnl-dens`
     em `style.css`, para o hover não ficar transparente. */
  .sh-olho:hover { color: var(--ink-800);
    background: var(--surface-2, var(--divider)); }
}
@media (pointer: coarse) {
  .sh-olho { width: 48px; }
  .sh-senha input { padding-right: 56px; }
}
.sh-err { color: var(--alarme-txt); font-weight: 600; margin: 10px 0 0; }
.sh-entrar { width: 100%; margin-top: 16px; }
.sh-pin { width: 100%; margin-top: 8px; }

/* Entrada pela Microsoft. É um <a> (navegação para o Entra, não fetch), e os
   estilos de botão do style.css são todos `button.xxx` — então a aparência é
   remontada aqui. `flex` porque um <a> não honra `min-height` sem isso.
   Espresso: o mesmo botão branco com filete do resto do Liga, 40 px. */
a.sh-ms {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  min-height: 40px; font-size: var(--t-base); font-weight: 500;
  text-decoration: none; text-align: center;
  border: 1px solid var(--divider); border-radius: var(--r-xs);
  padding: 0 var(--s-4); box-sizing: border-box;
  background: var(--surface); color: var(--ink-800);
  transition: transform .2s cubic-bezier(.2,.7,.3,1), background .2s, box-shadow .2s;
  -webkit-tap-highlight-color: transparent;   /* o retângulo cinza do Android */
  touch-action: manipulation;                 /* mata o atraso de 300 ms */
}
.sh-ms-logo { width: 21px; height: 21px; flex: 0 0 21px; }
/* 🔴 :hover SÓ onde há ponteiro. Em tela de toque ele fica GRUDADO e o
   operador não sabe se apertou (CLAUDE.md §3). */
@media (hover: hover) {
  a.sh-ms:hover { background: var(--ink-50); }
}
/* Retorno visual ao toque em menos de 100 ms, que é o que o §4 exige. */
a.sh-ms:active { transform: scale(.98); }
a.sh-ms:focus-visible { outline: none; border-color: var(--ink-300);
  box-shadow: 0 0 0 3px var(--ink-100); }

.sh-ou {
  margin: 14px 0 2px; text-align: center;
  color: var(--ink-500); font-size: var(--t-base);
}

/* ------------------------------------------------------------------- topo */
.sh-topo { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px clamp(12px, 3vw, 24px); background: var(--surface);
  border-bottom: 1px solid var(--divider); position: sticky; top: 0; z-index: 5; }
.sh-logo-mini { width: 28px; height: auto; }
/* 🔴 A MARCA DO TOPO É O CAMINHO DE VOLTA, e no celular é o ÚNICO: o trilho vira
   gaveta e sai da tela, e `trilho.css` só devolve este `.brand` porque ela
   passou a ser a saída. Com 28×22 px medidos num telefone de 390 px, era alvo
   de mira, não de dedo com luva — §4 pede ≥44 px sob `pointer: coarse`.

   ⚠ Escopo `.sh-topo >` de propósito: o SCADA tem a marca dele em
   `#topbar .brand` (faixa A) e esta regra não pode alcançá-la. */
.sh-topo > .brand { display: flex; align-items: center; justify-content: center;
  border-radius: 10px; }
@media (pointer: coarse) {
  .sh-topo > .brand { min-width: 44px; min-height: 44px; }
}
.sh-topo-txt { font-size: var(--t-lg); }
/* EMBRULHA — e isto é a trava de §3 do cabeçalho inteiro (28/08/2026).
   Enquanto esta faixa foi UMA linha indivisível, cada ação de texto nova
   empurrava o resto para FORA da tela, e o primeiro a sair era o
   "← Módulos", a única saída daquela tela. Medido em 390px sobre e795438:
   `/flow` com 678px de `scrollWidth` e `/flow/precos` com 472, os dois com o
   TÍTULO da tela espremido a 0px. E não era defeito só de telefone: o `/flow`
   só parava de estourar acima de ~646px de viewport.
   🔴 ÍCONE NO LUGAR DO TEXTO NÃO RESOLVE, e isso é medido, não opinião: com
   TODAS as ações do `/flow` em 44×44 o cabeçalho ainda dava 428px, porque em
   390px o espaço útil da faixa é 318. O que resolve é ela poder cair para a
   linha de baixo — e, com wrap, ação nova NÃO CONSEGUE mais estourar, que é o
   motivo de a trava viver aqui e não numa contagem de botões por tela.
   `justify-content: flex-end` mantém tudo colado à direita quando sobra linha;
   `row-gap` menor que o `gap` porque fileira empilhada em cabeçalho sticky
   custa altura de primeira dobra, que no celular é o recurso caro. */
.sh-topo-dir { margin-left: auto; display: flex; align-items: center;
  gap: 10px; row-gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.sh-dim { color: var(--ink-500); font-size: var(--t-sm); }

/* `.ghost` no style.css é seletor de <button> — num <a> ele não pega e o link
   fica texto solto no meio da barra (medido no botão "Chamado Técnico",
   28/08/2026). Mesma pílula de `.sq-botao`/`.fl-botao` de cada módulo, só que
   aqui de uma vez para a casca e para quem carrega só `shell.css`. */
/* `white-space: nowrap` (29/08/2026): com 3 pílulas no cabeçalho (Sobre +
   Chamado Técnico + ← Módulos, desde que a página Sobre existe) o texto de
   CADA botão quebrava em duas linhas num celular de 375px — `.sh-topo-dir`
   agora quebra o GRUPO (flex-wrap), então o botão que não coube desce
   inteiro para a linha de baixo, em vez de espremer a palavra dentro dele. */
.sh-botao { text-decoration: none; display: inline-flex; align-items: center;
  font-weight: 700; font-size: var(--t-base); padding: 9px 16px; white-space: nowrap;
  border-radius: var(--pill); border: 1.5px solid rgba(35,31,32,.12);
  background: var(--surface); color: var(--ink-800); box-shadow: var(--shadow-sm); }
@media (hover: hover) and (pointer: fine) {
  .sh-botao:hover { border-color: var(--red-500); color: var(--red-500); }
}
.sh-botao:focus-visible { outline: 2px solid var(--red-500); outline-offset: 2px; }
@media (pointer: coarse) { .sh-botao { min-height: 44px; } }

/* ENGRENAGEM DO SISTEMA (13/09/2026) — configuração de IA, só para o admin.
   Quadrada e sem texto porque ela é UM glifo ao lado de dois botões de palavra:
   com o padding de `.sh-botao` ela ficaria larga como "Sobre" e desequilibraria
   a faixa em 375 px, que é onde `.sh-topo-dir` já embrulha (o motivo está
   escrito logo acima).
   ⚠ Nasce `hidden` no HTML (`web/topo.py`) e quem a revela é
   `shell/notificacoes.js`, ao ver `papel === "admin"`. O `hidden` vira
   `display:none !important` por `style.css`, então nenhuma regra daqui a
   acende sem querer. */
.sh-engrenagem { justify-content: center; padding: 9px 12px;
  font-size: var(--t-lg); line-height: 1; }
@media (pointer: coarse) { .sh-engrenagem { min-width: 44px; } }

/* SINO DE NOTIFICAÇÃO (27/08/2026, pedido do usuário): sugestões de
   prioridade do PCP aguardando a aprovação de QUEM está logado — visível em
   QUALQUER tela do Liga, não só na Fila, porque quem aprova pode estar em
   outro módulo quando a sugestão chega. Widget PRÓPRIO (`notificacoes.js`),
   ao lado do "quem" em todo `sh-topo-dir` — ver cada módulo.
   SEMPRE visível (pedido do usuário, 27/08/2026) — não só pra quem tem
   sugestão pendente ou pra quem decide (Comercial/Produção): é peça FIXA da
   casca, como o botão "← Módulos", não um elemento que aparece/some. Quem
   não tem nada pendente abre e vê "Nenhuma sugestão esperando sua
   aprovação" — só o número da pílula (`.sh-sino-badge`) some quando é zero.
   NÃO usa a classe `.sh-quem`: essa some em tela estreita (<420px, acima) —
   o sino é ACIONÁVEL, o nome é só identidade, pesos diferentes. */
.sh-sino-wrap { position: relative; display: flex; align-items: center; }
.sh-sino-botao { position: relative; background: transparent; border: none;
  box-shadow: none; padding: 8px; border-radius: var(--r-xs);
  line-height: 1; cursor: pointer; color: var(--ink-600); font-weight: 500; }
@media (hover: hover) { .sh-sino-botao:hover { background: var(--divider-soft); } }
@media (pointer: coarse) { .sh-sino-botao { min-width: 44px; min-height: 44px; } }
/* Traço, não emoji — MESMA linguagem dos glifos de módulo do canvas
   "Design System Sapucaia" (ver `<defs>` em shell/index.html: contorno,
   sem preenchimento, ponta quadrada, junção em meia-esquadria). A diferença
   é a cor: os glifos de módulo são brancos fixos porque vivem sobre um
   disco escuro; o sino vive direto no topo da página, então usa
   `currentColor` — acompanha `--ink-600` acima e o tema claro/escuro. */
.sh-sino-icone { width: 20px; height: 20px; display: block;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: square; stroke-linejoin: miter; }
.sh-sino-badge { position: absolute; top: 0; right: 0;
  background: var(--red-500); color: #fff; font-family: var(--font-mono);
  font-size: var(--t-2xs); font-weight: 700; line-height: 1; padding: 2px 4px;
  border-radius: var(--pill); min-width: 15px; text-align: center; }
/* `position: fixed` + left/top calculados em JS (`posicionar()` em
   notificacoes.js), não `absolute` ancorado no wrap: o sino fica perto do
   NOME (pedido do usuário), não na quina direita da tela — ancorar a caixa
   no próprio wrap (ícone pequeno) a jogava pra fora da viewport à esquerda
   em telas estreitas. `right`/`top` abaixo são só o valor INICIAL antes do
   primeiro cálculo (evita a caixa "pular" de 0,0 caso algo a mostre cedo). */
.sh-sino-caixa { position: fixed; top: 56px; right: 12px;
  width: min(340px, calc(100vw - 16px)); max-height: min(420px, 70dvh);
  overflow-y: auto; background: var(--surface); border: 1px solid var(--divider);
  border-radius: var(--r-lg); box-shadow: var(--shadow-md); z-index: 20;
  padding: 6px; }
/* A caixa do SINO cresce (27/09/2026, pedido do Juan: *"aumentar o tamanho
   da janela para melhorar a leitura"*): 480 px e 75% da altura, com o
   cabeçalho parado e só a lista rolando. A das Novidades fica como estava. */
#sh-sino-caixa { width: min(480px, calc(100vw - 16px)); max-height: 75dvh;
  padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.sh-sino-item { display: flex; flex-direction: column; gap: 2px;
  padding: 9px 10px; border-radius: var(--r-md); text-decoration: none;
  color: inherit; }
@media (hover: hover) { .sh-sino-item:hover { background: var(--divider-soft); } }
.sh-sino-item + .sh-sino-item { border-top: 1px solid var(--divider-soft); margin-top: 2px; }
.sh-sino-item-topo { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.sh-sino-item-topo b { font-size: var(--t-sm); font-weight: 600; }
.sh-sino-item-cliente { font-size: var(--t-sm); font-weight: 600; }
.sh-sino-item-motivo { font-size: var(--t-xs); color: var(--ink-500); font-style: italic; }
.sh-sino-vazio { color: var(--ink-500); font-size: var(--t-sm); padding: 14px 10px; margin: 0; }
/* a busca e o "Ver tudo" da caixa de Novidades (12/10/2026) */
.sh-novid-busca { width: 100%; margin: 0 0 4px; }
.sh-novid-tudo { display: block; padding: 8px 10px 4px; font-size: var(--t-sm);
  border-top: 1px solid var(--divider-soft); margin-top: 4px;
  color: var(--ink-900); font-weight: 500; text-decoration: none; }
@media (hover: hover) { .sh-novid-tudo:hover { text-decoration: underline; } }

/* ── os AVISOS do sino (27/09/2026) ──────────────────────────────────────────
   Um item = ponto de não-visto · origem e hora · título · texto · quem, e à
   direita o Ciente (ou "visto 27/09 14:32"). O visto não some: fica
   esmaecido na aba "Todos" — é ele que responde "o que eu já vi". */
.sh-av-cab { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  padding: 10px 12px; border-bottom: 1px solid var(--divider); }
.sh-av-cab > b { font-size: var(--t-base); font-weight: 600; margin-right: auto; }
.sh-av-abas { display: inline-flex; padding: 2px; gap: 2px; background: var(--ink-50);
  border-radius: var(--r-xs); }
.sh-av-abas button { appearance: none; border: 0; background: transparent; cursor: pointer;
  font: inherit; font-size: var(--t-xs); font-weight: 500; color: var(--ink-500);
  padding: 4px 8px; border-radius: 4px; box-shadow: none; }
.sh-av-abas button.on { background: var(--surface); color: var(--ink-800);
  box-shadow: 0 0 0 1px var(--divider); }
.sh-av-abas span { font-variant-numeric: tabular-nums; margin-left: 2px; }
.sh-av-todos { appearance: none; border: 0; background: transparent; cursor: pointer;
  font: inherit; font-size: var(--t-xs); color: var(--ink-600); padding: 4px 6px;
  border-radius: 4px; box-shadow: none; }
.sh-av-lista { overflow-y: auto; min-height: 0; padding: 4px; }
.sh-av { display: grid; grid-template-columns: 10px 1fr auto; gap: 8px;
  align-items: start; padding: 10px 8px; border-radius: var(--r-md); }
.sh-av + .sh-av { border-top: 1px solid var(--divider-soft); }
/* o ponto é o que "não visto" quer dizer, e é o único vermelho da caixa */
.sh-av-ponto { width: 8px; height: 8px; margin-top: 6px; border-radius: 50%;
  background: var(--red-500); }
.sh-av--visto .sh-av-ponto { background: transparent; }
.sh-av--visto .sh-av-corpo { color: var(--ink-500); }
.sh-av--visto .sh-av-titulo { font-weight: 500; }
.sh-av-corpo { display: flex; flex-direction: column; gap: 2px; min-width: 0;
  color: var(--ink-800); text-decoration: none; }
.sh-av-linha1 { display: flex; gap: 8px; align-items: baseline; font-size: var(--t-xs);
  color: var(--ink-500); }
.sh-av-origem { font-weight: 500; color: var(--ink-600); }
.sh-av-linha1 time { font-variant-numeric: tabular-nums; }
.sh-av-titulo { font-size: var(--t-sm); font-weight: 600; overflow-wrap: anywhere; }
.sh-av-texto { font-size: var(--t-sm); line-height: 1.4; overflow-wrap: anywhere; }
.sh-av-meta { font-size: var(--t-xs); color: var(--ink-500); overflow-wrap: anywhere; }
.sh-av-ciente { appearance: none; cursor: pointer; font: inherit; font-size: var(--t-xs);
  font-weight: 500; color: var(--ink-800); background: var(--surface);
  border: 1px solid var(--divider); border-radius: var(--r-xs); padding: 4px 10px;
  min-height: 28px; box-shadow: none; }
.sh-av-estado { font-size: var(--t-xs); color: var(--ink-500); white-space: nowrap; padding-top: 2px; }
@media (hover: hover) and (pointer: fine) {
  .sh-av:hover { background: var(--ink-50); }
  .sh-av-ciente:hover, .sh-av-todos:hover { background: var(--ink-50); }
}
@media (pointer: coarse) { .sh-av-ciente { min-height: 36px; } }

/* ---------------------------------------------------------------- lançador */
/* Alinhado ao canvas "Design System Sapucaia" (26/08/2026) em 27/08. Três coisas
   mudaram, e cada uma tem motivo escrito na própria maquete:

   1. A GRADE OCUPA A LARGURA. Tinha `max-width:1200px; margin:0 auto` — a ilha
      de cartões no meio de 1600px de cinza que a maquete chama de "assinatura do
      protótipo". E com 11 módulos o cap custa uma coluna inteira.
   2. CARTÃO POR SOMBRA, não por borda, raio do canvas (os tokens `--r-*` do
      style.css foram alinhados a 14/18/24). A borda sai AQUI e não lá: no
      style.css ela separa tiles na tela do operador, e em alto contraste a
      sombra desaparece.
   3. DISCO COM GLIFO. Onze cartões de texto puro não se varrem com o olho.

   ⚠ O que a maquete tem e NÃO entrou, de propósito: a linha de telemetria por
   módulo, o "pulso" da planta e o sino de alarmes — cada número precisa de
   fonte medida, e a tela inicial não pode disparar cinco consultas ao espelho do
   ERP a cada login. Quando houver medição entra como bloco opcional no
   `GET /api/plataforma/modulos`, que já existe: UM endpoint. E a barra de
   progresso do módulo em construção não entrou porque o número não existe —
   progresso inventado é pior que progresso ausente (CLAUDE.md §2 e §3). */

.sh-abertura { padding: clamp(14px, 3vw, 26px) clamp(12px, 3vw, 24px) 0; }
.sh-ola { margin: 0; font-size: clamp(21px, 3.4vw, 30px); font-weight: 600;
  letter-spacing: -.035em; line-height: 1.1; color: var(--ink-500); }
.sh-ola b { color: var(--ink-800); font-weight: 600; }

/* A BUSCA DE TODO O LIGA (18/10/2026). Campo PREENCHIDO e sem borda, como
   todo campo do Espresso; mais alto que o de formulário (40 px) porque é a
   porta da tela, mas sem virar pílula. A lista de resultados é a do trilho
   (`.tr-achados`, em `trilho.css`), aqui flutuando sob o campo.
   CENTRADA na largura da tela desde 19/10/2026 (pedido do Juan), como a
   barra do Google: é a porta da tela, não mais um bloco da coluna. */
.sh-busca { position: relative; display: flex; align-items: center;
  margin: clamp(12px, 2vw, 18px) auto 0;
  width: min(100% - 2 * clamp(12px, 3vw, 24px), 44rem); }
.sh-busca-ic { position: absolute; left: 12px; width: 18px; height: 18px; fill: none;
  stroke: var(--ink-500); stroke-width: 1.7; stroke-linecap: round; pointer-events: none; }
.sh-busca input { width: 100%; min-height: 40px; padding: 8px 64px 8px 38px;
  border: 1px solid transparent; border-radius: var(--r-xs); background: var(--ink-100);
  color: var(--ink-800); font: inherit; font-size: var(--t-base); }
.sh-busca input:focus { outline: none; background: var(--surface);
  border-color: var(--ink-300); box-shadow: 0 0 0 3px var(--ink-100); }
.sh-busca-kbd { position: absolute; right: 10px; font-family: var(--font-mono);
  font-size: var(--t-2xs); color: var(--ink-500); pointer-events: none; }
.sh-busca .sh-busca-saida { position: absolute; z-index: 30; top: calc(100% + 6px); left: 0; right: 0;
  margin: 0; padding: 6px; background: var(--surface); border: 1px solid var(--divider);
  border-radius: var(--r-sm); box-shadow: var(--shadow-md); max-height: min(30rem, 65dvh); }
/* no toque não há teclado físico: o atalho é ruído */
@media (pointer: coarse) { .sh-busca-kbd { display: none; } .sh-busca input { padding-right: 12px; } }

/* Régua com contagem: separa "seus módulos" de "em construção" sem gastar um
   card de título. A contagem é o único número real que a tela tem. */
.sh-faixa-rot { display: flex; align-items: baseline; gap: 14px;
  padding: clamp(14px, 3vw, 22px) clamp(12px, 3vw, 24px) 0; }
.sh-rotulo { font-size: var(--t-xs); font-weight: 500; color: var(--ink-500);
  white-space: nowrap; }
.sh-regua { flex: 1; height: 1px; background: var(--divider); }
.sh-conta { font-size: var(--t-xs); color: var(--ink-500); white-space: nowrap; }

/* `minmax(min(100%, 340px), 1fr)`: o `min(100%, …)` é a trava contra estouro
   horizontal em tela estreita — sem ele a coluna força scroll lateral, que é
   proibido no corpo da página. */
.sh-grade { display: grid; gap: clamp(10px, 2vw, 16px);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr));
  padding: clamp(10px, 2vw, 16px) clamp(12px, 3vw, 24px); }

.sh-mod { position: relative; display: flex; flex-direction: column; gap: 14px;
  text-align: left; text-decoration: none; color: inherit;
  padding: 16px; border-radius: var(--r-sm); background: var(--surface);
  border: 1px solid var(--divider); box-shadow: none; min-height: 132px; font: inherit;
  cursor: pointer; }
.sh-mod-topo { display: flex; align-items: flex-start; gap: 13px; min-width: 0; }
.sh-disco { width: 42px; height: 42px; border-radius: 50%; flex: 0 0 auto;
  background: var(--ink-800); display: grid; place-items: center; }
.sh-disco svg { width: 46%; height: auto; display: block; }
.sh-disco-off { background: var(--ink-500); opacity: .7; }
.sh-mod-nome { flex: 1; min-width: 0; }
.sh-mod-nome b { display: block; font-size: var(--t-xl); font-weight: 600;
  letter-spacing: -.025em; line-height: 1.15; }
.sh-mod-nome small { display: block; margin-top: 5px; font-size: var(--t-sm);
  line-height: 1.45; color: var(--ink-500); text-wrap: pretty; }
.sh-mod .sh-nivel { margin-top: auto; font-size: var(--t-xs); font-weight: 500;
  color: var(--ink-500); }

/* EM CONSTRUÇÃO: roteiro em linhas, não pílula solta. E a descrição vem no
   CORPO, não no `title` — no tablete não existe hover, então `title` era
   informação que o operador não tinha como alcançar (CLAUDE.md §4). */
.sh-roteiro { margin: 10px clamp(12px, 3vw, 24px) clamp(16px, 3vw, 28px);
  background: var(--surface); border-radius: var(--r-sm);
  border: 1px solid var(--divider); overflow: hidden; }
.sh-rt { display: grid; grid-template-columns: 34px minmax(0, 200px) minmax(0, 1fr);
  gap: 14px; align-items: center; padding: 10px clamp(12px, 2vw, 18px);
  border-top: 1px solid var(--divider-soft); }
.sh-rt:first-child { border-top: 0; }
.sh-rt .sh-disco { width: 32px; height: 32px; }
.sh-rt-nome { font-size: var(--t-base); font-weight: 600; letter-spacing: -.01em;
  color: var(--ink-500); min-width: 0; }
.sh-rt-desc { font-size: var(--t-sm); line-height: 1.4; color: var(--ink-500);
  min-width: 0; text-wrap: pretty; }
@media (max-width: 720px) {
  .sh-rt { grid-template-columns: 34px minmax(0, 1fr); row-gap: 2px; }
  .sh-rt-desc { grid-column: 2; }
}

/* CH-2026-032: datas e aniversários do mês — apoio, não decisão (CLAUDE.md
   §3), por isso compacto: duas colunas quando cabe, uma quando não.
   ⚠ CH-2026-035 supera o "sem cor com significado" que valia aqui até então
   — pedido explícito do usuário foi justo introduzir o significado: feriado
   em vermelho para saltar aos olhos entre as demais datas do mês. */
.sh-cal { display: grid; gap: clamp(10px, 2vw, 16px);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  margin: 10px clamp(12px, 3vw, 24px) clamp(16px, 3vw, 28px); }
.sh-cal-bloco { background: var(--surface); border-radius: var(--r-sm);
  border: 1px solid var(--divider); padding: 12px clamp(12px, 2vw, 18px); }
.sh-cal-bloco b { font-size: var(--t-xs); font-weight: 600; color: var(--ink-500); }
.sh-cal-lista { list-style: none; margin: 8px 0 0; padding: 0; }
.sh-cal-lista li { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding: 5px 0; border-top: 1px solid var(--divider-soft); font-size: var(--t-base); }
.sh-cal-lista li:first-child { border-top: 0; }
.sh-cal-dia { font-family: var(--font-mono); font-weight: 600;
  color: var(--ink-500); min-width: 1.6em; text-align: right; }
.sh-cal-evento { flex: 1 1 auto; }

/* CH-2026-035: feriado de verdade (nunca ponto facultativo, que é rótulo à
   parte) pinta a linha inteira — data e nome — na cor de estado de alarme
   já usada no resto do Liga (`--alarme-txt`), não um vermelho novo. */
.sh-cal-feriado .sh-cal-dia, .sh-cal-feriado .sh-cal-evento { color: var(--alarme-txt); }

/* O selo de categoria — neutro nos três tipos sem destaque (ponto
   facultativo, Sapucaia, comemorativa); no feriado seria redundante com a
   linha já vermelha, então herda a MESMA cor em vez de um selo próprio. */
.sh-cal-selo { font-size: var(--t-xs); font-weight: 500;
  padding: 2px 7px; border-radius: var(--r-xs);
  background: var(--divider-soft); color: var(--ink-500); white-space: nowrap; }
.sh-cal-selo-feriado { background: transparent; color: var(--alarme-txt); padding: 2px 0; }

@media (hover: hover) and (pointer: fine) {
  .sh-mod:hover { border-color: var(--ink-300); text-decoration: none; color: inherit; }
}
.sh-mod:focus-visible { outline: none; border-color: var(--ink-300);
  box-shadow: 0 0 0 3px var(--ink-100); }
/* retorno visual ao toque em < 100 ms: toque sem retorno faz tocar de novo */
.sh-mod:active { transform: scale(.985); }
/* ---------------------------------------------------------------- faixa sync */
.sh-faixa { margin: clamp(12px, 3vw, 24px) clamp(12px, 3vw, 24px) 0;
  padding: 12px 14px; border-radius: var(--r-md); background: var(--aviso-bg);
  color: var(--ink-800); font-weight: 600; line-height: 1.45; }
.sh-faixa b { display: block; margin-bottom: 2px; }

/* --------------------------------------- tipografia de bloco (usada nos módulos) */
/* `.sh-h2` e `.sh-ajuda` nasceram na grade de permissão da casca, que saiu em
   27/08/2026 para o módulo `pessoas`. FICAM: os módulos de gestão importam esta
   folha e usam as duas (sgx, pcp, pessoas). O resto do bloco `.pm-*` saiu junto
   com a tela — CSS morto é defeito, não estilo (CLAUDE.md §5). */
.sh-h2 { margin: 0 0 6px; font-size: var(--t-3xl); }
.sh-ajuda { color: var(--ink-500); font-size: var(--t-sm); line-height: 1.5; margin: 0 0 12px; }
/* O alvo de 44 px "com luva" saiu em 02/10/2026 (a régua foi revogada em
   08/09): o piso de 40 px do `style.css` vale aqui como em todo lugar. */
@media (pointer: coarse) {
  .sh-mod { min-height: 128px; }
}

/* ------------------------------------------------- correções de densidade
   Medido no navegador em 1280x720 e em 375x812 (2026-08-23):

   1. Sete cartões iguais deixavam ~60% da altura vazia no desktop e empurravam
      o único módulo que ABRE para fora da primeira dobra no celular. Módulo em
      construção é MAPA, não menu: virou etiqueta, não cartão.
   2. O nível ("admin") num módulo que não abre é ruído — se não abre, o meu
      nível nele não decide nada.
   3. O header quebrava em duas linhas no celular por causa do nome do usuário. */

/* o lançador ocupa a altura útil e centra quando sobra espaço */
#v-modulos { min-height: calc(100dvh - 52px); display: flex;
  flex-direction: column; justify-content: center; }
.sh-grade { align-content: start; }
/* cartões da mesma linha com a mesma altura, sem fundo ragged */
.sh-grade > .sh-mod-caixa { display: grid; position: relative; }
.sh-mod-caixa > .sh-mod { height: 100%; }
.sh-mod-caixa .sh-mod-nome { padding-right: 36px; }
/* 23/10/2026: a estrela de favorito mora no canto do card, irmã do link (botão dentro de <a> é inválido). 40 px é o piso de alvo. */
.sh-fav { position: absolute; top: 6px; right: 6px; width: 40px; height: 40px; padding: 0;
  display: grid; place-items: center; background: transparent; border: 0; border-radius: 50%;
  color: var(--ink-300); cursor: pointer; }
.sh-fav svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linejoin: round; }
.sh-fav.on { color: var(--ink-800); }
.sh-fav.on svg { fill: currentColor; }
.sh-fav:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--ink-100); }
.sh-fav:active { transform: scale(.92); }
@media (hover: hover) {
  .sh-fav:hover { color: var(--ink-800); }
}

/* O `.sh-vem` guardava CHIPS (`.sh-vem-tit`/`.sh-vem-lista`/`.sh-chip`), que
   saíram em 27/08/2026 junto com o `title` inalcançável no toque — viraram o
   `.sh-roteiro` acima. CSS morto é defeito, não estilo (CLAUDE.md §5). */
.sh-vem { width: 100%; }

/* Painéis TV (Duilio, 4941d99): é outra SEÇÃO do lançador, não outro
   componente. `#sh-paineis` reusa `.sh-grade` e `.sh-mod` de propósito —
   mesma linguagem visual, fonte de dados diferente (lista fixa no JS, não a
   grade de permissão).
   Duas mudanças no merge de 27/08, para não haver duas linguagens na mesma
   tela: o TÍTULO passou a usar a régua `.sh-faixa-rot`/`.sh-rotulo` das outras
   faixas (o `.sh-paineis-tit` morreu com ela), e o `max-width: 1200px;
   margin: 0 auto` saiu — a grade de módulos logo acima ocupa a largura toda,
   e uma seção capada abaixo dela desalinha as duas visivelmente. */
.sh-paineis-wrap { width: 100%; }
.sh-paineis-wrap .sh-grade { padding-top: 0; }

/* Tela estreita: o nome sai porque a identidade já está na sessão — quem está
   logado descobre em Sair, e o espaço vertical do celular vale mais que a
   repetição.

   ⚠ O `.sh-topo { flex-wrap: nowrap }` que morava aqui SAIU em 28/08/2026.
   Ele prometia "o header cabe numa linha só" e entregava outra coisa: forçava
   uma linha só e deixava o excedente sair pela direita, com scroll horizontal
   no corpo — justo o que a §3 proíbe, e justo na largura em que menos cabe.
   Com `.sh-topo-dir` embrulhando (acima), a faixa cai de linha em vez de
   vazar. O `text-overflow` fica: ele é o que faz o título ENCOLHER com
   reticências em vez de empurrar as ações, e sem ele o `/flow` volta a medir
   o título em 0px. */
@media (max-width: 420px) {
  .sh-quem { display: none; }
  .sh-topo-txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* Coluna com teto, e o TETO é o ponto (medido em 23/08/2026): com UM módulo
   disponível, `1fr` esticava o cartão para ~580px e ele virava banner — largura
   de faixa para o conteúdo de um cartão. Entre 300 e 420px a caixa é sempre uma
   caixa, com 1 módulo ou com 11. Números subiram em 27/08 com o cartão do canvas
   (disco de 42px + descrição no corpo), que é mais alto que o antigo.
   ⚠ Isto NÃO é cap de layout: a GRADE ocupa a largura toda (`justify-content:
   start` distribui da esquerda), o teto é por cartão. */
.sh-grade { grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 420px));
  justify-content: start; }

/* ⚠ `margin: 0 auto` num ITEM DE FLEXBOX desliga o stretch e centraliza a caixa.
   Medido no navegador em 23/08/2026, com o botão de permissões (que saiu em
   27/08): ele aparecia no meio da tela enquanto "EM CONSTRUÇÃO" ficava à
   esquerda. A armadilha continua valendo para o próximo item que entrar aqui. */

/* A PESSOA LEVA AO "MEU PERFIL" (05/11/2026; nasceu em 28/09 só com o nome).
   Foto (ou iniciais) + nome de uso num link que não parece link. O avatar
   fica em tela estreita, onde o `.sh-quem` some (acima): é o caminho do
   celular para o perfil. Círculo de 28 px, o tamanho do ícone do sino. */
.sh-eu { display: inline-flex; align-items: center; gap: var(--s-2); color: inherit;
  text-decoration: none; min-width: 0; }
.sh-avatar { flex: none; display: inline-grid; place-items: center; width: 28px; height: 28px;
  border-radius: 50%; overflow: hidden; background: var(--ink-100); color: var(--ink-700);
  font-size: var(--t-xs); font-weight: 600; line-height: 1; }
.sh-avatar:empty { display: none; }
.sh-avatar img { width: 100%; height: 100%; object-fit: cover; }
@media (hover: hover) { .sh-eu:hover .sh-quem { text-decoration: underline; } }
