/* Componentes dos portais (sobre os tokens). Tudo herda --brand via tokens.css. */

/* ---- campos ---- */
.hs-label { display:block; font-size:var(--fs-corpo); font-weight:700; color:var(--ink-2); margin:0 0 6px; }
.hs-input, .hs-textarea, .hs-select {
  width:100%; font-family:var(--font); font-size:var(--fs-subtitulo); color:var(--ink);
  background:var(--surface); border:1.5px solid var(--line-2); border-radius:var(--r-field);
  padding:11px 14px; outline:none; transition:border-color .14s, box-shadow .14s;
}
.hs-input:focus, .hs-textarea:focus, .hs-select:focus {
  border-color:var(--primary);
  /* DS 2.0: o anel virou token (--anel-foco), mesmo valor de sempre */
  box-shadow:var(--anel-foco, 0 0 0 3px color-mix(in srgb, var(--brand) 18%, transparent));
}
.hs-textarea { min-height:96px; resize:vertical; }
/* (#139 revertido) NAO forcar appearance/chevron no .hs-select: havia chevron
   proprio em varios selects -> dava "duas setas" e quebrava o dropdown. Mantemos
   a seta NATIVA, que funciona em todas as telas (turma/presenca/rotina/etc.). */
/* #542: lista suspensa apertada contra a borda da tela. Quando ela precisa
   encolher para continuar alinhada com o campo (ver posicionar() no admin), a
   opção longa passa a quebrar linha, o inline white-space:nowrap de cada opção
   exige o !important. Sem isto sobraria uma barra de rolagem horizontal dentro
   da lista, que é justamente o que o dono vetou no sistema inteiro. */
.dd-estreita [data-v] { white-space:normal !important; line-height:1.35; }
/* #6434 - o rotulo e a seta do botao da lista suspensa (web/js/lista-suspensa.js) */
.hs-select .dd-rot { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hs-select .dd-seta { flex-shrink:0; opacity:.6; }

.hs-field { margin-bottom:16px; }
.hs-help { font-size:var(--fs-corpo-pequeno); color:var(--ink-3); margin-top:5px; }
/* #310 - a ajuda que fica logo acima de uma lista ou de um grupo de botoes (era style= solto na Cobranca) */
.hs-help.hs-help--antes-da-lista { margin-bottom:10px; }

/* ---- #4212: telefone como link de ligação (painel de saúde da Enfermaria) ----
   Nasceu no perfil de saúde da criança, onde o telefone do médico responsável
   precisa ser um toque e não uma leitura em voz alta. A cor vem de --accent-ink
   (o accent USADO COMO LETRA), nunca do --accent cru: foi o que o #4426/13-08
   mediu, e cor cravada aqui sumiria no tema escuro. O sublinhado só no hover e
   no foco de teclado, para a lista de campos não virar um muro de links. */
.hs-field--compacto { margin-bottom:10px; }
.hs-tel {
  display:inline-block; font-size:var(--fs-corpo); font-weight:700; line-height:1.55;
  color:var(--accent-ink,var(--primary)); text-decoration:none;
}
.hs-tel:hover, .hs-tel:focus-visible { text-decoration:underline; }

/* ---- checkbox do design system ----
   rev-131: usado no "responsavel financeiro" da ficha de Pessoas. Caixa pequena
   (20px), marca um TIQUE VERDE de sucesso quando ligado (nada de amarelo nem
   tamanho de avatar). Acessivel: o <input> nativo fica escondido mas presente,
   o <span class="hs-checkbox-box"> e a parte visivel. Herda var() => tema escuro
   de graca. Padrao de marcacao: <label class="hs-checkbox"><input type="checkbox">
   <span class="hs-checkbox-box"></span><span>rotulo</span></label>
   #470 (09/11): a caixa e UMA so em toda tela, de 18px (com a letra de 13px do #338 a de 20px
   parecia grande demais), e nenhuma tela muda o tamanho dela. */
.hs-checkbox { position:relative; display:inline-flex; align-items:center; gap:10px; cursor:pointer;
  user-select:none; font-size:var(--fs-corpo); color:var(--ink); }
.hs-checkbox input { position:absolute; opacity:0; width:0; height:0; }
/* #6444 e #470 - a borda da caixa vazia le --control-border (3:1 nos dois temas); sem ele (cache velho) cai no --line-2 */
.hs-checkbox-box { width:18px; height:18px; flex-shrink:0; border-radius:5px;
  border:1.5px solid var(--control-border, var(--line-2)); background:var(--surface); position:relative;
  line-height:15px; transition:border-color .14s, background .14s; }
/* #470 - a caixa ganha a linha de base do texto: no meio de uma frase ou ao lado do nome da linha, o rotulo assenta na mesma base das palavras vizinhas (sem isto a base era o pe da caixa e o texto subia) */
.hs-checkbox-box::before { content:""; display:inline-block; }
.hs-checkbox:hover .hs-checkbox-box { border-color:var(--green); }
/* o tique: dois tracos brancos desenhados com borda; some por opacidade quando off */
.hs-checkbox-box::after { content:""; position:absolute; left:5px; top:1.5px;
  width:4.5px; height:9px; border:solid #fff; border-width:0 2.2px 2.2px 0;
  transform:rotate(45deg) scale(0); opacity:0; transition:transform .16s, opacity .12s; }
.hs-checkbox input:checked + .hs-checkbox-box { background:var(--green); border-color:var(--green); }
.hs-checkbox input:checked + .hs-checkbox-box::after {
  transform:rotate(45deg) scale(1); opacity:1; animation:hs-check-pop .2s ease-out; }
.hs-checkbox input:disabled + .hs-checkbox-box { opacity:.45; cursor:not-allowed; }
/* #4644: o estado PARCIAL (indeterminate, que so o JS liga): um TRACO no
   lugar do tique. E o "marcar todos" de coluna com selecao pela metade, como
   na matriz de Perfis do console (#4386). Sem esta regra o quadradinho
   parcial parece vazio, porque o input nativo fica escondido. */
.hs-checkbox input:indeterminate + .hs-checkbox-box { background:var(--green); border-color:var(--green); }
.hs-checkbox input:indeterminate + .hs-checkbox-box::after {
  left:3px; top:6.4px; width:9px; height:0; border-width:0 0 2.2px 0;
  transform:none; opacity:1; }

/* ---- abas ---- */
.hs-tabs { display:flex; gap:4px; border-bottom:1.5px solid var(--line); flex-wrap:wrap; }
.hs-tab {
  font-family:var(--font); font-size:var(--fs-corpo); font-weight:600; color:var(--ink-2);
  background:none; border:none; cursor:pointer; padding:10px 14px;
  border-bottom:2.5px solid transparent; margin-bottom:-1.5px; transition:color .14s;
}
.hs-tab:hover { color:var(--ink); }
.hs-tab[aria-selected="true"] { color:var(--accent-ink,var(--primary)); border-bottom-color:var(--primary); }
.hs-panel { padding:22px 2px; }
.hs-panel[hidden] { display:none; }

/* ---- tabela ---- */
.hs-table { width:100%; border-collapse:collapse; font-size:var(--fs-corpo); }
.hs-table th { text-align:left; font-size:var(--fs-corpo-pequeno); text-transform:uppercase; letter-spacing:.4px;
  color:var(--ink-3); font-weight:700; padding:8px 10px; border-bottom:1.5px solid var(--line); }
.hs-table td { padding:9px 10px; border-bottom:1px solid var(--line); color:var(--ink-2); }
.hs-table td:first-child { color:var(--ink); }
/* #5779: tabela que nunca sai do cartao. O layout fixo respeita a largura de cada
   coluna de numero; a primeira coluna fica com o resto e quebra o texto longo (rota,
   endereco) em vez de empurrar as outras para fora. Sem reticencias: o texto inteiro
   continua a vista. */
.hs-table--fixa { table-layout:fixed; }
.hs-table--fixa td:first-child { overflow-wrap:anywhere; }
.hs-table--fixa .hs-col-num { width:64px; }
.hs-table--fixa .hs-col-num-curta { width:48px; }
.hs-mono { font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:var(--fs-corpo-pequeno); }

/* #5734: o botao flutuante da Ana nunca cobre a acao principal da tela. No Mensageiro
   o Enviar fica no canto de baixo a direita, exatamente onde a Ana mora: ali ela sobe
   acima da caixa de escrever, e a janela dela sobe junto. O seletor com a pagina vence
   o do bloco do console pela especificidade, em qualquer largura. */
#anaFlutBtn[data-pagina="mensagens"] { bottom:96px; }
#anaFlutJanela[data-pagina="mensagens"] { bottom:162px; max-height:min(560px, calc(100vh - 200px)); }
/* wrapper utilitario p/ tabelas largas: rola na horizontal em tela pequena
   em vez de estourar a viewport (foco ~911px). Aplicar envolvendo a .hs-table. */
.tbl-resp { overflow-x:auto; max-width:100%; -webkit-overflow-scrolling:touch; }
/* #5646: reserva a altura de uma segunda linha pequena (10,5 px) que nao existe, para
   uma linha de tabela sem porcentagem ficar da altura das que tem. Vazia de proposito:
   nao inventa numero. */
.hs-linha-reserva { font-size:var(--fs-legenda); margin-top:1px; min-height:1lh; }
/* #338: a linha da porcentagem com o mesmo tamanho da reserva (#5646); a cor vem da linha da tabela */
.hs-linha-pct { font-size:var(--fs-legenda); font-weight:700; margin-top:1px; }
.hs-linha-pct--vazia { color:var(--ink-3); font-weight:400; }

/* ---- KPI ---- */
.hs-kpis { display:grid; grid-template-columns:repeat(auto-fit,minmax(var(--piso-numero),1fr)); gap:12px; }
.hs-kpi { background:var(--surface-2); border:1px solid var(--line); border-radius:14px; padding:14px 16px; }
.hs-kpi .v { font-family:var(--font-display); font-size:var(--fs-titulo); font-weight:800; }
.hs-kpi .l { font-size:var(--fs-corpo-pequeno); color:var(--ink-3); font-weight:600; margin-top:2px; }
.hs-kpi.ok .v { color:var(--green); }
.hs-kpi.ruim .v { color:var(--rose); }
/* #6255 - o display:grid acima engolia o hidden do placar. */
.hs-kpis[hidden] { display:none; }

/* ---- toasts ---- */
/* z-index ACIMA de qualquer modal (overlay = 4000): o toast de erro precisa ser
   lido por cima do modal com blur (#111). Sem isto, o erro/codigo ficava atras. */
/* #471: os dropdowns temáticos subiram para z-9600 (p/ vencer os modais em 9000);
   os toasts precisam ficar ACIMA deles, senão o toast de erro some atrás da lista. */
#hs-toasts { position:fixed; right:18px; bottom:18px; display:flex; flex-direction:column;
  gap:8px; z-index:var(--z-toast, 9990); }
.hs-toast { background:var(--ink); color:var(--bg); font-size:var(--fs-corpo); font-weight:600;
  padding:11px 16px; border-radius:12px; box-shadow:var(--sh-2);
  animation:hs-fade-up .18s ease-out; max-width:340px; }
.hs-toast--erro { background:var(--danger-solid); color:var(--danger-solid-fg); }
.hs-toast--prog { display:flex; align-items:center; gap:10px; }

/* ---- toast de ERRO rico (#30): cartao maior com CODIGO + amigavel + erro real ---- */
.hs-toast--erro-rico { background:var(--danger-solid); color:var(--danger-solid-fg); max-width:400px;
  padding:13px 16px 14px; border-radius:14px; line-height:1.4; }
.hs-toast-cab { display:flex; align-items:center; gap:8px; margin-bottom:6px; }
.hs-toast-cod { background:rgba(255,255,255,.22); color:#fff; font-weight:800;
  font-size:var(--fs-corpo-pequeno); letter-spacing:.3px; padding:2px 9px; border-radius:999px; flex-shrink:0; }
.hs-toast-amig { font-size:var(--fs-corpo); font-weight:700; }
.hs-toast-tec { font-size:var(--fs-corpo-pequeno); font-weight:500; margin-top:7px; padding-top:7px;
  border-top:1px solid rgba(255,255,255,.22); opacity:.92; word-break:break-word; }
@media (max-width:560px) {
  #hs-toasts { left:12px; right:12px; }
  .hs-toast--erro-rico { max-width:none; }
}
.hs-spinner-sm { width:16px; height:16px; border-radius:50%; flex-shrink:0;
  border:2.5px solid color-mix(in srgb, var(--bg) 30%, transparent); border-top-color:var(--bg);
  animation:hs-spin .7s linear infinite; }
.hs-toast.saindo { opacity:0; transform:translateY(8px); transition:all .4s; }
/* #314: botão "x" para fechar o toast na hora (aviso/erro) */
.hs-toast { position:relative; padding-right:34px; }
/* #318 - 24 px de alvo (WCAG 2.2, 2.5.8) e o anel na cor do texto do aviso: o azul do foco sumia no fundo escuro e no vermelho (1,1:1) */
.hs-toast-x { position:absolute; top:4px; right:5px; width:24px; height:24px; padding:0;
  border:0; background:transparent; color:inherit; font-size:var(--fs-titulo); line-height:1;
  font-weight:700; cursor:pointer; opacity:.6; border-radius:7px; display:flex;
  align-items:center; justify-content:center; }
.hs-toast-x:hover { opacity:1; background:rgba(255,255,255,.18); }
.hs-toast-x:focus-visible { opacity:1; outline-color:currentColor !important; }
/* #318 - o campo da busca do topo (Pessoas) ocupa a altura da caixa: o alvo era 18 px dentro de uma caixa de 36 */
.busca-topo input { align-self:stretch; }

/* ---- #3794: microanimações dos toasts ------------------------------------ */
/* Confetes verdes DELICADOS no sucesso: 10 pontinhos que voam ~40px e somem.
   Cada um recebe --dx/--dy/--gira via JS (ui.js). aria-hidden; puro enfeite. */
.hs-confete-ninho { position:absolute; left:-4px; top:50%; width:0; height:0; pointer-events:none; }
.hs-confete { position:absolute; width:5px; height:8px; border-radius:1.5px;
  background:var(--green, #22a06b); opacity:0;
  animation:hs-confete-voa .75s ease-out forwards; }
.hs-confete:nth-child(2n) { background:color-mix(in srgb, var(--green, #22a06b) 60%, #fff); width:4px; height:6px; }
.hs-confete:nth-child(3n) { border-radius:50%; width:5px; height:5px; }
@keyframes hs-confete-voa {
  0%   { opacity:0; transform:translate(0,0) rotate(0); }
  12%  { opacity:1; }
  100% { opacity:0; transform:translate(var(--dx,20px), var(--dy,-20px)) rotate(var(--gira,90deg)); }
}
/* (#3702, 27/07) O unicórnio do 404 no toast de ERRO foi REMOVIDO a pedido do
   dono ("esse unicórnio no toasted não era nada disso"). Os confetes do sucesso
   ficam, esses ele aprovou, e o toast de erro rico segue intacto. */
@media (prefers-reduced-motion: reduce) {
  .hs-confete { animation:none; }
}

/* #3794: o ícone temático do feriado no calendário "dança" de leve (o Papai Noel
   do dia 25/12). Balanço sutil de 3s; some para quem pediu menos movimento. */
.cal-ico-feriado { transform-origin:50% 90%; animation:cal-feriado-danca 3s ease-in-out infinite; }
@keyframes cal-feriado-danca {
  0%, 100% { transform:rotate(0) translateY(0); }
  25%      { transform:rotate(-5deg) translateY(-1px); }
  50%      { transform:rotate(0) translateY(0); }
  75%      { transform:rotate(5deg) translateY(-1px); }
}
@media (prefers-reduced-motion: reduce) { .cal-ico-feriado { animation:none; } }

/* ---- overlay central de upload (foto/arquivo): evidente, acima de qualquer modal ---- */
/* opacity ESTÁTICA (1): sem depender de animação tocar, o overlay aparece sempre.
   A entrada é só um "pop" de TRANSFORM (cosmético; se não rodar, segue visível). */
.hs-up-overlay { position:fixed; inset:0; z-index:var(--z-upload, 99990); display:flex; align-items:center;
  justify-content:center; background:color-mix(in srgb, var(--ink) 30%, transparent); opacity:1; }
.hs-up-overlay.saindo { opacity:0; transition:opacity .28s ease-out; }
/* card usa o MESMO par dos toasts (provado legível): fundo --ink, texto --bg */
.hs-up-card { display:flex; align-items:center; gap:14px; background:var(--ink); color:var(--bg);
  padding:18px 26px; border-radius:16px; box-shadow:0 18px 50px rgba(0,0,0,.30);
  font-size:var(--fs-subtitulo); font-weight:700; animation:hs-up-pop .18s ease-out; }
.hs-up-card.hs-up-erro { background:var(--danger-solid); color:var(--danger-solid-fg); }
/* #5508: a pergunta antes do segundo grupo da mesma criança (web/js/grupo-duplicado.js). */
.grp-dup-texto { margin:0 0 14px; font-size:var(--fs-corpo); line-height:1.55; color:var(--ink-2); }
.grp-dup-acoes { display:flex; flex-wrap:wrap; gap:8px; justify-content:flex-end; }

/* #5472 - no calendário, a conversa marcada na Agenda pública não tem o X de remover evento */
.cal-card--agenda { cursor:pointer; }
/* #6063 - titulo, descricao e barra de ler em outro idioma do cartao de evento da Agenda */
.cal-ev-titulo { font-size:var(--fs-subtitulo); font-weight:700; color:var(--ink); }
.cal-ev-desc { font-size:var(--fs-corpo); color:var(--ink-2); margin-top:6px; line-height:1.5; }
.cal-ev-desc:empty, .cal-ev-traduzir:empty { display:none; }
.cal-ev-traduzir { margin-top:8px; }
/* #6063 - titulo da aula do Academy e a barra de ler em outro idioma logo abaixo */
.acad-aula-titulo { font-size:var(--fs-subtitulo); font-weight:800; color:var(--ink); margin-bottom:14px; }
.acad-aula-traduzir { margin:-6px 0 14px; }
.acad-aula-traduzir:empty { display:none; }

/* #5478 - o aviso central sempre tem saída */
.hs-up-cancelar { margin-left:6px; padding:6px 14px; border-radius:999px; cursor:pointer;
  background:transparent; color:inherit; font:inherit; font-size:var(--fs-corpo); font-weight:700;
  border:1px solid color-mix(in srgb, var(--bg) 45%, transparent); }
.hs-up-cancelar:hover { background:color-mix(in srgb, var(--bg) 14%, transparent); }
.hs-up-cancelar:focus-visible { outline:2px solid var(--bg); outline-offset:2px; }
.hs-spinner-md { width:26px; height:26px; border-radius:50%; flex-shrink:0;
  border:3px solid color-mix(in srgb, var(--bg) 28%, transparent); border-top-color:var(--bg);
  animation:hs-spin .7s linear infinite; }
@keyframes hs-up-pop { from { transform:translateY(6px) scale(.97); } to { transform:none; } }

/* ---- shell do console ---- */
/* #4561 - tela fixa, só o .adm-main rola, na altura útil (--altura-tela) que desconta as faixas do topo */
.adm { display:flex; height:var(--altura-tela, 100vh); overflow:hidden; }
.adm-side { width:260px; flex-shrink:0; background:var(--cromo-bg); border-right:1px solid var(--cromo-linha);
  color:var(--cromo-fg); --anel-foco:0 0 0 2px var(--cromo-fg);
  padding:24px 16px; display:flex; flex-direction:column; gap:2px;
  /* altura fixa + clip: a lista de itens (#menuScroll) rola por dentro e o
     perfil/sair/status ficam SEMPRE visíveis no rodapé, nunca abaixo da barra
     de tarefas, mesmo com o menu agrupado mais alto. */
  height:var(--altura-tela, 100vh); overflow:hidden; }
#menuScroll { flex:1 1 auto; min-height:0; overflow-y:auto; overflow-x:hidden;
  display:flex; flex-direction:column; gap:2px;
  scrollbar-width:thin; scrollbar-color:var(--cromo-barra) transparent; }
/* #6381: a barra de rolagem aparece, fina, na cor da letra (branca sobre cor escura,
   preta sobre cor clara). Antes ela era escondida (largura 0) e a pessoa nao sabia
   que havia mais itens embaixo. */
#menuScroll::-webkit-scrollbar { width:6px; }
#menuScroll::-webkit-scrollbar-track { background:transparent; }
#menuScroll::-webkit-scrollbar-thumb { background:var(--cromo-barra); border-radius:999px; }
/* #6381: o espaco que empurra o rodape para baixo antes de a lista ser montada */
.menu-fim { flex:1; }
#perfilSidebar, #statusBar { flex-shrink:0; }
/* #4648: piso de 641px. A explicação inteira mora no bloco do `.recolhido` mais
   abaixo; aqui basta o motivo curto: abaixo de 640 a barra é faixa de rodapé, e
   ali a barra de status precisa continuar na tela. */
@media (min-width:641px){ .adm-side.recolhido #statusBar { display:none !important; } }
/* Equipe do After: cada cargo num toggle recolhível */
details.after-grupo { width:100%; margin-top:9px; border:1px solid var(--line); border-radius:10px; overflow:hidden; }
details.after-grupo > summary { list-style:none; cursor:pointer; display:flex; align-items:center; gap:7px;
  padding:9px 12px; background:var(--surface-2); font-size:var(--fs-legenda); font-weight:800; color:var(--ink-2);
  text-transform:uppercase; letter-spacing:.4px; user-select:none; }
details.after-grupo > summary::-webkit-details-marker { display:none; }
details.after-grupo > summary .after-caret { display:inline-block; transition:transform .15s; color:var(--ink-3); font-size:var(--fs-corpo-pequeno); }
details.after-grupo[open] > summary .after-caret { transform:rotate(90deg); }
details.after-grupo > summary .after-cont { color:var(--ink-3); font-weight:600; }
details.after-grupo .after-chips { display:flex; gap:8px; flex-wrap:wrap; padding:11px 12px; }
/* spinner de carregamento (ex.: Ana escrevendo no editor) */
.ia-spin { display:inline-block; width:13px; height:13px; border:2px solid var(--line);
  border-top-color:var(--accent); border-radius:50%; animation:ia-rot .7s linear infinite;
  vertical-align:-2px; flex-shrink:0; }
@keyframes ia-rot { to { transform:rotate(360deg); } }
/* Config → Equipe: só o corpo da tabela rola; cabeçalho fica fixo (sticky) */
.equipe-scroll { max-height:54vh; overflow:auto; border:1px solid var(--line); border-radius:10px; }
.equipe-scroll thead th { position:sticky; top:0; z-index:1; background:var(--surface);
  box-shadow:inset 0 -1px 0 var(--line); }
.adm-side .marca { display:flex; flex-direction:column; align-items:stretch; gap:10px; padding:6px 8px 16px;
  margin-bottom:8px; border-bottom:1px solid var(--cromo-linha); }
/* #6381: nome e subtitulo da marca, e o botao de recolher, na letra do cromo */
.marca-nome { font-size:var(--fs-corpo); font-weight:800; color:var(--cromo-fg); }
.marca-sub { font-size:var(--fs-legenda); color:var(--cromo-fg-2); }
.marca-recolher { background:none; border:none; cursor:pointer; color:var(--cromo-fg-2); padding:6px;
  border-radius:8px; display:flex; flex-shrink:0; }
.marca-recolher:hover { background:var(--cromo-hover); color:var(--cromo-fg); }
.marca-recolher:focus-visible { outline:none; box-shadow:var(--anel-foco); }
.adm-side .marca-logo { display:flex; align-items:center; justify-content:center; }
/* a logo vem numa arte quadrada com muita margem (≈39% em cima/embaixo); recorto a
   faixa central (object-fit:cover) p/ a wordmark preencher a largura e ficar legível,
   sem o espaço morto vertical que a fazia parecer minúscula. */
.adm-side .marca-logo img { width:100%; height:64px; box-sizing:border-box; object-fit:cover;
  object-position:center; display:block; border-radius:12px; }
.adm-side .marca-conta { display:flex; align-items:center; gap:10px; }
/* logo em JPG tem fundo branco: no tema escuro vira um cartão claro p/ a wordmark colorida não brigar com o fundo */
[data-theme="dark"] .adm-side .marca-logo img,
[data-marca-escola="sim"] .adm-side .marca-logo img { background:#fff; padding:6px 10px; }
.adm-side .marca-mono { width:36px; height:36px; border-radius:11px; flex-shrink:0; overflow:hidden;
  display:flex; align-items:center; justify-content:center; color:var(--accent-fg); font-weight:800;
  font-family:var(--font-display); font-size:var(--fs-subtitulo); background-size:cover; background-position:center center;
  background-image:linear-gradient(135deg, var(--accent-hover), var(--accent));
  box-shadow:0 0 0 1px var(--cromo-linha), 0 1px 3px color-mix(in srgb,var(--accent) 30%,transparent);
  text-shadow:0 1px 2px rgba(0,0,0,.20); }
.adm-side .marca-txt { min-width:0; }
/* #6381, 13/10: o dono preferiu a barra da Fundacao nova, menos arredondada, mais larga e com mais folga */
.adm-item { display:flex; align-items:center; gap:10px; padding:10px 12px; border-radius:var(--r);
  font-size:var(--fs-menu-item); font-weight:600; color:var(--cromo-fg-2); cursor:pointer; border:none;
  background:none; width:100%; text-align:left; font-family:var(--font); transition:all .13s; }
.adm-item:hover { background:var(--cromo-hover); color:var(--cromo-fg); }
/* #6381: o item ativo vira pilula na cor da letra, com a letra na cor do fundo (o par
   que ja passa de 4,5:1), e um ponto a direita na barra cheia */
.adm-item[aria-current="true"] { background:var(--cromo-fg); color:var(--cromo-bg); }
.adm-item[aria-current="true"]::after { content:""; width:6px; height:6px; border-radius:50%;
  background:currentColor; margin-left:auto; flex-shrink:0; }
.adm-item[aria-current="true"]:has(.msg-badge:not([hidden]))::after { display:none; }
.adm-grupo .rotulo { min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

/* #6381: O GRUPO NO MODELO DO CJSIN. Cabecalho com icone, nome em negrito um pouco
   maior que o item, seta a direita e fundo levemente mais claro quando aberto. Os
   itens moram numa caixa com a linha fina a esquerda, alinhada ao centro do icone do
   grupo. Um grupo aberto por vez (web/js/menu-lateral.js poe ou tira `.fechado`). */
.adm-cat { display:flex; align-items:center; gap:10px; width:100%; padding:10px 12px; margin-top:6px;
  border:none; border-radius:var(--r); background:transparent; cursor:pointer; user-select:none;
  font-family:var(--font); font-size:var(--fs-menu-grupo); font-weight:700; color:var(--cromo-fg); text-align:left;
  transition:background .12s; }
.adm-cat:hover { background:var(--cromo-hover); }
.adm-cat.aberta { background:var(--cromo-aberto); }
.adm-cat:focus-visible { outline:none; box-shadow:var(--anel-foco); }
.adm-cat-ic { display:inline-flex; flex-shrink:0; }
.adm-cat-rot { flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.adm-cat-chev { display:inline-flex; flex-shrink:0; color:var(--cromo-fg-2); transition:transform .15s; }
.adm-cat.aberta .adm-cat-chev { transform:rotate(180deg); }
.adm-grupo { display:flex; flex-direction:column; gap:3px; margin:4px 0 10px 20px; padding-left:9px;
  border-left:1px solid var(--cromo-linha); }
.adm-grupo .adm-item { padding:10px 12px; }
.adm-grupo.fechado { display:none; }
@media (prefers-reduced-motion:reduce) { .adm-cat-chev { transition:none; } }

/* #6381: a dica com o nome inteiro ao passar o mouse (no trilho so aparece o icone) */
.menu-dica { position:fixed; z-index:9700; transform:translateY(-50%); pointer-events:none;
  padding:5px 9px; border-radius:6px; background:var(--text-1); color:var(--surface);
  font:600 var(--fs-corpo-pequeno)/1.3 var(--font); white-space:nowrap; box-shadow:var(--sh-2); }
.menu-dica[hidden] { display:none; }

/* #6389: A BUSCA DE FUNCAO no topo da barra (web/js/menu-busca.js), como a da Fundacao. O campo
   e transparente sobre o cromo: a letra de apoio do placeholder ja passa de 4,5:1 sobre o fundo. */
.menu-busca { position:relative; display:flex; align-items:center; margin:0 0 10px; }
.menu-busca-ic { position:absolute; left:10px; display:inline-flex; color:var(--cromo-fg-2); pointer-events:none; }
.menu-busca-campo { width:100%; height:36px; box-sizing:border-box; padding:0 32px 0 32px;
  border:1px solid var(--cromo-linha); border-radius:9px; background:transparent; color:var(--cromo-fg);
  font:500 var(--fs-corpo)/1 var(--font); -webkit-appearance:none; appearance:none; }
.menu-busca-campo::placeholder { color:var(--cromo-fg-2); opacity:1; }
.menu-busca-campo::-webkit-search-cancel-button { display:none; }
.menu-busca-campo:focus { outline:none; border-color:var(--cromo-fg); box-shadow:var(--anel-foco); }
.menu-busca-limpar { position:absolute; right:6px; width:24px; height:24px; border:0; border-radius:6px;
  background:transparent; color:var(--cromo-fg-2); cursor:pointer; display:inline-flex; align-items:center;
  justify-content:center; }
.menu-busca-limpar:hover { background:var(--cromo-hover); color:var(--cromo-fg); }
.menu-busca-limpar:focus-visible { outline:none; box-shadow:var(--anel-foco); }
.menu-busca-limpar[hidden] { display:none; }
#menuLateral .busca-fora { display:none; }
#menuLateral .adm-grupo.busca-aberta { display:flex; }
.menu-busca-titulo { padding:12px 11px 4px; font:700 var(--fs-corpo-pequeno)/1.2 var(--font); color:var(--cromo-fg-2); }
.menu-achado { display:flex; flex-direction:column; align-items:flex-start; gap:2px; width:100%; padding:7px 11px;
  border:0; border-radius:11px; background:none; color:var(--cromo-fg); text-align:left; cursor:pointer;
  font-family:var(--font); }
.menu-achado:hover { background:var(--cromo-hover); }
.menu-achado:focus-visible { outline:none; box-shadow:var(--anel-foco); }
.menu-achado-nome { font-size:var(--fs-corpo); font-weight:600; }
.menu-achado-onde { font-size:var(--fs-legenda); color:var(--cromo-fg-2); }
.menu-busca-vazio { padding:10px 11px; font-size:var(--fs-corpo); color:var(--cromo-fg-2); }
.menu-busca-ajustes[hidden], .menu-busca-vazio[hidden] { display:none; }
/* ocupa toda a largura disponível, sem cap (o conteúdo ia até 50% em monitor largo).
   Sem padding: cada página traz a própria .topo-pagina (sticky, flush no topo) e o
   próprio padding de conteúdo, assim a barra do topo não descola nem cola nos cards. */
/* #6427 - a coluna que rola e tambem o bloco de posicao: o filho escondido por position absolute (.sr-only)
   sem ancestral posicionado escapava dela e esticava a janela, que rolava inteira com a barra lateral
   (Rede social 1.690 px e Mural 1.302 px de janela para 943 e 768 de tela). So a posicao, sem z-index:
   nao vira contexto de empilhamento e nao muda nada do que e fixed (modais, listas, Ana, toasts). */
.adm-main { flex:1; min-width:0; padding:0; height:var(--altura-tela, 100vh); overflow-y:auto; position:relative; }
/* Pessoas: 2 painéis que preenchem a tela exatamente. A faixa do topo tem altura
   variável, então em vez de calc(100vh - constante), que estourava o .adm-main em
   poucos px e gerava a 2ª barra de rolagem, a seção vira flex-column de 100vh e a
   linha dos painéis ocupa o resto com flex:1. O :not([hidden]) preserva o ocultar. */
#pagina-pessoas:not([hidden]) { display:flex; flex-direction:column; height:var(--altura-tela, 100vh); }
/* Comunicados: mesmo padrao do Pessoas. O compositor de 3 colunas usava
   min-height:calc(100vh - 75px) com um numero magico (75px) que nao batia com a
   altura real da .topo-pagina (sticky, altura variavel), sobravam 1-2px e nascia
   a 2a barra de rolagem. Vira flex-column de 100vh e a linha das colunas pega o
   resto com flex:1, sem constante. */
#pagina-comunicados:not([hidden]) { display:flex; flex-direction:column; height:var(--altura-tela, 100vh); }
/* Rotina (#304): MESMO padrao. A linha das 3 colunas usava height:calc(100vh - 75px)
   com o numero magico (75px) que nao batia com a altura real da .topo-pagina,
   sobravam 1-2px e nascia a barra de rolagem lateral da pagina. Vira flex-column
   de 100vh e a linha das colunas pega o resto com flex:1 (sem constante). De quebra,
   a coluna da biblioteca fica com altura cheia p/ a lista de modelos preencher 100%. */
#pagina-rotina:not([hidden]) { display:flex; flex-direction:column; height:var(--altura-tela, 100vh); }
/* Cardapio (#4620): a QUARTA pagina com o mesmo defeito, e a ultima que ainda
   usava o numero magico. O dono, num MacBook: "a barra de publicar refeicoes por
   algum motivo ganha uma barra de rolagem invisivel e come os botoes no rodape".

   MEDIDO em 1440x789 (MacBook 13" em tela cheia), antes do conserto:

     .topo-pagina ..... 79px de altura real
     .comp-3col ....... calc(100vh - 75px) = 714px
     soma ............. 79 + 714 = 793 contra 789 de viewport

   Sobravam 4px, e o .adm-main (overflow-y:auto) ganhava uma barra de rolagem de
   4px. No Windows ela apareceria; no macOS a barra e SOBREPOSTA e so surge
   quando alguem rola, entao ela e literalmente invisivel, que e a palavra que
   ele usou. E como a coluna de publicar ja rola por dentro (28px escondidos), o
   rodape dela ficava embaixo de uma segunda barra que ninguem ve: dois roladores
   aninhados, e o dedo sempre cai no de dentro (a armadilha do #4149).

   Nao existe constante certa: a .topo-pagina e sticky e de altura variavel (75px
   em 768, 79px em 1280). Por isso as tres irmas acima trocaram o calc por
   flex-column de 100vh, e o Cardapio passa a fazer o mesmo. */
/* #369 - o Cardapio virou a casca da casa (web/css/cardapio.css): sem colunas presas, a pagina rola no .adm-main e o cabecalho gruda; a altura fixa saiu */
/* #4635: as QUATRO ULTIMAS telas com o mesmo numero magico, achadas ao consertar
   o Cardapio. O defeito e identico e a conta tambem:

     .topo-pagina .... 79px em 1512, 1440, 1280, 1180 e 1100 de largura
                       (75px so em 920 e 768)
     a linha ......... calc(100vh - 75px)
     sobra ........... 79 + (100vh - 75) = 100vh + 4

   MEDIDO no banco de ensaio, uma pagina por vez, ANTES do conserto: excedente
   vertical do .adm-main = 4px em 1512x830, 1440x789, 1280x700, 1180x800 e
   1100x800, nas QUATRO telas. Sao exatamente os 4px que viram barra de rolagem
   invisivel no macOS (a barra la e sobreposta e so aparece enquanto se rola) e
   um segundo rolador em cima do rodape de quem ja rola por dentro.

   O conserto e o mesmo das quatro irmas de cima, sem constante nenhuma: a secao
   vira flex-column de 100vh e a linha de conteudo pega o resto com
   flex:1;min-height:0. DEPOIS, nas mesmas cinco larguras: excedente 0 nas quatro.

   DUAS DELAS SOLTAM A ALTURA EM TELA ESTREITA e duas nao, e isso e medido, nao
   escolhido: After School e Calendario empilham as colunas em 920px (a regra do
   .comp-3col e a do .cal-3col), entao ali a secao volta a `display:block` para a
   pilha rolar como pagina (o mesmo que o #4620 fez no Cardapio). Retirada e Sala
   de espera nao empilham em largura nenhuma: a Retirada e uma linha de coluna
   mais painel do scanner, e a Sala de espera e uma coluna so. Devolver essas
   duas para `block` no celular tiraria o fundo de tela cheia sem consertar nada. */
/* #373: o After School saiu do console para o padrao Comunicador: a casca da casa (web/css/afterschool.css) rola com a pagina,
   sem secao travada em uma tela (travada, a casca parava em 100vh e o cabecalho fixo soltava quando o diario passava da tela). */
/* #366 e #367 (11/11): a Retirada e a Sala de espera sairam do console para o padrao Comunicador: a casca da casa rola com a
   pagina, sem secao travada em uma tela (travada, a casca parava na altura da tela e, com a lista longa, o cabecalho que devia
   grudar subia 2120 px na Retirada e 1196 px na Sala de espera acima do topo; medido no Chrome a 1440 x 789). */
/* #363: o Calendario saiu do molde de colunas: a casca da casa (web/admin/paginas/calendario.html) rola com a pagina. */
/* badge de mensagens não lidas no item da barra lateral (e no canto quando recolhido) */
.msg-badge { position:absolute; top:50%; right:14px; transform:translateY(-50%); min-width:18px;
  height:18px; padding:0 5px; border-radius:999px; background:var(--danger-solid); color:var(--danger-solid-fg); font-size:var(--fs-legenda);
  font-weight:800; display:flex; align-items:center; justify-content:center; line-height:1; box-sizing:border-box; }
.msg-badge[hidden] { display:none; }
/* #4206 - o contador de matriculas pendentes no botao da Secretaria */
.sec-badge-pre-mat { background:var(--danger-solid); color:var(--danger-solid-fg); border-radius:999px; font-size:var(--fs-legenda);
  font-weight:800; padding:1px 7px; margin-left:4px; }
/* #4648: mesmo piso de 641px do resto do `.recolhido` (explicação no bloco abaixo). */
@media (min-width:641px){
  .adm-side.recolhido .msg-badge { top:5px; right:8px; transform:none; min-width:16px; height:16px; font-size:var(--fs-legenda); padding:0 4px; }
}
/* ações por mensagem (reagir/responder/apagar), aparecem ao passar o mouse na linha */
.msg-acoes { display:flex; gap:2px; align-self:center; opacity:0; transition:opacity .12s; flex-shrink:0; }
.msg-linha:hover .msg-acoes { opacity:1; }
.msg-acao { border:none; background:var(--surface-2); border-radius:8px; width:28px; height:28px; cursor:pointer;
  color:var(--ink-3); display:flex; align-items:center; justify-content:center; padding:0; }
.msg-acao:hover { background:var(--surface-3); color:var(--ink); }
.msg-reacao:hover { filter:brightness(.97); }

/* #4321 (10/08), canal FIXO "Fale com a escola" (#328), o da família. Ele
   nasce com `hidden` no HTML e o `_revelarAlanaFixo()` escreve
   `b.hidden = !_ehFamilia` desde o dia em que a tela nasceu. Só que o botão
   carregava `display:flex` no `style=""`, e inline vence QUALQUER regra: o
   `[hidden]{display:none}` do navegador não tinha como desligá-lo. Resultado
   medido num navegador de verdade, em 360x800: um botão de 328x58 com o texto
   "Elogios, sugestões e reclamações" aparecendo para a ESCOLA, que não tem o
   que fazer ali, é o canal do pai reclamar dela.
   O display mora AQUI agora, onde a regra abaixo consegue desligar. Décima
   família desta mesma armadilha (ver a nota do [hidden] no tokens.css). */
.msg-alana-fixo { display:flex; align-items:center; gap:10px;
  margin:12px 16px 0; padding:10px 12px; flex-shrink:0; text-align:left;
  border:1px solid var(--primary); border-radius:12px;
  background:var(--primary-soft); cursor:pointer; font-family:var(--font); }
.msg-alana-fixo[hidden] { display:none; }

/* #4321: OS DOIS QUE A VARREDURA DO NAVEGADOR NÃO ENXERGAVA, porque o
   JavaScript é quem os monta: eles não existem no DOM quando a página nasce.
   Quem os achou foi a varredura do ARQUIVO (tests/test_4321_hidden_com_display_inline).
   Mesma mecânica dos outros: `display` no `style=""` mata o `hidden`.

   .msg-resp-prev, a tira "Respondendo a…" acima do compositor de mensagens.
   O `_pintarRespostaPrev()` faz `prev.hidden = true` quando não há resposta em
   curso; com o display inline ela nunca sumia e sobrava uma faixa vazia de 8px
   empurrando o compositor para baixo o tempo todo.

   .ag-resp-sel, a etiqueta do professor responsável, no modal da agenda. Esta
   é a que mais dói: ao clicar em "Trocar", o `pintarResp()` cai no ramo do
   `respSel.hidden = true` E NÃO LIMPA O innerHTML (de propósito, para repintar
   depois). Com o `hidden` sem efeito, o nome do responsável ANTIGO continuava
   na tela, com o botão "Trocar" do lado, ao mesmo tempo que a busca reabria:
   a pessoa via dois responsáveis e não sabia qual valia. */
.msg-resp-prev { display:flex; align-items:center; gap:8px; padding:8px 16px 0; }
.msg-resp-prev[hidden] { display:none; }
.ag-resp-sel { display:flex; align-items:center; gap:8px; padding:7px 10px;
  margin-bottom:6px; background:var(--surface-2); border:1px solid var(--line);
  border-radius:9px; }
.ag-resp-sel[hidden] { display:none; }
/* menu recolhido (botão hambúrguer): só ícones, persistido em localStorage */

/* #4648: O PISO DE 641px, E POR QUE ELE FALTAVA.

   O `.recolhido` é a escolha de quem clicou no hambúrguer, e ela é guardada no
   navegador (`camino_menu_recolhido`), não na tela. Quando a mesma pessoa abre o
   console num celular, a escolha volta junto, e aí a classe encontra o bloco de
   mobile pela frente.

   QUEM GANHA: `.adm-side.recolhido` tem DOIS nomes de classe, `.adm-side` tem um.
   Media query não soma especificidade, então a classe vence o bloco de celular
   inteiro por 0,2,0 contra 0,1,0. O celular pedia `width:100%` e recebia 64px.

   MEDIDO no banco de ensaio, janela de 375px, com a classe ligada à mão:

                            sem a classe        com a classe
     barra                  375x52              64x58
     tela morta ao lado     0px                 311px
     rodapé do perfil       linha               coluna
     itens alcançáveis      10 de 37            3 de 37
     barra de status        na tela             fora

   Ou seja: a faixa de rodapé virava um quadrado de 64px no canto inferior
   esquerdo, com 311px de tela sobrando ao lado e 34 dos 37 itens do menu só
   alcançáveis rolando dentro de uma janelinha de 64px de largura.

   COMO SE CHEGA LÁ, e é por isso que o card é p4 e não p2: num celular puro a
   chave nunca é escrita, porque o hambúrguer mora dentro do `.marca`, que é
   `display:none` no celular. O caminho é o tablet: quem recolheu o menu num iPad
   deitado e depois girou o aparelho para retrato cai abaixo de 640 com a classe
   ligada.

   O CONSERTO É UM PISO, NÃO UMA LISTA DE EXCEÇÕES. Poderia ser um punhado de
   regras `.adm-side.recolhido` dentro do bloco de celular desfazendo uma a uma o
   que a classe faz, mas aí toda regra nova do `.recolhido` nasceria com a
   obrigação de ter a gêmea que a desfaz, e a primeira que esquecesse traria o
   defeito de volta. Com o piso, regra nova escrita aqui dentro já nasce sem
   alcance no celular.

   641 É O MESMO PISO DO #4627, e pelo mesmo motivo: 640 é o último pixel em que a
   barra é faixa horizontal de rodapé. Acima dele nada muda, e isso é o que
   importa para o dono, que usa o menu recolhido no computador todo dia: medido a
   1180px e a 1512px, antes e depois, a barra segue 64x812 com os 37 itens no
   lugar. Cobrado por `tests/test_4648_o_recolhido_nao_alcanca_o_celular.py`. */
@media (min-width:641px){
  .adm-side.recolhido { width:72px; }
  /* #6619 (print do dono, 15/10): "o quadrado branco fica distorcido ... a barra de rolagem nao pode ficar colada
     nele, tem que ter o mesmo espacamento dos dois lados". Medido no Chromium com a barra de 64px: a folga de 16px de
     cada lado e a rolagem fina (10px, nao os 6 do ::-webkit-scrollbar, que o scrollbar-width:thin desliga) deixavam
     o item ativo em 21 x 36, encostado na rolagem. Agora a barra tem 72px; a lista vai de borda a borda, reserva a
     faixa da rolagem (scrollbar-gutter) e centra o item de 40 x 40 no que sobra: o espaco da esquerda e o de antes
     da rolagem saem iguais em qualquer navegador (10,5px no Chromium, 11,5 no Firefox). Os 10px da direita sao a
     faixa da rolagem, para o topo e o rodape centrarem no mesmo eixo dos quadrados. */
  .adm-side.recolhido { padding-left:0; padding-right:10px; }
  .adm-side.recolhido #menuScroll { margin-right:-10px; align-items:center; scrollbar-gutter:stable; }
  .adm-side.recolhido .rotulo,
  .adm-side.recolhido .marca-logo,
  .adm-side.recolhido .marca-txt { display:none; }
  .adm-side.recolhido .marca-conta { flex-direction:column; gap:8px; }
  .adm-side.recolhido #recolherMenu { margin-left:0; }
  .adm-side.recolhido .adm-item { justify-content:center; padding:0; width:40px; height:40px; flex:0 0 40px; }
  .adm-side.recolhido #perfilSidebar { flex-direction:column; padding:10px 2px 4px; }
  .adm-side.recolhido #perfilSidebar #meuPerfil { display:none; }
  /* #6381: no menu recolhido nao ha grupo: a caixa some e os itens ficam todos, so icone */
  .adm-side.recolhido .adm-grupo,
  .adm-side.recolhido .adm-grupo.fechado { display:contents; }
  .adm-side.recolhido .adm-item[aria-current="true"]::after { display:none; }
  /* #6389: no menu so de icones nao cabe a busca */
  .adm-side.recolhido .menu-busca,
  .adm-side.recolhido .menu-busca-ajustes,
  .adm-side.recolhido .menu-busca-vazio { display:none; }
  #menuLateral.recolhido .adm-grupo.busca-aberta { display:contents; }
}
/* #3858: a foto do rodape passou a ser o botao da CENTRAL DE NOTIFICACOES (era
   onde o dono pediu). No menu recolhido some o bloco de texto e sobra a foto com
   a bolinha -- que e justamente o que precisa continuar visivel ali. O atalho de
   Meu perfil nao se perde: Configuracoes > Usuario esta no menu do lado. */

/* #3859: a FOTO do rodape e o botao da central. Duas correcoes do dono aqui:

   1) A BOLINHA APARECIA COM "0". O `hidden` do HTML so funciona porque o
      navegador traz `[hidden]{display:none}` na folha DELE -- e qualquer
      `display` no atributo style="" ganha dessa regra, por especificidade
      infinita do inline. A bolinha tinha `display:flex` inline, entao ficava
      visivel mesmo escondida. O display mora AQUI agora, numa classe, onde a
      regra [hidden] consegue desligar. E a 8a vez que essa mesma armadilha
      aparece no projeto (ver a nota do [hidden] no tokens.css).

   2) A BOLINHA CAIA FORA DE LUGAR. O botao nao tinha tamanho proprio: a caixa
      dele dependia da linha de texto, entao o "canto superior direito" era o
      canto de uma caixa maior que a foto. Agora o botao E a foto (34x34, grid),
      e a bolinha ancora no canto certo. z-index garante que ela fique SOBRE a
      foto, nunca por baixo. */
.perfil-central { position:relative; display:grid; place-items:center; width:34px; height:34px;
  background:none; border:none; padding:0; margin:0; cursor:pointer; border-radius:50%;
  flex-shrink:0; line-height:0; }
.perfil-central #centralAv { width:34px; height:34px; font-size:var(--fs-corpo); transition:filter .15s; }
.perfil-central:hover #centralAv { filter:brightness(.92); }
.perfil-central:focus-visible { outline:2px solid var(--accent); outline-offset:3px; }

.perfil-bolha { position:absolute; top:-3px; right:-3px; z-index:2;
  min-width:18px; height:18px; padding:0 4px; border-radius:9px;
  background:var(--danger-solid); color:var(--danger-solid-fg); font-size:var(--fs-legenda); font-weight:800; line-height:1;
  display:flex; align-items:center; justify-content:center;
  border:2px solid var(--surface); font-variant-numeric:tabular-nums; box-sizing:border-box; }
.perfil-bolha[hidden] { display:none; }
/* #5800 - o display das duas classes vencia o hidden que a conta da cozinha poe no sino e no avatar */
.perfil-central[hidden], .perfil-acao[hidden] { display:none; }

/* #6381: O RODAPE DO PERFIL NA LETRA DO CROMO. As cores moravam no style montado pelo
   JS (tinta escura fixa), que some sobre a cor da escola. O nome, o papel, o sino e o
   sair viraram classe. A borda de cima do rodape tambem: o resto do style do
   #perfilSidebar fica no HTML de proposito: o padding dele vence hoje as regras do
   recolhido e do trilho, e tira-lo dali mudaria o rodape do menu de 64px. */
#perfilSidebar { border-top:1px solid var(--cromo-linha); }
.perfil-eu-nome { font-size:var(--fs-corpo); font-weight:700; color:var(--cromo-fg);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.perfil-eu-papel { font-size:var(--fs-legenda); color:var(--cromo-fg-2);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.perfil-acao { flex-shrink:0; background:none; border:none; cursor:pointer; padding:8px;
  border-radius:10px; color:var(--cromo-fg-2); display:flex; position:relative; }
.perfil-acao:hover { background:var(--cromo-hover); color:var(--cromo-fg); }
#meuPerfil:hover { background:var(--cromo-hover); }
/* #6618: o botao do nome saiu do style montado pelo JS (inline proibido, #5542). No trilho, a regra do #4536 (38px,
   flex:0 0 auto) passa a valer nele tambem, como valia nos outros botoes do rodape. */
.perfil-eu { flex:1; min-width:0; display:flex; align-items:center; background:none; border:none; cursor:pointer;
  padding:6px; border-radius:10px; text-align:left; }
/* #6618 (print do dono, 15/10): com o botao de reportar erro (#4434), a foto, o sino, o reportar e o sair comiam a
   linha da barra aberta e sobravam ~42px para o nome ("Re..."). Opcao B, a recomendada: na barra aberta o rodape quebra
   em duas linhas; a foto e o nome com o papel usam a largura toda, e as acoes descem para a linha de baixo, espalhadas.
   So na barra aberta (1180px ou mais, sem o recolhido): o trilho e o celular nao mudam. */
/* #6147 - sem @media de 1180 (corte novo): as regras valem sempre e o bloco do 1179 (#4232) as desfaz; a 2a fica sem o id para o #4536 vencer no trilho */
/* #6641 (desenho do dono, 16/10): o rodape volta a UMA linha. Ele cabe de novo porque
   dois botoes sairam: o sino virou selo na propria foto (os dois chamavam abrirCentral,
   era duplicata) e o reportar saiu do rodape. A opcao B do #6618, que quebrava em duas
   linhas, fica aposentada.
   O PRECO, medido: a largura util do nome cai de 180 para 118 px, e ele passa a cortar
   a partir de 16 caracteres em vez de 28. Foi escolha dele, de olho na medida. */
/* O ORCAMENTO DA LINHA, em 248 px de barra (#6641, 2a volta: "o nome esta cortado").
   Na 1a volta sobravam 128 px para o nome e "Renato Sanches" cortava. A conta de onde
   vem cada pixel: 8 de padding + 40 de foto + 9 de vao + NOME + 6 de vao + 30 do sair
   + 6 de padding. Sobram 149, contra 128: 21 px, que e o que separa cortar de caber.
   A foto cai de 44 para 40, os vaos e os paddings apertam, e o selo saiu do lado
   esquerdo, que era onde ele obrigava a folga de 10 px. */
.adm-side:not(.recolhido) #perfilSidebar { flex-wrap:nowrap; gap:9px; padding:12px 6px 10px 8px; }
.adm-side:not(.recolhido) .perfil-central { width:40px; height:40px; overflow:visible; }
.adm-side:not(.recolhido) .perfil-central #centralAv { width:40px; height:40px; font-size:var(--fs-subtitulo); }
.adm-side:not(.recolhido) .perfil-central.tem-anel #centralAv { width:34px; height:34px; font-size:var(--fs-corpo); }
.adm-side:not(.recolhido) .perfil-eu { flex:1 1 auto; min-width:0; padding:2px 0 2px 2px; margin-right:-3px; }
.adm-side:not(.recolhido) .perfil-eu-nome { font-size:var(--fs-subtitulo); }
.adm-side:not(.recolhido) .perfil-eu-papel { font-size:var(--fs-corpo-pequeno); }
.adm-side:not(.recolhido) #sair { padding:6px; }

/* O SELO DO AVISO (#6641). Ele NAO conta nada: numero no selo e ruido, porque ninguem
   decide nada sabendo que sao 3 e nao 4. Em silencio veste a cor da barra e quase some;
   com recado acende.
   O ARO NAO E ENFEITE, e o que faz o aviso existir. MEDIDO: o vermelho da casa contra a
   barra teal da 1,20 de contraste, e contra uma escola de marca vermelha da 1,38, ou
   seja, a bolinha SOME. O pulso salvava quem enxerga movimento, mas a casa respeita
   prefers-reduced-motion e quem liga isso ficaria sem aviso nenhum. Com o aro em
   var(--cromo-fg), que a casa ja calcula contra a cor da escola, a medida vai para 5,72
   no teal e 6,54 no vermelho, e funciona PARADA. */
/* #6641 (16/10, 2a volta): o selo passa para a DIREITA da foto, por pedido do dono. De
   quebra ele deixa de pendurar para fora a esquerda, e o padding esquerdo do rodape pode
   encolher: sao 2 px que viram letra no nome. */
.perfil-selo { position:absolute; right:-4px; bottom:-3px; z-index:3; width:21px; height:21px;
  border-radius:50%; display:grid; place-items:center;
  background:var(--cromo-bg); color:var(--cromo-fg-2);
  border:2px solid var(--cromo-bg); box-shadow:0 0 0 1px var(--cromo-linha);
  transition:background .2s, color .2s, box-shadow .2s; }
.perfil-selo svg { width:12px; height:12px; display:block; }
.perfil-selo.tem-aviso { background:var(--danger-solid); color:var(--danger-solid-fg);
  border-color:var(--cromo-fg); box-shadow:0 0 0 1px var(--danger-solid);
  animation:hs-selo-pulsa 1.6s ease-out infinite; }
@keyframes hs-selo-pulsa {
  0%   { box-shadow:0 0 0 1px var(--danger-solid), 0 0 0 0 color-mix(in srgb, var(--danger-solid) 70%, transparent); }
  70%  { box-shadow:0 0 0 1px var(--danger-solid), 0 0 0 9px color-mix(in srgb, var(--danger-solid) 0%, transparent); }
  100% { box-shadow:0 0 0 1px var(--danger-solid), 0 0 0 0 color-mix(in srgb, var(--danger-solid) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) { .perfil-selo.tem-aviso { animation:none; } }
/* quem usa leitor de tela ouve a contagem pelo aria-label do BOTAO (sino-notificacoes.js):
   aria-label no pai vence o conteudo do filho, entao texto escondido aqui nunca seria lido. */
/* NO TRILHO E NO RECOLHIDO NADA DISSO VALE. O padrao do #6147 e que as regras acima
   valem sempre e o bloco de 641 a 1179 (#4232) as desfaz; como as minhas sao novas, o
   desfazer tambem tem de ser novo, senao a foto de 44 px estoura a barra de 72 px.
   O selo encolhe junto com a foto, senao ele encosta na borda. */
/* A GEMEA E OBRIGATORIA (#4627): abaixo de 1180 a barra vira trilho SEM a classe
   .recolhido, entao cada regra escrita para o hamburguer vale duas vezes. E o bloco do
   recolhido fica dentro de min-width:641, senao ele alcanca o celular (#4648). */
/* #6653 - o selo e a foto do rodape (#6641) moram nos blocos de 641 e de 641 a 1179 logo abaixo: um bloco por corte */
.perfil-central #centralAv { box-shadow:0 0 0 2px var(--cromo-linha); }
/* #6393 (08/10): APOSENTADO. O rodape de status saiu do console; as classes ficam porque
   a biblioteca do design system e o documento de estrategia ainda as descrevem. */
.status-item { display:inline-flex; align-items:center; gap:5px; font-size:var(--fs-legenda); color:var(--cromo-fg-2); }

/* O anel comprado na lojinha do Academy, agora tambem aqui. Mesma tecnica do
   perfil do Academy (fundo + mascara radial), so que no tamanho do rodape: a
   foto encolhe 4px para o anel caber sem empurrar o layout da barra. */
.perfil-central.tem-anel #centralAv { width:28px; height:28px; font-size:var(--fs-corpo-pequeno); }
.perfil-anel { position:absolute; inset:0; border-radius:50%; pointer-events:none;
  -webkit-mask:radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2px));
  mask:radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2px));
  animation:hs-perfil-gira 9s linear infinite; }
/* Nome proprio: o @keyframes acadGira so e injetado quando a tela do Academy
   abre, e o anel do rodape precisa girar desde o boot, em qualquer pagina. */
@keyframes hs-perfil-gira { to { transform:rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .perfil-anel { animation:none; } }
/* barra de status do rodapé: 3 bolinhas (banco/servidor/Ana) verde/amarelo/vermelho.
   Classe própria (svc-dot) p/ NÃO colidir com os dots de presença (.status-dot). */
.svc-dot { width:9px; height:9px; border-radius:50%; background:var(--ink-3); flex-shrink:0;
  display:inline-block; transition:background .3s ease; }
/* #4648: mesmo piso de 641px do resto do `.recolhido` (explicação no bloco acima). */
@media (min-width:641px){
  .adm-side.recolhido .status-lab { display:none; }
  .adm-side.recolhido #statusBar { flex-direction:column; align-items:center; gap:7px; padding:4px 2px 8px; }
  /* #6641: a foto e o selo encolhem junto, senao a foto de 44 px estoura a barra de 72 px */
  .adm-side.recolhido .perfil-central,
  .adm-side.recolhido .perfil-central #centralAv { width:34px; height:34px; font-size:var(--fs-corpo); }
  .adm-side.recolhido .perfil-selo { width:17px; height:17px; right:-3px; bottom:-2px; }
  .adm-side.recolhido .perfil-selo svg { width:10px; height:10px; }
}
/* tablet: barra lateral vira trilho de ícones.

   #4232: O CORTE SUBIU DE 1024 PARA 1179, e a conta é o argumento inteiro.

   O menu recolhido ocupa 64px; o cheio, 228. Com o corte em 1024, a janela
   crescia UM pixel e o espaço útil CAÍA 163: em 1024 sobravam 960px para o
   conteúdo, em 1025 sobravam 797. A tela ficava PIOR ao ficar maior, que é o
   contrário do que qualquer pessoa espera, e por isso ninguém procura ali
   quando reclama que "ficou apertado".

   Pior: as regras responsivas do sistema param em 920px de janela. Então de
   1025 a 1083 o console tinha MENOS espaço útil do que tem a 920 (855 contra
   856) e não recebia ajuste nenhum, porque pela largura da JANELA ele já era
   considerado grande. É exatamente onde vivem iPad deitado, iPad Pro e MacBook
   13", "as resoluções da Apple" que o dono citou no #4188.

   A RÉGUA: o menu cheio só pode aparecer quando o espaço útil ficar >= 856px
   (o que a janela de 920 já entregava). Isso dá janela >= 1084. Escolhi 1180 em
   vez de 1084 para não colar no limite, a 1180 sobram 952px de conteúdo, 96 de
   folga. Empurrar mais (1280) atrasaria o menu com rótulos sem ganho medido.

   #6381, 13/10: o menu cheio passou de 228 para 260px (a barra da Fundacao nova, que o dono
   preferiu). Conta refeita: o cheio so cabe com janela >= 1116 (856 + 260); o corte em 1180
   continua valendo, e a 1180 sobram 920px de conteudo, 64 de folga.

   Isto NÃO substitui a régua do estudo #4202, que propõe medir o CONTEÚDO e não
   a janela. É o conserto do degrau, que dava para fazer hoje. */
@media (max-width:1179px){ .adm-side{width:72px;} .adm-side .rotulo, .adm-side .marca-logo, .adm-side .marca-txt{display:none;} .adm-side .marca-conta{flex-direction:column;gap:8px;} .adm-main{padding:0;}
  /* #6618: abaixo de 1180 o rodape do perfil volta ao que era (a quebra e so da barra aberta) */
  .adm-side:not(.recolhido) #perfilSidebar { flex-wrap:nowrap; row-gap:normal; justify-content:normal; }
  .adm-side:not(.recolhido) .perfil-eu { flex:1; } }

/* #4627: O TRILHO TEM DUAS ORIGENS, E SÓ UMA ESTAVA VESTIDA.

   Uma é a classe `.recolhido`, que o botão de hambúrguer liga: ela traz TODAS as
   regras que fazem 64px funcionar (o rodapé do perfil vira coluna, o nome sai de
   cena, o ícone de pessoa aparece, os itens ficam centrados, a barra de status
   some). A outra é a linha do #4232 logo acima: ela põe a barra em 64px SEM ligar
   a classe, e por isso nenhuma daquelas regras valia. A barra ficava estreita e
   crua.

   MEDIDO no banco de ensaio, com a janela em 1100px e sem clicar no hambúrguer:

     .adm-side ........ 64px, overflow hidden
     #perfilSidebar ... clientWidth 39px contra scrollWidth 144px, ainda em linha
     #sair ............ terminava em x=156, ou seja 92px FORA da barra
     #btnSino ......... 50px fora
     11 elementos vazando ao todo (os rótulos da barra de status inclusive)

   Como a barra é `overflow:hidden`, o sino e o SAIR não ficavam só feios: ficavam
   CORTADOS, invisíveis e sem clique. Quem trabalha em MacBook 13 polegadas ou
   iPad deitado vive nessa faixa e perde o botão de sair da conta.

   POR QUE O CORTE DE BAIXO É 641 E NÃO ZERO: abaixo de 640 a barra deixa de ser
   trilho vertical e vira faixa horizontal no rodapé (o bloco de mobile logo
   abaixo). Ali o rodapé do perfil TEM que continuar em linha, e o `display:none`
   da barra de status tiraria informação de quem já está na tela menor. Repetir as
   regras do trilho sem esse piso quebraria o celular para consertar o MacBook.

   A PARIDADE ENTRE AS DUAS ORIGENS É COBRADA POR TESTE
   (`tests/test_4627_trilho_automatico_veste_o_rodape.py`): declaração que entrar
   numa e não na outra reprova. É o que impede o defeito de nascer de novo, já que
   CSS não sabe dizer "vale também quando aquela media query estiver ativa". */
@media (min-width:641px) and (max-width:1179px){
  /* #6641: o rodape do perfil no trilho, foto e selo menores */
  .adm-side #perfilSidebar { flex-wrap:wrap; gap:6px; padding:10px 4px 6px; }
  .adm-side .perfil-central,
  .adm-side .perfil-central #centralAv { width:34px; height:34px; font-size:var(--fs-corpo); }
  .adm-side .perfil-selo { width:17px; height:17px; right:-3px; bottom:-2px; }
  .adm-side .perfil-selo svg { width:10px; height:10px; }
  .adm-side .perfil-eu-nome { font-size:var(--fs-corpo); }
  .adm-side .perfil-eu-papel { font-size:var(--fs-legenda); }
  /* O `!important` é o mesmo da linha do `.recolhido` lá em cima, e pela mesma
     razão: o `#statusBar` nasce com `style="display:flex"` no HTML, e estilo
     inline ganha de qualquer seletor. Sem ele, medido, sobravam 4 elementos
     vazando (os rótulos "Servidor" e "Ana", 12,4px fora da barra de 64px). */
  .adm-side #statusBar { display:none !important; }
  .adm-side .adm-item { justify-content:center; padding:0; width:40px; height:40px; flex:0 0 40px; }
  /* #6619: a gemea do recolhido (o quadrado de 40 centrado entre a borda e a rolagem) */
  .adm-side { padding-left:0; padding-right:10px; }
  .adm-side #menuScroll { margin-right:-10px; align-items:center; scrollbar-gutter:stable; }
  /* #6381: a gemea do recolhido, o trilho tambem nao tem grupo */
  .adm-side .adm-grupo,
  .adm-side .adm-grupo.fechado { display:contents; }
  .adm-side .adm-item[aria-current="true"]::after { display:none; }
  .adm-side .menu-busca,
  .adm-side .menu-busca-ajustes,
  .adm-side .menu-busca-vazio { display:none; }
  #menuLateral .adm-grupo.busca-aberta { display:contents; }
  .adm-side #perfilSidebar { flex-direction:column; padding:10px 2px 4px; }
  .adm-side .msg-badge { top:5px; right:8px; transform:none; min-width:16px; height:16px; font-size:var(--fs-legenda); padding:0 4px; }
}
/* mobile: barra lateral vira faixa fixa no rodapé, conteúdo ganha a tela toda */
@media (max-width:640px){
  .adm{flex-direction:column;}
  /* #4188/#4202: ESTA LINHA (`height:auto`) É O QUE FAZ O CONSOLE ABRIR NO CELULAR.
     O dono: "quando eu acesso pela web do navegador de um celular, ele quebra
     completamente... aconteceu uma catástrofe, preciso acessar pelo celular por
     emergência e não dá para baixar o aplicativo".

     A causa era uma herança de uma linha. O `.adm-side` nasce com `height:100vh`
     (lá em cima, de propósito: no desktop ele é uma coluna cheia com o rodapé de
     perfil colado embaixo). Aqui embaixo ele vira faixa de RODAPÉ, ganha
     `position:fixed; bottom:0; width:100%; z-index:50`, mas a altura nunca era
     desfeita. O resultado é uma faixa de 100% da largura, 100% da ALTURA e por
     cima de tudo: uma cortina de tela cheia. O conteúdo estava lá atrás o tempo
     todo, intacto e inalcançável.

     A prova de que o desenho era este: o `.adm-main` logo abaixo já reserva
     exatamente 76px de rodapé, a altura de uma barra de ícones, não de uma tela.

     `overflow:hidden` da declaração de origem também sai: em faixa horizontal ele
     cortaria os itens que passam da largura, e o `overflow-x:auto` daqui só
     conserta um dos dois eixos. */
  .adm-side{width:100%;flex-direction:row;justify-content:space-around;overflow-x:auto;
    height:auto;overflow-y:visible;
    border-right:none;border-top:1px solid var(--line);padding:6px 4px;gap:2px;
    position:fixed;bottom:0;left:0;z-index:50;}
  /* O rolador interno da lista existe para a coluna alta do desktop. Em faixa de
     rodapé ele viraria um segundo rolador dentro do primeiro, a armadilha do
     #4149, em que o dedo cai no de dentro e o de fora nunca anda. */
  #menuScroll{flex-direction:row;overflow:visible;flex:0 0 auto;}
  .adm-side .marca{display:none;}
  .adm-item{flex-direction:column;gap:3px;padding:6px 8px;font-size:var(--fs-legenda);justify-content:center;}
  .adm-main{padding:0 0 76px;}
  /* #6381: a faixa do rodape segue com todos os itens, sem cabecalho de grupo nem linha */
  .adm-side .adm-cat{display:none;}
  .adm-grupo, .adm-grupo.fechado{display:contents;}
  .adm-grupo .adm-item{padding:6px 8px;}
  .adm-item[aria-current="true"]::after{display:none;}
  .adm-side .menu-busca, .adm-side .menu-busca-ajustes, .adm-side .menu-busca-vazio{display:none;}
  #menuLateral .adm-grupo.busca-aberta{display:contents;}
}

/* ---- swatches de cor (Config > Geral) ---- */
.sw-row { display:flex; gap:10px; align-items:center; flex-wrap:wrap; }
.sw { width:30px; height:30px; border-radius:50%; border:2px solid var(--surface);
  box-shadow:0 0 0 1px var(--line-2); cursor:pointer; padding:0; transition:transform .12s; }
.sw:hover { transform:scale(1.12); }
.sw[aria-pressed="true"] { box-shadow:0 0 0 2.5px var(--brand); transform:scale(1.1); }
/* #5413: o codigo hexadecimal da cor da marca, ao lado das bolinhas (web/js/cor-hex.js) */
.cor-hex { display:flex; align-items:center; gap:8px 10px; flex-wrap:wrap; margin-top:10px; }
.cor-hex__seletor { width:36px; height:36px; padding:2px; border:1px solid var(--line);
  border-radius:var(--r-field); background:var(--surface); cursor:pointer; }
.cor-hex__rotulo { font-size:var(--fs-corpo); color:var(--ink-3); }
.cor-hex__texto { width:120px; font-family:var(--font-mono); text-transform:uppercase; }
.cor-hex__aviso { font-size:var(--fs-corpo-pequeno); color:var(--st-danger-fg); }
.cor-hex__aviso[hidden] { display:none; }

/* chip de filtro selecionado (ex.: filtros de restrição/alergia no cardápio).
   !important porque a base .hs-chip é "unlayered" e venceria a especificidade. */
.hs-chip[aria-pressed="true"] { background:var(--accent) !important; color:var(--accent-fg) !important; border-color:var(--accent) !important; }
.hs-chip[aria-pressed="true"]:hover { background:var(--accent-hover) !important; }

/* trocar foto (Pessoas): badge + no canto do avatar */
.foto-troca { position:relative; cursor:pointer; flex-shrink:0; }
.foto-troca-icone { position:absolute; right:-2px; bottom:-2px; width:20px; height:20px;
  border-radius:50%; background:var(--primary); border:2px solid var(--surface);
  display:flex; align-items:center; justify-content:center; }
.foto-troca:hover .av { filter:brightness(.92); }

/* ---- modal genérico (Cadastrar, ver comunicado, ver publicação) ---- */
/* #4060: SAIU o `backdrop-filter:blur(3px)`.
   Ele obriga o navegador a fotografar e desfocar TUDO o que está atrás do modal.
   Atrás do modal está o console inteiro (uma página enorme), e a conta é refeita a
   cada vez que a janela perde e recupera o foco, que é exatamente o que acontece
   quando o explorador de arquivos do Windows abre e fecha. Resultado medido pelo
   dono: a janela de upload demorava a aparecer e, ao fechar, o Windows tocava o som
   de erro, porque a página tinha parado de responder. O escurecido subiu de .55
   para .62 e o modal continua destacado, sem cobrar o preço do desfoque. */
/* #441 - toda janela no meio da tela; o teto da .hs-modal cabe no respiro e o `safe` volta ao topo se alguma passar da tela */
.hs-modal-bg { position:fixed; inset:0; z-index:200; background:rgba(10,14,22,.62);
  display:flex; align-items:center; align-items:safe center; justify-content:center;
  padding:28px 16px; overflow:auto; animation:hs-fade .15s ease-out; }

/* #4123 e #4121: NONA vez da mesma armadilha (ver a nota do [hidden] no
   tokens.css). O `display:flex` da linha acima e regra NOSSA, e folha do autor
   vence a do navegador: com ela no ar, o atributo `hidden` do HTML parava de
   esconder o modal. As duas telas da Fundacao Comercial marcam os dialogos com
   `hidden` no HTML, entao nasciam com TODOS eles abertos e empilhados por cima
   da pagina -- e nada embaixo recebia clique, porque o overlay cobre a tela
   inteira. Era o "tela completamente quebrada" e o "nao tem acao" do dono.
   O `abrir()` daquelas telas, que fecha um dialogo ao abrir o outro, estava
   certo desde o #3801: ele so mexia no `hidden`, que nao valia nada -- por isso
   o defeito "continuava" depois de ja ter sido corrigido no JavaScript.
   Sem !important: `.hs-modal-bg[hidden]` (0,2,0) ja vence `.hs-modal-bg` (0,1,0).
   `.hs-modal` entra junto porque tambem declara `display`, e a regra do
   tokens.css manda a primitiva entrar na lista no MESMO commit. */
.hs-modal-bg[hidden], .hs-modal[hidden] { display:none; }
/* #6054 - a caixa da janela recebe o foco por programa quando nao ha campo dentro; ela nao e controle e fica sem contorno */
[role="dialog"][tabindex="-1"]:focus-visible { outline:none !important; }

/* #6054 - visor de imagem do console (abrirVisorImagem), escuro nos dois temas: o anel de foco usa --visor-fg, o azul de --focus nao chega a 3:1 aqui */
.hs-visor { position:fixed; inset:0; z-index:9500; background:var(--visor-fundo);
  display:flex; flex-direction:column; --focus:var(--visor-fg); }
.hs-visor-topo { display:flex; align-items:center; gap:8px; padding:12px 16px; flex-shrink:0; }
.hs-visor-titulo { flex:1; min-width:0; color:var(--visor-fg); font-size:var(--fs-corpo); font-weight:700;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.hs-visor-btn { display:inline-flex; align-items:center; gap:6px; height:34px; padding:0 12px;
  border:1px solid rgba(255,255,255,.35); border-radius:999px; background:rgba(255,255,255,.08);
  color:var(--visor-fg); font-family:var(--font); font-size:var(--fs-corpo); font-weight:700; cursor:pointer; }
.hs-visor-btn--icone { padding:0 10px; }
.hs-visor-btn svg { pointer-events:none; }
.hs-visor-palco { flex:1; min-height:0; display:flex; align-items:center; justify-content:center;
  padding:0 16px 22px; }
.hs-visor-img { max-width:100%; max-height:100%; object-fit:contain; border-radius:10px;
  box-shadow:0 14px 44px rgba(0,0,0,.55); }

@keyframes hs-fade { from{opacity:0;} to{opacity:1;} }
.hs-modal { background:var(--surface); border:1px solid var(--line); border-radius:20px;
  box-shadow:var(--sh-2); width:100%; max-width:min(560px,92vw); overflow:hidden;
  display:flex; flex-direction:column; max-height:min(calc(100vh - 56px), calc(100dvh - 56px));
  animation:hs-fade-up .18s ease-out; }
.hs-modal.lg { max-width:min(900px,92vw); }
.hs-modal.xl { max-width:min(1120px,95vw); }
/* #3628: grade larga (lojinha), a tela ocupa a largura disponivel; o 1120px do
   xl deixava 4 colunas e uma barra de rolagem que nao precisava existir. */
.hs-modal.full { max-width:min(1600px,96vw); }
/* #6013: a janela SOB MEDIDA alarga ate o conteudo parar de rolar. Quem escolhe o degrau e
   web/js/janela-sob-medida.js (a mesma lista de larguras, conferida pelo teste do card);
   aqui so mora a largura de cada degrau, para nada virar estilo cravado no elemento.
   O teto real continua sendo a tela: a .hs-modal tem width:100% dentro do fundo, entao
   degrau maior que a tela para na borda do respiro. Abaixo de 641 px o modulo nao mexe. */
@media(min-width:641px){
  .hs-modal.hs-modal--sob-medida[data-largura="640"] { max-width:640px; }
  .hs-modal.hs-modal--sob-medida[data-largura="720"] { max-width:720px; }
  .hs-modal.hs-modal--sob-medida[data-largura="800"] { max-width:800px; }
  .hs-modal.hs-modal--sob-medida[data-largura="880"] { max-width:880px; }
  .hs-modal.hs-modal--sob-medida[data-largura="960"] { max-width:960px; }
  .hs-modal.hs-modal--sob-medida[data-largura="1040"] { max-width:1040px; }
  .hs-modal.hs-modal--sob-medida[data-largura="1120"] { max-width:1120px; }
  .hs-modal.hs-modal--sob-medida[data-largura="1200"] { max-width:1200px; }
  .hs-modal.hs-modal--sob-medida[data-largura="1280"] { max-width:1280px; }
  .hs-modal.hs-modal--sob-medida[data-largura="1360"] { max-width:1360px; }
  .hs-modal.hs-modal--sob-medida[data-largura="1440"] { max-width:1440px; }
}
/* #441 - o topo (titulo e fechar) e o pe nunca encolhem: quando falta altura, quem cede e rola e o corpo */
.hs-modal-top { display:flex; align-items:center; gap:12px; padding:18px 22px; flex-shrink:0;
  border-bottom:1px solid var(--line); }
.hs-modal-top h2 { margin:0; font-size:var(--fs-titulo); font-family:var(--font-display); font-weight:800; flex:1; }
.hs-modal-x { width:34px; height:34px; border-radius:10px; border:none; background:var(--surface-2);
  color:var(--ink-2); cursor:pointer; font-size:var(--fs-titulo); display:flex; align-items:center; justify-content:center; }
.hs-modal-x:hover { background:var(--surface-3); color:var(--ink); }
.hs-modal-body { padding:22px; overflow-y:auto; min-height:0; }
/* #208 - o modal do leitor de QR da casa (web/js/qr-leitor.js), que era estilo inline */
.qr-leitor-video { display:block; width:100%; max-height:320px; object-fit:cover; border-radius:12px;
  border:1px solid var(--line); background:var(--visor-fundo); }
.qr-leitor-ajuda { font-size:var(--fs-corpo); color:var(--ink-3); margin-top:8px; }
/* #5111b: `hs-modal-corpo` e `hs-modal-pe` eram usadas por QUATRO modulos
   (banners-escola, tags-comunicado, comunicado-confirmar-envio e
   canal-comunicado) e NAO EXISTIAM em lugar nenhum do CSS. O efeito era o que o
   dono viu no print: texto colado na borda, sem margem, e o botao do rodape
   encostado a esquerda. Quatro telas com o mesmo defeito, porque nasceram na
   mesma leva.

   `corpo` e apelido de `body` de proposito, e nao um segundo jeito de fazer a
   mesma coisa: renomear em quatro arquivos custaria quatro conflitos no
   monolito por uma diferenca de idioma. O `pe` alinha o rodape a DIREITA, que e
   onde a casa poe acao de modal. */
.hs-modal-corpo { padding:22px; overflow-y:auto; min-height:0; }
.hs-modal-pe { display:flex; justify-content:flex-end; align-items:center; gap:10px; flex-shrink:0;
  padding:14px 22px; border-top:1px solid var(--line); }
.hs-modal-tabs { display:flex; gap:6px; padding:14px 22px 0; }
.hs-modal-tab { flex:1; height:40px; border-radius:11px; border:1px solid var(--line);
  background:var(--surface); color:var(--ink-2); font-weight:700; font-size:var(--fs-corpo); cursor:pointer;
  font-family:var(--font); }
.hs-modal-tab.on { background:var(--primary); color:var(--accent-fg); border-color:var(--primary); }
/* #6147 - celular da régua: até 560px. */
@media(max-width:560px){ .hs-modal-bg{padding:12px;}
  .hs-modal{ max-height:min(calc(100vh - 24px), calc(100dvh - 24px)); } }

/* ============================================================================
   [L1] FUNDACAO RESPONSIVA, breakpoint primario ~920px (cobre 1366x768 @150%
   = ~911px de largura logica, a resolucao mais critica do dono). Uma unica
   media query sistemica que conserta a maior parte das telas SEM tocar layout
   desktop. Tudo usa var() => tema claro e escuro herdam de graca.
   Convive com o @media(max-width:900px) e o (max-width:640px) do index.html:
   920 > 900 > 640, entao as regras mais especificas (menores) sobrescrevem
   estas quando a tela diminui ainda mais. ========================================= */
@media(max-width:920px){
  /* modais: menos respiro no overlay p/ aproveitar a largura util. O teto do modal
     acompanha o padding do overlay (16px topo + 16px base = 32px) para o conjunto
     overlay+modal nunca passar da viewport: assim quem rola e SO o corpo (uma barra),
     sem scroll aninhado. */
  .hs-modal-bg{ padding:16px 12px; }
  .hs-modal{ max-height:min(calc(100vh - 32px), calc(100dvh - 32px)); }
  /* tabelas: densidade menor p/ caber mais coluna antes de precisar rolar */
  .hs-table{ font-size:var(--fs-corpo); }
  .hs-table th, .hs-table td{ padding:7px 6px; }
  /* topo das paginas: padding/gap menores.
     !important p/ vencer a base no <style> inline do index.html, que carrega
     DEPOIS do components.css (mesma especificidade, ordem de fonte posterior). */
  .topo-pagina{ padding:14px 16px !important; gap:10px !important; }
  /* toast de erro rico: nunca mais largo que a tela */
  .hs-toast--erro-rico{ max-width:min(350px,80vw); }

  /* GRIDS NOMEADOS, vencem o grid-template-columns inline (e o style.cssText
     que o JS injeta) via !important. Rebaixa o minmax p/ as colunas quebrarem
     em ~911px em vez de estourar a viewport. */
  #dashMetricas, #dashCabecalho, #dashOper{
    grid-template-columns:repeat(auto-fit,minmax(var(--piso-numero),1fr)) !important; }
  #dashRetiradas, #enfLista, #filaCards{
    grid-template-columns:repeat(auto-fill,minmax(var(--piso-cartao),1fr)) !important; }
  #presLista{ grid-template-columns:repeat(auto-fill,minmax(var(--piso-conteudo),1fr)) !important; }
  #esperaCards{ grid-template-columns:repeat(auto-fill,minmax(var(--piso-conteudo),1fr)) !important; }
  #dashResumoMes, #finResumo{
    grid-template-columns:repeat(auto-fit,minmax(var(--piso-numero),1fr)) !important; }
  #asLista{ grid-template-columns:repeat(auto-fill,minmax(var(--piso-conteudo),1fr)) !important; }
  /* !important pelo mesmo motivo do .topo-pagina: a base (.ac-grid-painel
     minmax 280px) vive no <style> inline do index.html, que carrega depois. */
  .ac-grid-painel{ grid-template-columns:repeat(auto-fit,minmax(var(--piso-cartao),1fr)) !important; }
  /* o "meio" do dashboard (2fr 1fr) empilha numa coluna so */
  #dashMeio{ grid-template-columns:1fr !important; }

  /* #134 Contrato individual: a linha "inicio / dia vencimento / observacao"
     (3 colunas 1.2/.8/1.6fr inline no modal) empilha numa coluna so no estreito,
     em vez de espremer os campos. So <=920px; herda var() => tema claro/escuro iguais. */
  .ctr-linha{ grid-template-columns:1fr !important; }

  /* ==========================================================================
     [L2] FUNDACAO 2, campos, filtros e botoes que estouram a linha.
     Inputs/selects/botoes em barras flex com flex-basis/min-width altos somam
     mais que a viewport em ~911px. Aqui rebaixamos os minimos e deixamos os
     campos quebrarem (wrap) em vez de empurrar a tela. So afeta <=920px;
     tudo herda var() => tema claro e escuro iguais. !important onde precisa
     vencer estilo inline do index.html (style="width:..."/flex inline). ====== */

  /* busca do topo das paginas: encolhe sem sumir */
  .busca-topo{ flex:0 1 auto; min-width:120px; }

  /* busca da sala de espera: ocupa a linha inteira (vence o flex/min/max inline) */
  #esperaBusca{ flex:1 1 100% !important; min-width:120px; max-width:none !important; }

  /* Reajuste em massa (Financeiro): os campos viram flexiveis e quebram.
     O container .rj-barra ja tem flex-wrap:wrap. Os flex-children sao .hs-field
     divs (um deles com width:130px inline), viram flexiveis e crescem juntos.
     Dentro deles, os selects/input com min-width/width inline soltam a largura. */
  .rj-barra > .hs-field{ flex:1 1 140px; min-width:120px; width:auto !important; }
  #rjComp, #rjTurma, #rjTipo, #rjValor{
    min-width:120px !important; width:100% !important; }

  /* botoes com min-width inline alto em barras flex: nao deixa estourar */
  .hs-btn[style*='min-width']{ min-width:110px !important; }

  /* Presenca (topo): a barra usa .topo-pagina; deixa quebrar e os campos
     de largura fixa inline (180/150/240px) viram flexiveis. flex-wrap aqui
     e' aditivo (a base nao tem) e so vale <=920px => nao afeta o desktop. */
  .topo-pagina{ flex-wrap:wrap; }
  #presBusca, #presData, #presTurma{
    width:auto !important; min-width:120px; flex:1 1 140px; }

  /* SLA por pessoa no Inicio: select de 220px fixo => flexivel com teto */
  #dashSlaPessoa{ width:auto !important; max-width:220px; flex:1 1 140px; }

  /* R13: imagens dos cards grandes (Comunicados / News / After) sao geradas
     com height/max-height inline (150/128/120px ou 240/260px no detalhe).
     Em telas menores essas capas ficam altas demais e empurram o texto,
     criando barra de rolagem desnecessaria. Reduz a altura no card e na
     capa do modal de leitura. O !important vence o estilo inline. */
  .card-capa{ height:96px !important; }
  .card-capa-img{ max-height:150px !important; }
  .card-foto-prev{ height:110px; }
}

/* Corpo de comunicado/news com formatação leve (markdown-lite seguro) */
.com-md p { margin:0 0 .6em; }
.com-md p:last-child { margin-bottom:0; }
.com-md ul { margin:.4em 0 .6em; padding-left:1.2em; }
.com-md li { margin:.15em 0; }
.com-md strong { font-weight:700; }
.com-md em { font-style:italic; }

/* Cardapio: area de upload de foto (estado vazio) + miniatura com lixeira */
.card-upload { display:flex; align-items:center; gap:12px; width:100%; text-align:left;
  padding:14px 16px; border:1.5px dashed var(--line-2); border-radius:12px;
  background:var(--surface-2); color:var(--ink-2); cursor:pointer; font-family:var(--font);
  transition:border-color .15s ease, background .15s ease, color .15s ease; }
.card-upload:hover { border-color:var(--primary); background:var(--primary-soft); color:var(--ink); }
/* #6390 - o estado sobre-arraste do E10 (o arquivo em cima do alvo): o mesmo do hover, porque o arraste nao passa o mouse */
.card-upload--sobre { border-color:var(--primary); background:var(--primary-soft); color:var(--ink); }
.card-upload--sobre .card-upload__ico { color:var(--accent-ink,var(--primary)); border-color:var(--primary); }
.card-upload__ico { width:42px; height:42px; border-radius:11px; flex-shrink:0;
  display:flex; align-items:center; justify-content:center;
  background:var(--surface); border:1px solid var(--line); color:var(--ink-3); }
.card-upload:hover .card-upload__ico { color:var(--accent-ink,var(--primary)); border-color:var(--primary); }
.card-upload__ico svg { display:block; }
.card-upload__txt { display:flex; flex-direction:column; gap:2px; font-size:var(--fs-corpo); font-weight:700; line-height:1.2; }
.card-upload__txt small { font-size:var(--fs-corpo-pequeno); font-weight:500; color:var(--ink-3); }

.card-foto-prev { position:relative; width:100%; height:150px; border-radius:12px;
  border:1px solid var(--line); background:var(--surface-2) center/cover no-repeat; overflow:hidden;
  margin-bottom:16px; }  /* respiro entre a miniatura e o botao de publicar */
.card-foto-prev__rem { position:absolute; top:8px; right:8px; width:34px; height:34px;
  border-radius:9px; border:none; cursor:pointer; display:flex; align-items:center; justify-content:center;
  background:rgba(15,20,26,.62); color:#fff; backdrop-filter:blur(2px);
  transition:background .15s ease; }
.card-foto-prev__rem:hover { background:rgba(220,38,38,.92); }
.card-foto-prev__rem svg { display:block; }

/* #6082 - A FOTO DA REFEICAO E LARGA, E O FRAME TEM DE SER IGUAL A ELA.
   Ela nasce 1536 x 672 porque o pedido ao Gemini leva aspectRatio "21:9"
   (backend/services/cardapio_imagem.py, PROPORCAO). Com altura fixa mais
   object-fit:cover, o frame mostrava so a faixa do meio: a escola pagava a
   imagem inteira e via um terco dela. Mesma proporcao nos TRES lugares por onde
   a foto passa (previa, confirmacao e card publicado) e o corte deixa de
   existir. Mudar a PROPORCAO la pede mudar o 1536/672 daqui. */
.card-foto-prev--refeicao { height:auto; aspect-ratio:1536/672; }
.card-foto-refeicao { display:block; width:100%; aspect-ratio:1536/672;
  object-fit:cover; border-radius:12px; background:var(--surface-3); }
.card-foto-refeicao--lista { margin-top:10px; border-radius:10px; }

/* ============================================================================
   DS 2.0, classes NOVAS da "Biblioteca de Componentes 2.0" (27/07, #3789).
   Regra deste update: classe nova ENTRA, nenhuma sai, nenhuma muda de cara.
   O estudo por componente (o que diverge e o risco) vive em
   web/pd-redesign-ds2.html (#3792).
   ============================================================================ */

:focus-visible,
.hs-checkbox input:focus-visible + .hs-checkbox-box,
.hs-switch input:focus-visible + .hs-switch-trilho,
.hs-radio input:focus-visible + .hs-radio-ponto {
  outline:2px solid var(--focus) !important;
  outline-offset:2px !important;
}
/* o contorno do botão outline vive num box-shadow inset, o foco COMPÕE com ele
   em vez de apagá-lo */
.hs-btn--outline:focus-visible {
  box-shadow: inset 0 0 0 1.5px var(--border-strong),
              var(--anel-foco, 0 0 0 3px color-mix(in srgb, var(--brand) 18%, transparent));
}
/* a11y da ficha F2: as ações que o hover revela precisam aparecer também para
   quem navega por Tab, sem isto o teclado nunca vê reagir/responder/apagar */
.msg-linha:focus-within .msg-acoes { opacity:1; }

/* Botão perigo (lote 1, decisão 2, aprovada; faltava nascer no código).
   Perigo é STATUS: o mesmo vermelho em toda escola, nunca segue o accent.
   Destrutivo de verdade = esta variante + confirmação em modal. */
.hs-btn--danger { background: var(--danger-solid); color: var(--danger-solid-fg); }
.hs-btn--danger:hover { background: color-mix(in srgb, var(--danger-solid) 84%, #000); }

/* #5397: botao desabilitado (ui.ocupado, ou a trava dos tres botoes da Ana em
   web/js/comunicado-ana-redacao.js) precisa PARECER travado, sem isto a cor
   continua igual e a pessoa acha que ainda pode clicar. */
.hs-btn:disabled { opacity: .55; cursor: not-allowed; }
/* #4678 - o botao que e link (a). O sublinhado do navegador nao e parte do botao; as paginas que ja tinham isto o escreviam no atributo. */
a.hs-btn { text-decoration: none; }

/* Botão sm oficial (lote 1, decisão 5): console e barra densa, SÓ ponteiro.
   Em alvo de toque (app/mobile) é md ou nada, 36px não passa os 44px de toque. */
.hs-btn--sm { height: var(--h-btn-sm, 36px); padding: 0 14px; font-size: var(--fs-corpo); }
/* card 339: as alturas que as telas escreviam na mao no botao, agora por classe, e o botao que nao quebra a linha */
.hs-btn--a38 { height: 38px; }
.hs-btn--a40 { height: 40px; }
.hs-btn--uma-linha { white-space: nowrap; }
.aj-ver-todas { margin-top: 10px; }   /* card 339: o botao de ver todas as perguntas da Central de ajuda */
/* Botao so de icone (4748, 06/09): quadrado, sem texto visivel; o nome vai em
   aria-label e title. */
.hs-btn--icone { width: var(--h-btn-sm, 36px); padding: 0; justify-content: center; }
.hs-btn--icone svg { width: 17px; height: 17px; flex-shrink: 0; }

/* Botão-ícone unificado (sugestão do lote 1: unifica os "3 primos" de raio cru,
   modal-x 10px, msg-acao 8px, toast-x 7px, para item NOVO; os primos
   continuam como estão). Tamanhos da ficha F2: 22 toast · 28 linha · 34 modal ·
   36 topbar. Neutro por definição: nunca colorir com o accent para "destacar". */
.hs-icon-btn { display:inline-flex; align-items:center; justify-content:center;
  width:28px; height:28px; padding:0; border:none; cursor:pointer;
  border-radius:var(--r-btn); background:var(--surface-2); color:var(--text-3);
  transition:background .14s, color .14s; flex-shrink:0; }
.hs-icon-btn:hover { background:var(--surface-3); color:var(--text-1); }
.hs-icon-btn--22 { width:22px; height:22px; }
.hs-icon-btn--34 { width:34px; height:34px; }
.hs-icon-btn--36 { width:36px; height:36px; }
.hs-icon-btn--contorno { background:transparent; box-shadow:inset 0 0 0 1px var(--border-strong); }
.hs-icon-btn--perigo:hover { background:var(--st-danger-soft); color:var(--st-danger-fg); }

/* Interruptor (ficha F7: o toggle existia em 4 telas SEM classe). Ligado segue
   o accent, seleção é um dos 3 alvos da cor da escola; desligado é neutro.
   Marcação: <label class="hs-switch"><input type="checkbox">
   <span class="hs-switch-trilho"></span><span>rótulo</span></label> */
.hs-switch { position:relative; display:inline-flex; align-items:center; gap:10px; cursor:pointer;
  user-select:none; font-size:var(--fs-corpo); color:var(--ink); }
.hs-switch input { position:absolute; opacity:0; width:0; height:0; }
.hs-switch-trilho { width:40px; height:22px; flex-shrink:0; border-radius:999px;
  background:var(--surface-3); border:1.5px solid var(--line-2); position:relative;
  transition:background .15s, border-color .15s; }
.hs-switch-trilho::after { content:""; position:absolute; top:2px; left:2px;
  width:15px; height:15px; border-radius:50%; background:var(--surface);
  box-shadow:var(--sh-1); transition:transform .15s, background .15s; }
.hs-switch input:checked + .hs-switch-trilho { background:var(--accent); border-color:var(--accent); }
.hs-switch input:checked + .hs-switch-trilho::after { transform:translateX(18px); background:var(--accent-fg); }
.hs-switch input:disabled + .hs-switch-trilho { opacity:.45; cursor:not-allowed; }

/* ---- compositor da Rede social (#3702, devolução 27/07) ----
   O dono pediu "cara de Facebook, usar o que é mais comum no mercado": um campo
   grande sem moldura no topo, e o ALCANCE como pílula discreta ao lado do autor
   (não um campo rotulado a mais). O <select> do alcance é trocado pelo dropdown
   temado (_upgradeSelect), por isso a regra alcança as DUAS marcações, e o
   nativo fica embrulhado num <span>, nunca com o display alterado na mão
   (pegadinha 4 da skill design-system). */
.rs-comp-texto { width:100%; border:0; background:transparent; resize:vertical;
  min-height:120px; padding:2px; color:var(--ink); font-family:var(--font);
  font-size:var(--fs-subtitulo); line-height:1.55; outline:none; }
.rs-comp-texto::placeholder { color:var(--ink-3); }
.rs-alcance { display:inline-block; margin-top:3px; }
.rs-alcance .hs-select, .rs-alcance select {
  height:28px; padding:2px 10px; font-size:var(--fs-corpo); border-radius:999px;
  background:var(--surface-2); }

/* #4759: comentario comprido vazava o cartao (palavra sem espaco, um link
   colado, nao quebra sozinha) e o botao apagar, sem flex-shrink:0, era esmagado
   e a palavra montava em cima do texto. O molde e a fila de moderacao (#4056),
   cujo botao ja segura o proprio tamanho. */
.rs-coment-texto { overflow-wrap:anywhere; }
.rs-coment-apagar { flex-shrink:0; }

/* Radio (ficha E6: existia nas telas, sem classe; espelha o .hs-checkbox).
   Marca em ACCENT de propósito: ESCOLHA segue a cor da escola; o tique verde do
   checkbox é CONFIRMAÇÃO, exceção confirmada na revisão do lote 2 (rev-131). */
.hs-radio { position:relative; display:inline-flex; align-items:center; gap:10px; cursor:pointer;
  user-select:none; font-size:var(--fs-corpo); color:var(--ink); }
.hs-radio input { position:absolute; opacity:0; width:0; height:0; }
.hs-radio-ponto { width:20px; height:20px; flex-shrink:0; border-radius:50%;
  border:1.5px solid var(--line-2); background:var(--surface); position:relative;
  transition:border-color .14s; }
.hs-radio-ponto::after { content:""; position:absolute; inset:4px; border-radius:50%;
  background:var(--accent); transform:scale(0); transition:transform .14s; }
.hs-radio input:checked + .hs-radio-ponto { border-color:var(--accent); }
.hs-radio input:checked + .hs-radio-ponto::after { transform:scale(1); }
.hs-radio input:disabled + .hs-radio-ponto { opacity:.45; cursor:not-allowed; }

/* Campo com erro (ficha E4: hoje cada tela pinta a borda de erro inline).
   Erro é status: borda e texto de ajuda em perigo, nos dois temas. */
.hs-field--erro .hs-input, .hs-field--erro .hs-textarea, .hs-field--erro .hs-select {
  border-color: var(--st-danger-fg); }
.hs-field--erro .hs-input:focus, .hs-field--erro .hs-textarea:focus, .hs-field--erro .hs-select:focus {
  border-color: var(--st-danger-fg);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--st-danger-fg) 18%, transparent); }
.hs-field--erro .hs-help { color: var(--st-danger-fg); }

/* Segmented control (ficha F5: sem classe no código; lote 1, decisão 6,
   seleção é alvo do accent, então a pastilha ativa segue a cor da escola). */
.hs-seg { display:inline-flex; gap:2px; padding:3px; background:var(--surface-2);
  border:1px solid var(--line); border-radius:var(--r-btn); }
.hs-seg-btn { border:none; background:none; font-family:var(--font); font-size:var(--fs-corpo);
  font-weight:600; color:var(--ink-2); padding:6px 12px; cursor:pointer;
  border-radius:calc(var(--r-btn) - 2px); transition:background .14s, color .14s;
  white-space:nowrap; }
.hs-seg-btn:hover { color:var(--ink); }
.hs-seg-btn[aria-pressed="true"], .hs-seg-btn[aria-selected="true"] {
  background:var(--accent); color:var(--accent-fg); }
/* #4321: na faixa "uma coluna" da régua (#4233, até 560px) a bandeja QUEBRA.
   O motivo é mecânico, não estético: as pastilhas são `white-space:nowrap`, e
   uma linha flex sem quebra tem largura mínima igual à SOMA delas. As três abas
   da Galeria somavam 365px, mais que os 344px úteis de um aparelho de 360, e
   por isso a bandeja se recusava a encolher e empurrava a barra para 381px de
   rolagem lateral. Com a quebra, a largura mínima passa a ser a da MAIOR
   pastilha (168px) e a bandeja cabe. Acima de 560 nada muda: sem falta de
   espaço não há quebra. */
@media (max-width:560px) { .hs-seg { flex-wrap:wrap; } }

/* #4321 (10/08), barra de paginação ("Anterior · Página 1 de 3 · Próxima").
   Ela só existe quando a lista passa de uma página: o JS escreve
   `barra.hidden = lista.length <= porPagina`. Com `display:flex` no `style=""`
   esse `hidden` não valia nada, e a barra ficava no ar em lista de 3 nomes,
   com "Página 1 de 1" e os dois botões desligados, um controle que não
   controla nada (medido: 296x36 numa tela de 360). O display mora numa classe
   para a regra abaixo poder desligar. A margem de cima entra junto porque esta
   barra vive sempre colada embaixo da lista que ela pagina. */
.hs-paginacao { display:flex; align-items:center; gap:8px; margin-top:10px; }
.hs-paginacao[hidden] { display:none; }
/* #5758: rodape de cartao com a acao principal a esquerda e a paginacao a direita, na
   mesma linha. Em tela estreita a paginacao desce inteira. */
.hs-rodape-acoes { display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin-top:12px; }
.hs-rodape-acoes > .hs-paginacao { margin-top:0; margin-left:auto; }

/* Grupo de ações na barra do topo (#4050). Mesma bandeja do .hs-seg, fundo
   surface-2, borda line, raio de botão, só que segurando botões de verdade em
   vez de pastilhas de seleção. Nasceu no Financeiro: 10 botões enfileirados sem
   hierarquia nenhuma; agora eles vêm em blocos rotulados (o que custa · o que a
   escola configura · o que se faz hoje), e o olho acha o botão pelo grupo.
   O rótulo é texto, não ícone: grupo sem nome é só uma caixa. */
.hs-grupo-acoes { display:inline-flex; align-items:center; gap:6px; padding:4px 8px 4px 10px;
  background:var(--surface-2); border:1px solid var(--line); border-radius:var(--r-btn);
  flex-wrap:wrap; }
.hs-grupo-acoes > .hs-rotulo-grupo { font-size:var(--fs-legenda); font-weight:800; letter-spacing:.04em;
  text-transform:uppercase; color:var(--ink-3); white-space:nowrap; }
.hs-grupo-acoes > .hs-btn { height:36px; }
@media (max-width:900px) {
  /* Em tela estreita a bandeja vira uma linha só: o rótulo ocupa a largura toda
     e os botões quebram embaixo dele, em vez de espremer o texto do grupo.
     #4147: `:not(--menu)`, isto vale para a BANDEJA ABERTA (rótulo + botões de
     verdade), que precisa da linha inteira. O grupo-MENU é só um gatilho de
     ~53px; esticá-lo para 100% empurrava a engrenagem para uma segunda linha e
     era o que sobrava de altura na Secretaria depois do #4229 (medido: 144px de
     barra em 768, contra 75px com o gatilho no seu tamanho). */
  .hs-grupo-acoes:not(.hs-grupo-acoes--menu) { width:100%; }
  .hs-grupo-acoes > .hs-rotulo-grupo { width:100%; }
}
/* #4065: o grupo vira LISTA SUSPENSA, o pedido do dono era menu, não bandeja
   aberta (a bandeja esmagava o título da página). O gatilho leva o nome do
   grupo; o painel guarda os MESMOS botões (id e handler intactos), empilhados.
   `[hidden]{display:none}` é obrigatório: o display:flex do painel venceria o
   atributo hidden e o menu nasceria aberto (mesma lição do data-perm). */
.hs-grupo-acoes--menu { position:relative; padding:0; background:transparent; border:0; }
.hs-grupo-acoes--menu > .hs-menu-gatilho { height:42px; }
.hs-menu-seta { font-size:var(--fs-legenda); opacity:.75; margin-left:2px; }
/* #5727: engrenagem que leva direto a uma tela (sem menu), com o tamanho da engrenagem
   dos menus de acoes para as duas parecerem a mesma peca. */
.hs-engrenagem-solta { height:42px; }
.hs-menu-lista { position:absolute; top:calc(100% + 6px); left:0; z-index:120;
  display:flex; flex-direction:column; gap:6px; padding:8px; min-width:232px;
  background:var(--surface); border:1px solid var(--line); border-radius:var(--r-btn);
  box-shadow:0 10px 28px rgba(10,14,22,.18); }
.hs-menu-lista[hidden] { display:none; }
/* #4147: TETO DE ALTURA DO PAINEL, pelo mesmo motivo do teto da barra, só que
   no outro eixo. Com a engrenagem única o Financeiro passou a guardar NOVE ações
   e três títulos: 574px de painel, medidos. Numa tela de 640px de altura (o
   celular do #4202, que precisa abrir "por emergência"), um painel desses nasce
   colado no topo e termina fora da tela, e a barra é `sticky`, a pessoa não
   consegue rolar até o fim dele. O `min()` resolve os dois lados: no desktop
   (1024 de altura) o teto é 620px e o painel do Financeiro cabe inteiro, sem
   rolador nenhum; no celular ele vira 70% da altura e rola por dentro. */
.hs-menu-lista { max-height:min(70vh, 620px); overflow-y:auto; }
.hs-menu-lista > .hs-btn { width:100%; justify-content:flex-start; text-align:left; }
/* #4229: menu ANCORADO À DIREITA. No Financeiro os menus ficam no começo da
   barra e o painel cabe abrindo para a direita (`left:0`). Na Secretaria a
   engrenagem é o ÚLTIMO item, colada na borda: um painel de 232px partindo da
   esquerda de um gatilho de ~53px vazaria ~180px para fora da tela e nasceria
   uma barra de rolagem horizontal, que é proibida em qualquer largura. Aqui o
   painel alinha a borda DIREITA com a do gatilho e cresce para dentro. */
.hs-menu-lista--dir { left:auto; right:0; }
/* #441 - menu no PE de uma janela abre para CIMA: a .hs-modal corta o que passa da borda de baixo */
.hs-menu-lista--cima { top:auto; bottom:calc(100% + 6px); }
/* …e agora em TODA largura. Havia aqui um `@media (max-width:900px){ left:0;
   right:auto }`, escrito porque abaixo de 900 o grupo esticava na barra inteira
   e o gatilho ia parar na ponta esquerda, longe de um painel colado à direita.
   O #4147 desfez a CAUSA (o grupo-menu não estica mais, ver `:not(--menu)` logo
   acima), então some também o remendo: o painel sai sempre da direita do gatilho
   e cresce para dentro da tela. Conta do pior caso, celular de 375px: a barra
   tem 375-32=343px úteis, o painel pede 232px a partir da borda direita, sobram
   111px de folga. Nenhuma largura gera rolagem horizontal. */
/* #4320: a conta acima só fecha se o gatilho ESTIVER na borda direita, e essa
   parte estava sendo dada de graça. Quando a barra QUEBRA de linha, a última
   linha começa pela esquerda e o gatilho para no meio dela; o painel, ancorado
   pela direita do gatilho, sai pela esquerda da tela. Medido em Pessoas a 360px
   (barra de três linhas por causa do campo de busca): painel de 232px nascendo
   em x=-19. A Secretaria estava a 22px de cair no mesmo.
   `margin-left:auto` diz o que o #4147 já dizia em palavras, a engrenagem é a
   ÚLTIMA peça da barra, colada na borda, e passa a dizer também na linha que
   sobrou. Só na faixa "uma coluna" (régua do #4233): acima dela o bloco do
   título é `flex:1` e já come a folga toda, então a margem automática recebe
   zero e o desktop não sente nada. */
@media (max-width:560px) { .topo-pagina > .hs-grupo-acoes--menu { margin-left:auto; } }

/* ============================================================================
   #4147: A BARRA DE TÍTULO TEM TETO DE ALTURA (a régua da ENGRENAGEM ÚNICA)

   O pedido do dono, em 09/08: ação principal à mostra, e uma engrenagem que
   guarda todo o resto. O teto de altura sai de DUAS coisas, e as duas precisam
   valer, uma sozinha não segura:

   (1) POUCOS ITENS. Com título + ação principal + engrenagem a barra não tem o
       que empurrar para uma segunda linha. Isso é marcação, não CSS, e quem
       guarda é o teste `tests/test_4147_4196_engrenagem_unica.py`.

   (2) O TÍTULO NÃO CRESCE PARA BAIXO. Esta parte é CSS, e era o defeito
       invisível: o bloco do título é `flex:1;min-width:0`, ou seja, é ele quem
       cede quando os botões não cabem. Espremido a ZERO, o `h1` (nowrap) some,
       mas a linha de descrição continua quebrando, uma palavra por linha, e
       a barra fica ALTA em vez de estreita. Medido na Biblioteca em 1280px:
       o bloco do título com 0px de largura e 267px de ALTURA, barra de 300px.
       Com o corte por reticências a mesma barra dá 79px.

   Vale para as 35 telas que têm `.topo-pagina`, inclusive as que ainda não
   ganharam engrenagem, é o teto que o cartão pede "em nenhuma largura".
   ============================================================================ */
.topo-pagina h1 { overflow:hidden; text-overflow:ellipsis; }
/* #4758 (25/08, ordem do dono): "Quebre o texto em duas linhas e vamos ver o que
   a QA diz". A frase ERA uma linha só com reticências, e sumia inteira em tela
   estreita. Agora ela quebra, no máximo em DUAS linhas.
   O TETO DE ALTURA DO #4147 NÃO CAIU, ele só trocou de mecanismo: o perigo nunca
   foi a frase quebrar, foi ela quebrar SEM LIMITE. O bloco do título é
   `flex:1;min-width:0`, ou seja, é ele quem cede quando os botões não cabem, e
   espremido a zero a frase quebrava uma palavra por linha (267px medidos na
   Biblioteca em 1280). O `line-clamp:2` corta na segunda linha em qualquer
   largura, então o pior caso passou de 267px para duas linhas de texto.
   O `-webkit-` continua escrito porque é o nome que TODO navegador entende hoje;
   o `line-clamp` sem prefixo vai junto para o dia em que o prefixado sair. */
.topo-pagina .sub { display:-webkit-box; -webkit-box-orient:vertical;
  -webkit-line-clamp:2; line-clamp:2; overflow:hidden; }

/* #4147: TÍTULO DE SEÇÃO dentro da engrenagem. Quando um menu só junta 3 ou 4
   ações, a lista limpa basta. Quando ele junta as NOVE do Financeiro, que antes
   moravam em três menus nomeados (#4065), o nome do grupo é a única coisa que
   faz o olho achar "Gerar mensalidades" sem ler as nove. O título é texto, não
   ícone, grupo sem nome é só uma caixa (mesma lição do .hs-rotulo-grupo).
   O primeiro não leva respiro em cima: ele já encosta no padding do painel. */
.hs-menu-titulo { font-size:var(--fs-legenda); font-weight:800; letter-spacing:.04em;
  text-transform:uppercase; color:var(--ink-3); padding:6px 8px 2px; }
.hs-menu-titulo + .hs-btn { margin-top:0; }
.hs-menu-lista > .hs-menu-titulo:first-child { padding-top:2px; }
.hs-menu-titulo[hidden] { display:none; }

/* Badge neutra de contagem (sugestão do lote 3: separar "tem novidade",
   neutro, de "tem problema", vermelho; a .msg-badge segue como está). */
.hs-badge { display:inline-flex; align-items:center; justify-content:center;
  min-width:18px; height:18px; padding:0 5px; border-radius:999px;
  background:var(--surface-3); color:var(--text-2); font-size:var(--fs-legenda);
  font-weight:800; line-height:1; }
.hs-badge--accent { background:var(--accent); color:var(--accent-fg); }
.hs-badge--perigo { background:var(--danger-solid); color:var(--danger-solid-fg); }

/* ============================================================================
   .hs-tag: A ETIQUETA DE AVISO (#4621, desenho do dono em 24/08)

   POR QUE ELA PRECISOU NASCER. A casa tinha duas peças parecidas e nenhuma
   servia: a `.hs-badge` acima é CONTADOR (18px, redonda, para "3 novas"), e a
   `.hs-chip` do tokens.css é BOTÃO DE FILTRO (30px, clicável), e no Cardápio ela
   já vive três linhas acima, nos filtros "Todos / Restrição / Alergia". Vestir
   um aviso de chip faria a etiqueta parecer botão, e o dono clicaria nela.

   A ETIQUETA NUNCA DEPENDE SÓ DA COR. Ela leva sempre a PALAVRA do tipo
   (Alergia, Restrição, Proibição): cor sozinha carregando o significado é o que
   a régua de acessibilidade proíbe, e era exatamente o defeito que abriu o card
   (o aviso era uma linha de texto de 12px colorido, nada mais).

   A COR VEM POR VARIÁVEL, não por regra por elemento. Cada variante só troca
   `--tag-fg` e `--tag-soft`; como custom property herda, pôr a variante na LINHA
   pinta a etiqueta e a frase de uma vez, com uma classe só. É o que permite a
   mesma peça servir a Biblioteca (#4622) sem reescrever nada aqui.
   ============================================================================ */
.hs-tag {
  display:inline-flex; align-items:center; gap:6px;
  /* No DEV as 234 linhas desta tela são ficha em TEXTO LIVRE (medido em 24/08 pelo
     próprio /api/cardapio/restricoes), e texto livre é frase inteira, não "Amendoim":
     "Sem leite e derivados. Substituir por bebida vegetal." Sendo `inline-flex`, sem
     teto a pílula acompanha o conteúdo e passa da coluna, criando rolagem horizontal. */
  max-width:100%;
  padding:3px 10px; border-radius:var(--r-chip);
  /* #5075 - a cor NÃO é mais declarada aqui dentro (declaração no próprio elemento vence herança e apagava a cor da... */
  background:var(--tag-soft, var(--st-neutral-soft)); color:var(--tag-fg, var(--st-neutral-fg));
  border:1px solid color-mix(in srgb, var(--tag-fg, var(--st-neutral-fg)) 38%, var(--tag-soft, var(--st-neutral-soft)));
  font-size:var(--fs-corpo-pequeno); font-weight:800; line-height:1.45;
  cursor:default;                      /* não é botão: o cursor tem que dizer isso */
}
/* A etiqueta do TIPO tem largura mínima para as três empilharem alinhadas, e é o
   que faz a coluna de cores ser lida de cima a baixo num relance, em vez de
   serrilhada. `flex-shrink:0` porque pílula espremida quebra o texto dentro. */
.hs-tag--tipo { min-width:92px; justify-content:center; flex-shrink:0; }
/* A frase que explica o aviso mora na MESMA linha da etiqueta (regra do #4622:
   "tag e texto ao lado", nunca texto embaixo). Ela é a que pode quebrar. */
.hs-tag--frase { flex:1 1 200px; justify-content:flex-start; text-align:left;
  font-weight:500; padding:3px 12px;
  /* A frase é texto que uma FAMÍLIA digitou na ficha: pode vir uma palavra
     enorme sem espaço. Sem isto ela empurraria a pílula para fora da coluna e
     criaria rolagem horizontal, que é proibida em qualquer largura. */
  overflow-wrap:anywhere; }
.hs-tag--frase b { font-weight:800; text-transform:uppercase;
  letter-spacing:.02em; margin-right:2px; }

.hs-tag-linha { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.hs-tag-lista { display:flex; flex-direction:column; gap:5px; margin-top:6px; }

/* As variantes. Valem na etiqueta solta e na linha inteira (a herança faz o
   resto), e todas saem de token: nenhum hex mora aqui. */
.hs-tag--alergia,   .hs-tag-linha--alergia   { --tag-fg:var(--st-danger-fg);  --tag-soft:var(--st-danger-soft); }
.hs-tag--restricao, .hs-tag-linha--restricao { --tag-fg:var(--st-warning-fg); --tag-soft:var(--st-warning-soft); }
.hs-tag--proibicao, .hs-tag-linha--proibicao { --tag-fg:var(--st-veto-fg);    --tag-soft:var(--st-veto-soft); }
.hs-tag--neutro,    .hs-tag-linha--neutro    { --tag-fg:var(--st-neutral-fg); --tag-soft:var(--st-neutral-soft); }

/* Em tela estreita a frase desce para baixo da etiqueta por falta de espaço: aí
   ela ocupa a linha toda, em vez de virar uma coluna magra de duas palavras.
   560px é a quebra "uma coluna" da régua do #4233, não um número inventado: a
   lista de cortes de largura da casa tem 3 números oficiais, e o estudo existe
   justamente porque alguém sempre acrescenta o décimo terceiro. */
@media (max-width:560px) { .hs-tag--frase { flex:1 1 100%; } }

/* ============================================================================
   .cd-restr, O AVISO ALIMENTAR EM TEXTO (#4901, rollback pedido em 01/09)

   O dono pediu de volta o modelo antigo: "volte para os textos escrito em
   laranja para restrição e vermelho para alergia". As pílulas .hs-tag acima
   continuam existindo para quem as use, mas o Cardápio voltou ao texto.

   POR QUE O ANTERIOR SAIU CINZA, e fica escrito porque o defeito é sutil e
   volta fácil: o JS aplicava `hs-tag--tipo` na etiqueta e a variante de cor
   ficava na linha-pai (`hs-tag-linha--alergia`). Só que `.hs-tag` declara
   `--tag-fg` NELA MESMA, e em CSS declaração própria vence herança: a etiqueta
   lia sempre o neutro. As cores estavam certas no arquivo e nunca chegaram à
   tela.

   A COR NUNCA CARREGA O SIGNIFICADO SOZINHA: a linha abre com a palavra do
   nível em negrito. Era a razão que criou as pílulas em 24/08, e ela continua
   valendo sem elas.
   ============================================================================ */
.cd-restr-lista { display:flex; flex-direction:column; gap:4px; margin-top:5px; }
.cd-restr {
  font-size:var(--fs-corpo-pequeno); line-height:1.5; color:var(--ink-2);
  /* Ficha é texto que a família digitou: palavra longa sem espaço não pode
     empurrar a coluna e criar rolagem horizontal. */
  overflow-wrap:anywhere;
}
.cd-restr b { font-weight:700; }
.cd-restr--alergia   { color:var(--st-danger-fg); }
.cd-restr--restricao { color:var(--st-warning-fg); }
.cd-restr--proibicao { color:var(--st-veto-fg); }


/* Ficha F4 (link), "sublinhado no hover é obrigatório: cor sozinha não basta".
   Metade da ficha, de propósito: a outra metade ("o link passa a seguir o accent")
   é DÍVIDA A CORRIGIR na própria Biblioteca e, no carbono, deixaria o link com a
   mesma cor do texto, some a pista de que é clicável. Fica registrado, não feito. */
.ds2 a:hover { text-decoration: underline; }

/* Regra do dono, medida em toda entrega: zero rolagem horizontal. A imagem, a
   tabela e o bloco de código são os três que estouram a coluna nas páginas de
   documentação, aqui eles passam a caber. A tabela larga rola DENTRO do
   próprio bloco, que é a saída que a Biblioteca dá em vez de rolar a página. */
.ds2 img, .ds2 svg, .ds2 video, .ds2 canvas { max-width: 100%; }
.ds2 pre { max-width: 100%; overflow-x: auto; }
/* Tabela de documentação: medi 3 páginas da Fundação estourando a tela em 1280px
   (seguranca-codigo +915px, integracao-omie +292px, relatorio-q4 +85px), sempre
   uma tabela com célula de texto sem espaço (caminho de arquivo, JSON, hash).
   `overflow-wrap:anywhere` deixa a célula quebrar e a tabela caber; sem ele o
   navegador calcula a largura mínima pela maior palavra e empurra a página toda. */
.ds2 table { max-width: 100%; }
.ds2 th, .ds2 td { overflow-wrap: anywhere; }

/* #3794: Modelos prontos de certificado e timbrado (Config › Impressão).
   O dono pediu os templates DENTRO do sistema, não numa galeria com download
   e reenvio manual. Cada cartão traz a miniatura do próprio desenho que o
   backend gera, já na cor da escola, a prévia não pode mentir sobre o que sai
   na impressão. Cartão inteiro é botão: mira grande, um clique só. */
/* #3922: grid-auto-rows:1fr iguala a ALTURA de todos os cartões (a descrição de
   1 linha vs 2 deixava cada um de um tamanho); span com flex:1 empurra o rótulo
   "Aplicar" para o pé do cartão, todos alinhados e com respiro (era colado). */
.imp-modelos { display:grid; grid-template-columns:repeat(auto-fill,minmax(var(--piso-numero),1fr)); grid-auto-rows:1fr; gap:12px; }
.imp-modelo { display:flex; flex-direction:column; gap:6px; text-align:left; cursor:pointer;
  background:var(--surface); border:1px solid var(--line); border-radius:12px; padding:10px;
  font:inherit; color:inherit; transition:border-color .15s, box-shadow .15s, transform .15s; }
.imp-modelo:hover { border-color:var(--accent); box-shadow:var(--sh-1); transform:translateY(-1px); }
.imp-modelo:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
.imp-modelo svg { border:1px solid var(--line); }
.imp-modelo b { font-size:var(--fs-corpo); color:var(--ink); }
.imp-modelo span { font-size:var(--fs-corpo-pequeno); color:var(--ink-3); line-height:1.4; flex:1; }
.imp-modelo i { font-style:normal; margin-top:auto; padding-top:6px; justify-content:center; pointer-events:none; }
@media (prefers-reduced-motion: reduce) { .imp-modelo { transition:none; } .imp-modelo:hover { transform:none; } }

/* #3922: as 3 peças (timbrado A4, widescreen e fundo do certificado) agrupadas
   no topo da guia, lado a lado, cada uma num cartão igual ao vizinho, os
   botões Enviar/Gerar na mesma posição em todas (antes eram 3 campos empilhados
   com botão em altura diferente). A seção de Modelos prontos, logo abaixo,
   ganha divisória para as duas partes não parecerem uma coisa só. */
.imp-pecas { display:grid; grid-template-columns:repeat(auto-fit,minmax(var(--piso-cartao),1fr)); gap:14px; margin-bottom:14px; }
.imp-pecas .hs-field { border:1px solid var(--line); border-radius:12px; padding:12px; margin-bottom:0; }
#impModelos { margin-top:18px; padding-top:16px; border-top:1px solid var(--line); }

/* =====================================================================
   #3794: as microanimações aprovadas pelo dono (28/07). Todas param
   sozinhas em prefers-reduced-motion, no bloco no fim desta seção.
   ===================================================================== */

/* 1) Esqueleto de carregamento: o desenho da tabela chega antes do dado.
      Cinza que pulsa devagar (1.4s), rápido demais vira estroboscópio. */
.hs-skel { display:flex; flex-direction:column; gap:10px; padding:4px 0; }
.hs-skel-linha { display:flex; gap:12px; align-items:center; }
.hs-skel-linha span { height:12px; border-radius:999px; background:var(--surface-3);
  animation:hs-skel-pulsa 1.4s ease-in-out infinite; }
.hs-skel-linha:nth-child(2n) span { animation-delay:.15s; }
.hs-skel-linha:nth-child(3n) span { animation-delay:.3s; }
@keyframes hs-skel-pulsa { 0%,100% { opacity:.45; } 50% { opacity:.9; } }

/* 3) O check que se desenha no fim de um fluxo longo. O anel fecha e o tico
      é traçado depois, nessa ordem, senão o tico aparece no vazio. */
.hs-feito { display:flex; flex-direction:column; align-items:center; gap:10px; padding:18px 0; }
.hs-feito svg { width:56px; height:56px; }
.hs-feito-anel { stroke:var(--accent); stroke-width:2.5; stroke-dasharray:145;
  stroke-dashoffset:145; animation:hs-traco .5s ease-out forwards; }
.hs-feito-tico { stroke:var(--accent); stroke-width:3.4; stroke-linecap:round;
  stroke-linejoin:round; stroke-dasharray:36; stroke-dashoffset:36;
  animation:hs-traco .32s .42s ease-out forwards; }
.hs-feito span { font-size:var(--fs-subtitulo); font-weight:700; color:var(--ink); }
@keyframes hs-traco { to { stroke-dashoffset:0; } }
.hs-feito.sem-animar .hs-feito-anel, .hs-feito.sem-animar .hs-feito-tico { animation:none; stroke-dashoffset:0; }

/* 4) Transição de guia: o conteúdo da aba nova sobe 8px com fade. Percepção
      de resposta imediata sem custo real, a troca já aconteceu, isto só
      conta a história dela. 180ms: mais que isso já parece lentidão. */
.hs-panel:not([hidden]) { animation:hs-guia-entra .18s ease-out; }
@keyframes hs-guia-entra { from { opacity:0; transform:translateY(8px); } to { opacity:1; transform:none; } }

@media (prefers-reduced-motion: reduce) {
  .hs-skel-linha span { animation:none; opacity:.6; }
  .hs-feito-anel, .hs-feito-tico { animation:none; stroke-dashoffset:0; }
  .hs-panel:not([hidden]) { animation:none; }
}

/* #4763: Contador de caracteres sob textarea com limite (data-contador).
   O aviso chega enquanto a pessoa escreve, não no clique de publicar.
   Liga sozinho via web/js/contador-textarea.js. */
.contador-textarea { margin-top:4px; font-size:var(--fs-corpo-pequeno); color:var(--ink-3); text-align:right; }
.contador-textarea--quase { color:var(--amber); font-weight:700; }
.contador-textarea--cheio { color:var(--rose); font-weight:700; }

/* #4584: a política de senha ANTES do campo, não depois do erro.
   Mora aqui (e não no CSS de uma página) porque repete nas TRÊS telas em que
   se escolhe senha: a redefinição por link, a troca de senha do console e o
   modal de primeiro acesso. Quem preenche a lista é web/js/politica-senha.js,
   que busca o texto do servidor: nenhuma regra é escrita aqui nem no HTML.
   Cor só por token: cor cravada some no tema escuro, e essa pedra já mordeu.
   O marcador do item é glifo de texto (nada de emoji colorido). */
.hs-politica { margin:0 0 14px; padding:11px 13px; border:1px solid var(--line);
  border-radius:11px; background:var(--surface-2); }
/* --ink-2 e não --ink-3 em TUDO que é letra aqui, e isso foi medido nesta tela:
   no tema CLARO o --ink-3 (#8b97a3) sobre este fundo (#eef1f5) dá 2,63:1, muito
   abaixo dos 4,5:1 que texto pequeno exige. O escuro já foi consertado em 13/08;
   o claro tem o mesmo defeito em outra conta e tem card próprio. Com --ink-2 dá
   6,5:1 no claro e 7,53:1 no escuro. */
.hs-politica__titulo { margin:0 0 7px; font-size:var(--fs-legenda); font-weight:800;
  letter-spacing:.05em; text-transform:uppercase; color:var(--ink-2); }
.hs-politica__lista { margin:0; padding:0; list-style:none; font-size:var(--fs-corpo);
  line-height:1.5; color:var(--ink-2); }
.hs-politica__item { position:relative; padding-left:15px; }
.hs-politica__item + .hs-politica__item { margin-top:3px; }
.hs-politica__item::before { content:'\25B8'; position:absolute; left:0; }
/* O contador de letras do campo. Ele não repete regra nenhuma: mostra a MEDIDA
   (quantos bytes a senha já ocupa) contra o teto que o servidor informou. É o
   que faz o "acento conta por duas" virar visível, porque o número pula de dois
   em dois quando se digita "ç", explicação que frase alguma dá. */
.hs-politica-medida { margin-top:5px; font-size:var(--fs-corpo-pequeno); font-weight:700; color:var(--ink-2); }
.hs-politica-medida--cheio { color:var(--rose); }

/* ═══ #4686: Ocorrências do aluno (classes do módulo web/js/ocorrencias.js) ═══
   Moram aqui, e não inline, pela regra do "nada novo nasce inline". A paleta é
   toda de token: a tela mais sensível da casa não inventa cor própria. */
.oc-busca-card { padding: 16px 18px; display: flex; gap: 12px; align-items: end;
  flex-wrap: wrap; position: relative; margin-bottom: 18px; }
/* #5654 - o .cg-card corta o que sai dele, e a lista de criancas nasce fora do cartao */
.cg-card.oc-busca-card { overflow: visible; }
.oc-busca-rotulo { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 220px; }
.oc-titulo-mini { font-size: var(--fs-corpo); font-weight: 800; color: var(--ink); }
.oc-sub-mini { font-size: var(--fs-corpo-pequeno); color: var(--ink-3); }
.oc-busca-input { flex: 1; min-width: 240px; max-width: 400px; }
.oc-busca-lista { position: absolute; top: 100%; right: 18px; width: min(400px, 90%);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  box-shadow: 0 8px 24px rgba(0,0,0,.12); z-index: 30; overflow: hidden; }
.oc-sugestao { display: block; width: 100%; text-align: left; padding: 10px 14px;
  background: none; border: 0; border-bottom: 1px solid var(--line); cursor: pointer;
  font-size: var(--fs-corpo); color: var(--ink); }
.oc-sugestao:hover { background: var(--surface-2); }
.oc-sugestao:last-child { border-bottom: 0; }
.oc-mat { color: var(--ink-3); font-size: var(--fs-corpo-pequeno); }

/* #5009 - a linha da conversa diz de qual crianca ela e. Sem isto, duas
   conversas da mesma mae sobre dois filhos desenham identicas: mesmo nome,
   mesma foto, nada separando. Medido: 96 pares de irmaos nessa situacao.
   Cor por token, e --ink-2 e nao --ink-3 (licao do #4813: no tema claro o
   --ink-3 da 2,63:1 contra o piso de 4,5:1). */
.conv-sobre { font-size: var(--fs-corpo-pequeno); color: var(--ink-2); margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* #5057 - a tela de "com quem a familia pode falar". Folha, nao inline: a
   pagina nasceu agora e a regra do #4426 vale para o que nasce. Cor so por
   token, e texto pequeno em --ink-2 (o --ink-3 da 2,63:1 no tema claro). */
.cfg-msg-modos { display: grid; gap: 12px; margin: 0 0 14px;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--piso-conteudo), 100%), 1fr)); }
.cfg-msg-modo { display: flex; flex-direction: column; gap: 5px; text-align: left;
  padding: 14px 16px; border: 1px solid var(--line); border-radius: 12px;
  background: var(--surface); cursor: pointer; font-family: var(--font); }
.cfg-msg-modo:hover { background: var(--surface-2); }
.cfg-msg-modo.on { border-color: var(--accent); background: var(--surface-3); }
.cfg-msg-modo__t { font-size: var(--fs-subtitulo); font-weight: 800; color: var(--ink); }
.cfg-msg-modo__d { font-size: var(--fs-corpo); color: var(--ink-2); line-height: 1.45; }
/* Estas duas andam SEMPRE junto de `hs-switch` / `hs-checkbox` (regua #4270:
   chave para configuracao que fica valendo, quadradinho para escolher item de
   lista). Entao aqui fica SO o que e desta tela: display, gap, alinhamento e
   cursor sao do design system, e repeti-los era a receita de as duas versoes
   divergirem no primeiro ajuste. */
.cfg-msg-linha { align-items: flex-start; font-size: var(--fs-corpo); padding: 10px 0 0; }
/* #5774 - as cinco chaves e o cabecalho dos canais (antes eram style="" no modulo) */
.cfg-msg-ajuda { margin: 0 0 14px; }
.cfg-msg-aviso { display: block; border-left: 3px solid var(--danger-solid); color: var(--ink);
  font-size: var(--fs-corpo); padding: 3px 0 3px 10px; margin-top: 6px; }
.cfg-msg-canais { margin-top: 16px; }
.cfg-msg-canais-cab { display: flex; gap: 12px; align-items: flex-start; flex-wrap: wrap; }
.cfg-msg-canais-txt { flex: 1 1 var(--piso-cartao); }
.cfg-msg-canais-txt h2 { margin: 0 0 4px; }
.cfg-msg-canais-txt .hs-help { margin: 0; }
.cfg-msg-vazio { margin: 14px 0 0; }
.cfg-msg-acoes { white-space: nowrap; }
.cfg-msg-tabela { overflow-x: auto; border: 1px solid var(--line);
  border-radius: 12px; margin-top: 14px; }
.cfg-msg-tabela table { border-collapse: collapse; width: 100%; font-size: var(--fs-corpo); }
.cfg-msg-tabela th { text-align: left; padding: 9px 11px; background: var(--surface-2);
  color: var(--ink); font-weight: 800; font-size: var(--fs-corpo);
  border-bottom: 1px solid var(--line); }
.cfg-msg-tabela td { padding: 9px 11px; border-bottom: 1px solid var(--line);
  color: var(--ink-2); vertical-align: top; }
.cfg-msg-tabela tr:last-child td { border-bottom: 0; }
/* as turmas do canal: rola dentro da propria caixa para o modal nao virar
   uma pagina de 60 linhas (a Humboldt tem 60 turmas). */
.cfg-msg-turmas { max-height: 42vh; overflow: auto; border: 1px solid var(--line);
  border-radius: 12px; padding: 4px; }
.cfg-msg-grupo { padding: 6px 8px 10px; }
.cfg-msg-grupo__cab { display: flex; align-items: center; gap: 10px;
  padding: 6px 2px; border-bottom: 1px solid var(--line); margin-bottom: 6px; }
.cfg-msg-grupo__cab b { font-size: var(--fs-corpo); color: var(--ink); }
.cfg-msg-grupo__cab .hs-help { flex: 1; margin: 0; }
.cfg-msg-turma { display: flex; padding: 4px 2px; font-size: var(--fs-corpo);
  color: var(--ink-2); }
.cfg-msg-turma:hover { color: var(--ink); }
/* #5774 - o modal do canal (antes eram style="" no modulo): a dica das turmas, o erro e o rodape do botao */
.cfg-msg-dica { margin: 0 0 8px; }
.cfg-msg-erro { margin-bottom: 10px; }
.cfg-msg-rodape { display: flex; gap: 10px; justify-content: flex-end; }

/* #5058 - as portas de atendimento da familia, no topo do Inicio. So aparecem
   no modo restrito; em escola aberta a caixa fica hidden e isto nao pinta nada. */
.atd-atalhos { border: 1px solid var(--line); border-radius: var(--r-card, 14px);
  background: var(--surface); padding: 16px 18px; margin: 0 0 18px; }
.atd-atalhos__cab { display: flex; align-items: baseline; gap: 10px;
  flex-wrap: wrap; margin-bottom: 12px; }
.atd-atalhos__cab b { font-size: var(--fs-subtitulo); color: var(--ink); }
.atd-atalhos__cab .hs-help { margin: 0; }
.atd-atalhos__grade { display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--piso-cartao), 100%), 1fr)); }
.atd-atalho { display: flex; gap: 11px; align-items: center; text-align: left;
  padding: 12px 14px; border: 1px solid var(--line); border-radius: 12px;
  background: var(--surface-2); cursor: pointer; font-family: var(--font); }
.atd-atalho:hover { background: var(--surface-3); border-color: var(--accent); }
.atd-atalho__av { width: 40px; height: 40px; border-radius: 999px;
  object-fit: cover; flex-shrink: 0; }
.atd-atalho__av--letra { display: inline-flex; align-items: center;
  justify-content: center; background: var(--accent); color: var(--accent-fg);
  font-weight: 800; font-size: var(--fs-subtitulo); }
.atd-atalho__txt { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.atd-atalho__n { font-size: var(--fs-corpo); font-weight: 800; color: var(--ink); }
.atd-atalho__q { font-size: var(--fs-corpo); color: var(--ink-2); }
.atd-atalho__d { font-size: var(--fs-corpo-pequeno); color: var(--ink-2); }

/* #5059 - a Ana dos pais. Mora colada nos atalhos do #5058, e o desenho diz o
   porque: sao as duas portas da familia, uma para a maquina e outra para gente.
   O aviso do que ela sabe nasce na propria caixa (.hs-help do cabecalho), para
   ninguem perguntar de nota e ouvir "nao tenho essa informacao". */
.anaf { border: 1px solid var(--line); border-radius: var(--r-card, 14px);
  background: var(--surface); padding: 16px 18px; margin: 0 0 18px; }
.anaf__cab { display: flex; gap: 11px; align-items: flex-start; margin-bottom: 12px; }
.anaf__cab b { font-size: var(--fs-subtitulo); color: var(--ink); }
.anaf__cab .hs-help { margin: 2px 0 0; }
.anaf__av { width: 34px; height: 34px; border-radius: 999px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--accent); color: var(--accent-fg); font-weight: 800;
  font-size: var(--fs-subtitulo); }
.anaf__sug { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.anaf__chip { padding: 7px 13px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--line); background: var(--surface-2);
  color: var(--ink-2); font-size: var(--fs-corpo); font-family: var(--font); }
.anaf__chip:hover { border-color: var(--accent); color: var(--ink); }
.anaf__linha { display: flex; gap: 10px; flex-wrap: wrap; }
.anaf__linha .hs-input { flex: 1 1 240px; min-width: 0; }
.anaf__resposta { margin-top: 13px; }
.anaf__txt { border-left: 3px solid var(--accent); padding: 2px 0 2px 13px;
  font-size: var(--fs-corpo); line-height: 1.55; color: var(--ink); }
.anaf__txt--erro { border-left-color: var(--st-danger-bar); color: var(--ink-2); }
/* #390 - o "o que ela sabe" deixou de ser texto solto sublinhado: e botao de contorno da casa; aqui so o respiro */
.anaf__saber { margin-top: 6px; }
.anaf__lista { margin: 0 0 12px 45px; }
.anaf__lista ul { margin: 0; padding-left: 18px; }
.anaf__lista li { font-size: var(--fs-corpo); color: var(--ink-2); line-height: 1.7; }

/* #4969 - a caixa de sugestoes tambem FALA. Ate 28/08 ela so existia com
   resultado: lista vazia escondia a caixa e erro caia num catch mudo, entao
   "nao achei" e "quebrou" desenhavam a mesma tela (nenhuma). O recado NAO e
   clicavel de proposito: nao existe ficha de crianca removida. */
.oc-recado { padding: 12px 14px; font-size: var(--fs-corpo); line-height: 1.5;
  color: var(--ink-2); cursor: default; }
.oc-recado b { color: var(--ink); font-weight: 700; }
.oc-recado--erro { border-left: 3px solid var(--danger-solid); color: var(--ink); }
.oc-painel { padding: 16px 18px; }
.oc-cab { font-size: var(--fs-corpo); font-weight: 800; color: var(--ink); margin-bottom: 12px; }
.oc-abas { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 14px; }
.oc-aba { padding: 8px 14px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface-2); color: var(--ink-2); font-size: var(--fs-corpo); cursor: pointer; }
.oc-aba.on { border-color: var(--brand); background: var(--surface-3);
  color: var(--ink); font-weight: 700; }
.oc-flex { flex: 1; }
.oc-lista { display: flex; flex-direction: column; gap: 8px; }
.oc-linha { display: flex; gap: 12px; align-items: center; width: 100%; text-align: left;
  padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); cursor: pointer; font-size: var(--fs-corpo); color: var(--ink); }
.oc-linha:hover { border-color: var(--brand); }
.oc-anulada { opacity: .55; }
.oc-data { color: var(--ink-3); font-size: var(--fs-corpo); flex: 0 0 auto; }
.oc-tipo { font-weight: 700; flex: 0 0 auto; }
.oc-tit { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.oc-selo { font-size: var(--fs-legenda); padding: 2px 8px; border-radius: 999px;
  background: var(--st-success-soft); color: var(--st-success-fg); flex: 0 0 auto; }
.oc-selo--anulada { background: var(--st-danger-soft); color: var(--st-danger-fg); }
.oc-vazio { padding: 22px; text-align: center; color: var(--ink-3); font-size: var(--fs-corpo); }
/* O aviso da casa (outra criança nunca é nomeada): tem que parecer aviso, não rodapé. */
.oc-aviso { padding: 10px 14px; border-left: 3px solid var(--st-warning-bar, var(--brand));
  background: var(--st-warning-soft, var(--surface-2)); color: var(--ink-2);
  font-size: var(--fs-corpo); border-radius: 0 var(--r) var(--r) 0; margin-bottom: 14px; }
.oc-aviso--psi { border-left-color: var(--st-danger-bar, #b4232a); }
.oc-check { display: flex; gap: 8px; align-items: center; font-size: var(--fs-corpo);
  color: var(--ink); margin: 12px 0; cursor: pointer; }
.oc-det-tit { font-size: var(--fs-subtitulo); font-weight: 800; color: var(--ink); }
.oc-det-meta { font-size: var(--fs-corpo); color: var(--ink-3); margin: 4px 0 12px; }
.oc-det-anulada { padding: 8px 12px; border-radius: var(--r); font-size: var(--fs-corpo);
  background: var(--st-danger-soft); color: var(--st-danger-fg); margin-bottom: 12px; }
.oc-det-corpo { font-size: var(--fs-corpo); color: var(--ink); white-space: pre-line;
  margin-bottom: 12px; }
.oc-det-rotulo { font-size: var(--fs-corpo-pequeno); font-weight: 800; color: var(--ink-2);
  text-transform: uppercase; letter-spacing: .04em; margin-bottom: 4px; }
.oc-det-acoes { display: flex; gap: 10px; margin-top: 14px; }

/* #4980: a MESMA ocorrência dentro da ficha 360 da criança.
   Aqui ela é lida, não operada: por isso o registro vem ABERTO, com relato e
   medidas à vista, em vez da linha clicável que abre modal. Quem está na ficha
   quer entender a criança de uma vez; quem está na página de Ocorrências está
   operando, e lá a lista compacta é a certa. Zero cor cravada: todos os tokens
   saem de tokens.css, senão a ficha fica legível no claro e some no escuro. */
.oc-ficha-topo { display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px;
  font-size: var(--fs-corpo); font-weight: 700; color: var(--ink); margin-bottom: 14px; }
.oc-ficha-nota { font-size: var(--fs-corpo); font-weight: 400; color: var(--ink-3); }
.oc-ficha-item { padding: 16px 18px; margin-bottom: 12px; }
.oc-ficha-cab { display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin-bottom: 8px; }
.oc-ficha-tit { font-size: var(--fs-subtitulo); font-weight: 800; color: var(--ink); margin: 0 0 8px; }
.oc-ficha-corpo { font-size: var(--fs-corpo); line-height: 1.55; color: var(--ink-2);
  white-space: pre-line; margin: 0 0 10px; }
.oc-ficha-rotulo { font-size: var(--fs-corpo-pequeno); font-weight: 800; color: var(--ink-2);
  text-transform: uppercase; letter-spacing: .04em; margin: 0 0 4px; }

/* ═══ #4654: ClickSign (bloco de Config › Integrações) ═══ */
.cs-ok { color: var(--st-success-fg); font-weight: 700; }
.cs-alerta { color: var(--st-warning-fg, var(--ink-2)); font-weight: 700; }
.cs-mudo { color: var(--ink-3); }

/* #4686/#4654: o esqueleto das seções novas SEM style= (regra do #4426: o teto
   de inline do admin só desce; tela nova não pode subi-lo nem por 1). */
.oc-secao { margin: 0; }
.oc-topo-texto { flex: 1; min-width: 0; }
.oc-miolo { padding: 20px 28px; }
.cs-intro { font-size: var(--fs-corpo); color: var(--ink-2); margin: 0 0 12px; }
.cs-status { font-size: var(--fs-corpo); margin-bottom: 10px; }
.cs-linha { display: flex; gap: 10px; align-items: end; flex-wrap: wrap; }
.cs-linha--baixo { margin-top: 10px; }
.cs-campo { flex: 1; min-width: 220px; margin: 0; }
.cs-campo-curto { width: 150px; margin: 0; }
.cs-dica { margin-top: 6px; }
.cs-acoes { display: flex; gap: 10px; margin-top: 12px; }
/* #6338: o interruptor da conta da Horus (o .switch vem do console) */
.cs-chave { display: flex; align-items: center; gap: 10px; margin: 6px 0 4px; }
/* #57 - o tamanho mora no rotulo, como nos outros interruptores das Integracoes (regua do #4906) */
.cs-chave-rotulo { font-weight: 700; font-size: var(--fs-corpo); color: var(--ink); }
.cs-chave .switch:disabled { opacity: .45; cursor: not-allowed; }

/* ── #5105: a barra de idiomas do comunicado ───────────────────────────────
   Classe e nao `style=` pela regra do #4426 (nada novo nasce inline). Cor so por
   token, para a barra nao cegar no tema escuro. */
.com-trad { display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  margin: 12px 0 4px; }
.com-trad-rot { font-size: var(--fs-corpo-pequeno); font-weight: 700; color: var(--ink-2);
  margin-right: 2px; }
.com-trad-pill { font-family: inherit; font-size: var(--fs-corpo-pequeno); font-weight: 700;
  cursor: pointer; padding: 4px 11px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--bg); color: var(--ink-2); }
.com-trad-pill:hover:not(:disabled) { border-color: var(--accent); color: var(--ink); }
.com-trad-pill[aria-pressed="true"] { background: var(--accent);
  color: var(--accent-fg); border-color: transparent; }
.com-trad-pill:disabled { opacity: .55; cursor: default; }
.com-trad-voltar { border-style: dashed; }
.com-trad-aviso { font-size: var(--fs-corpo-pequeno); color: var(--ink-2); margin-left: 4px; }
.com-trad-aviso--erro { color: var(--st-danger-fg); }
.com-trad-aviso--ok { color: var(--st-success-fg); }

/* ── #5110: a pergunta do canal e a dupla confirmação do envio ─────────────
 *
 * Zero cor cravada: tudo em token, e por isso os dois temas nascem certos sem
 * conferência a cada ajuste. Foi a lição medida no #4813, onde um texto pequeno
 * dava 2,63:1 num lugar que pede 4,5:1 só porque a cor tinha nascido para fundo
 * branco e ninguém olhou o escuro depois.
 * ------------------------------------------------------------------------- */

/* #4748: a janela de ajustar a tela. Uma linha por painel, texto a esquerda e o
   interruptor a direita, na mesma coluna -- o mesmo desenho da janela do canal de
   comunicado, para as duas nao virarem dois jeitos de fazer a mesma coisa. */
.aj-tela { max-width: 460px; }
.aj-tela-intro { font-size: var(--fs-corpo); color: var(--ink-2); margin: 0 0 12px; line-height: 1.5; }
.aj-tela-lista { display: flex; flex-direction: column; }
/* 06/09: sem barra de rolagem no modal. A linha Conteudo (que nao tinha controle)
   saiu, e as outras ficaram mais baixas: 13 linhas cabem numa janela de 900px. */
.aj-tela-linha {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: center; gap: 14px; padding: 9px 2px;
}
.aj-tela-linha + .aj-tela-linha { border-top: 1px solid var(--line); }
.aj-tela-texto { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.aj-tela-nome { font-size: var(--fs-corpo); font-weight: 600; }
.aj-tela-ajuda { font-size: var(--fs-corpo-pequeno); color: var(--ink-2); line-height: 1.45; }
.comunic-ajustar { margin-left: auto; }

/* #4748: o aviso do campo obrigatorio do nome da capa. */
.ban-erro-nome { margin: 8px 0 0; font-size: var(--fs-corpo); line-height: 1.45;
  color: var(--st-danger-fg); }

/* #5121: `hs-link` era usada por banners-escola.js e tags-comunicado.js e NAO
   EXISTIA. E ela que desenha "Gerenciar" e "Criar a primeira", que sao as portas
   de cadastro das etiquetas e do acervo de capas: sem estilo, o botao saia com a
   cara cinza do navegador e o dono relatou nao achar onde registrar etiqueta.
   Botao que nao parece botao e um botao que nao existe.

   Terceira vez que este defeito aparece hoje (hs-modal-corpo, hs-modal-pe e
   agora esta): modulo escreve classe, CSS nunca definiu, ninguem percebe porque
   a tela ate carrega. Nasceu regua para isso no test_5121. */
.hs-link {
  background: none; border: none; padding: 0; cursor: pointer;
  font: inherit; font-size: var(--fs-corpo); font-weight: 700;
  color: var(--accent-ink, var(--primary)); text-decoration: none;
}
.hs-link:hover { text-decoration: underline; }
.hs-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

/* #5079: o estado de ERRO de uma tela. Ele entra NO LUGAR do conteudo que
   faltou, e nao passa voando como um toast: a tela esta vazia e vai continuar
   vazia, entao a mensagem tem que ficar onde a pessoa foi procurar. */
.hs-erro-tela {
  display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
  padding: 18px 20px; margin: 8px 0;
  border: 1px solid var(--line); border-left: 3px solid var(--st-danger-fg);
  border-radius: 10px; background: var(--surface);
}
.hs-erro-tela__frase { margin: 0; font-size: var(--fs-corpo); line-height: 1.5; color: var(--ink); }
.hs-erro-tela__detalhe {
  margin: 0; font-size: var(--fs-corpo); line-height: 1.5; color: var(--ink-3);
  font-family: ui-monospace, Consolas, monospace; word-break: break-word;
}
.hs-erro-tela__acao { margin-top: 2px; }
/* #6255 - o display:flex dos dois estados engolia o hidden de quem os deixa no HTML. */
.hs-erro-tela[hidden], .hs-carregando-tela[hidden] { display: none; }

/* #5320: o estado de CARREGANDO de uma tela, irmao do de erro logo acima. Entra
   no lugar do conteudo na hora em que a leitura sai, para a tela nunca ficar
   muda; se o prazo vence, web/js/tela-carregando.js troca pelo .hs-erro-tela. */
.hs-carregando-tela {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 0; margin: 4px 0;
  font-size: var(--fs-corpo); line-height: 1.5; color: var(--ink-3);
}
.hs-carregando-tela__pulso {
  flex-shrink: 0; width: 10px; height: 10px; border-radius: 50%;
  background: var(--accent);
  animation: hs-carregando-pulso 1.2s ease-in-out infinite;
}
@keyframes hs-carregando-pulso {
  0%, 100% { opacity: .25; transform: scale(.8); }
  50% { opacity: 1; transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .hs-carregando-tela__pulso { animation: none; opacity: .7; }
}

/* Card 5399 (sem cerquilha: a regua do 5320 le cerquilha e 4 algarismos como cor) - o cartao do vigia flutua no alto, fora do layout da tela. */
.hs-vigia-tela {
  position: fixed; top: 72px; left: 50%; transform: translateX(-50%);
  z-index: 60; width: max-content; max-width: min(520px, calc(100vw - 32px));
  padding: 2px 16px; border-radius: 12px;
  background: var(--surface); border: 1px solid var(--line);
  box-shadow: var(--sh-2, var(--sh-1));
}
.hs-vigia-tela .hs-carregando-tela { padding: 8px 0; margin: 0; }
.hs-vigia-tela .hs-erro-tela { margin: 8px 0; padding: 10px 14px; }
/* #6147 - celular da régua: até 560px. */
@media (max-width: 560px) {
  .hs-vigia-tela { top: auto; bottom: 16px; }
}

/* A pergunta do primeiro login */
.canal-com { max-width: 480px; }
.canal-com-intro { font-size: var(--fs-corpo); color: var(--ink-2); margin: 0 0 14px; line-height: 1.5; }
/* #5111b: tres linhas com interruptor a direita, no lugar de tres blocos de
   texto sem afordancia. O texto cresce e o interruptor fica ancorado na mesma
   coluna nas tres linhas, que era o desalinhamento que o dono viu. */
.canal-com-opcoes { display: flex; flex-direction: column; gap: 2px; }
.canal-com-opcao {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: center; gap: 14px; width: 100%;
  padding: 12px 12px; text-align: left; cursor: pointer;
  border: 1px solid transparent; border-radius: 9px;
  background: var(--surface); color: var(--ink);
  transition: background .12s, border-color .12s;
}
.canal-com-opcao + .canal-com-opcao { border-top: 1px solid var(--line); border-radius: 0; }
.canal-com-opcao:hover { background: var(--surface-2); }
.canal-com-opcao-texto { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.canal-com-opcao-chave { flex: none; pointer-events: none; }
/* #5111b: a linha marcada precisa se ver SEM depender so da chave, que e pequena
   e some para quem enxerga mal. O fundo e a borda dizem a mesma coisa que o
   interruptor, e quem le por leitor de tela ouve pelo aria-checked. */
.canal-com-opcao.on { background: var(--surface-2); border-color: var(--accent); }
.canal-com-opcao:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.canal-com-opcao-titulo { font-size: var(--fs-corpo); font-weight: 600; }
.canal-com-opcao-ajuda { font-size: var(--fs-corpo-pequeno); color: var(--ink-2); line-height: 1.45; }
.canal-com-erro { font-size: var(--fs-corpo); color: var(--st-danger-fg); margin: 10px 0 0; }
.canal-com-rodape { font-size: var(--fs-corpo-pequeno); color: var(--ink-3); margin: 14px 0 0; }

/* A dupla confirmação do envio */
.com-conf { max-width: 460px; }
.com-conf-titulo {
  font-size: var(--fs-corpo); font-weight: 600; margin: 0 0 12px;
  padding-bottom: 10px; border-bottom: 1px solid var(--line);
}
.com-conf-numeros { display: flex; flex-direction: column; gap: 6px; }
.com-conf-linha { display: flex; align-items: baseline; gap: 9px; }
.com-conf-num {
  min-width: 46px; text-align: right; font-size: var(--fs-subtitulo); font-weight: 600;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
.com-conf-linha--forte .com-conf-num { font-size: var(--fs-titulo); color: var(--accent-ink); }
.com-conf-rot { font-size: var(--fs-corpo); color: var(--ink-2); }
.com-conf-aviso {
  font-size: var(--fs-corpo); line-height: 1.5; margin: 13px 0 0; padding: 10px 12px;
  border-radius: 8px; border: 1px solid var(--amber-border);
  background: var(--amber-bg); color: var(--ink);
}
.com-conf-aviso--erro { border-color: var(--rose); background: var(--rose-bg); }
.com-conf-aviso--calmo {
  border-color: var(--line); background: var(--surface-2); color: var(--ink-2);
}
.com-conf-nomes { font-size: var(--fs-corpo-pequeno); color: var(--ink-2); }
.com-conf-rodape { font-size: var(--fs-corpo-pequeno); color: var(--ink-3); margin: 14px 0 0; }
/* #5209: a dupla confirmação DENTRO da dupla confirmação, só quando o público
   inclui criança. Borda em --rose (mesmo tom do aviso de erro) de propósito:
   é o único bloco desta janela que TRAVA o botão, e precisa parecer diferente
   dos avisos que só informam. */
.com-conf-crianca {
  margin-top: 14px; padding: 11px 12px;
  border: 1px solid var(--rose); border-radius: 9px;
  background: var(--rose-bg);
}
.com-conf-crianca-aviso { font-size: var(--fs-corpo); line-height: 1.5; color: var(--ink); margin: 0; }
.com-conf-crianca-check { margin-top: 10px; font-size: var(--fs-corpo); }
.com-conf-sim:disabled { opacity: .5; cursor: not-allowed; }

/* ── #5108: a etiqueta do comunicado ──────────────────────────────────────
 *
 * A cor vem SEMPRE de token (a paleta fechada mora no tokens.css, medida nos
 * dois temas). Zero hex aqui: se um dia a paleta mudar, muda num lugar.
 * ------------------------------------------------------------------------- */
.tag-com {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px; border-radius: 999px;
  font-size: var(--fs-corpo-pequeno); font-weight: 600; line-height: 1.7;
  white-space: nowrap; max-width: 190px;
  overflow: hidden; text-overflow: ellipsis;
  border: 1px solid transparent;
}
/* #6022: 16 cores, na ordem do circulo (a mesma de CORES_TAG no servidor). */
.tag-com--cinza     { color: var(--tag-cinza-fg);     background: var(--tag-cinza-bg); }
.tag-com--grafite   { color: var(--tag-grafite-fg);   background: var(--tag-grafite-bg); }
.tag-com--marrom    { color: var(--tag-marrom-fg);    background: var(--tag-marrom-bg); }
.tag-com--vermelho  { color: var(--tag-vermelho-fg);  background: var(--tag-vermelho-bg); }
.tag-com--laranja   { color: var(--tag-laranja-fg);   background: var(--tag-laranja-bg); }
.tag-com--ambar     { color: var(--tag-ambar-fg);     background: var(--tag-ambar-bg); }
.tag-com--amarelo   { color: var(--tag-amarelo-fg);   background: var(--tag-amarelo-bg); }
.tag-com--oliva     { color: var(--tag-oliva-fg);     background: var(--tag-oliva-bg); }
.tag-com--verde     { color: var(--tag-verde-fg);     background: var(--tag-verde-bg); }
.tag-com--esmeralda { color: var(--tag-esmeralda-fg); background: var(--tag-esmeralda-bg); }
.tag-com--turquesa  { color: var(--tag-turquesa-fg);  background: var(--tag-turquesa-bg); }
.tag-com--azul      { color: var(--tag-azul-fg);      background: var(--tag-azul-bg); }
.tag-com--anil      { color: var(--tag-anil-fg);      background: var(--tag-anil-bg); }
.tag-com--roxo      { color: var(--tag-roxo-fg);      background: var(--tag-roxo-bg); }
.tag-com--magenta   { color: var(--tag-magenta-fg);   background: var(--tag-magenta-bg); }
.tag-com--rosa      { color: var(--tag-rosa-fg);      background: var(--tag-rosa-bg); }

/* Selecionável (no editor de comunicado e no cadastro) */
.tag-com--btn { cursor: pointer; border-color: transparent; transition: border-color .12s; }
.tag-com--btn:hover { border-color: currentColor; }
.tag-com--btn[aria-pressed="false"] { opacity: .48; }
.tag-com--btn[aria-pressed="true"]  { border-color: currentColor; }
.tag-com-lista { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; }
.tag-com-usos { font-size: var(--fs-legenda); color: var(--ink-3); margin-left: 2px; }
.tag-com-intro { font-size: var(--fs-corpo); color: var(--ink-2); margin: 0 0 14px; line-height: 1.5; }
.tag-com-nova { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.tag-com-nova .hs-input { flex: 1; min-width: 150px; }
/* #6022: o seletor de cor do cadastro. Com 16 cores, os FUNDOS claros ficam quase
 * iguais (magenta e rosa medem 0,008 de distancia OKLab), e um botao pintado so de
 * fundo virava 16 manchas de bege. Quem separa as cores e a LETRA: cada botao leva
 * uma bolinha em currentColor, que e a cor da letra do proprio tema. Duas fileiras
 * de oito, e sem a opacidade .48 do seletor do compositor: la ela diz "etiqueta nao
 * marcada"; aqui apagaria justamente a cor que a pessoa precisa comparar. */
.tag-com-cores { display: grid; grid-template-columns: repeat(8, 28px); gap: 4px; }
.tag-com-cores[hidden] { display: none; }
.tag-com-cor {
  width: 28px; height: 24px; padding: 0; justify-content: center;
  cursor: pointer; transition: border-color .12s, box-shadow .12s;
}
.tag-com-cor:hover { border-color: currentColor; }
.tag-com-cor[aria-pressed="true"] { border-color: currentColor; box-shadow: inset 0 0 0 1px currentColor; }
.tag-com-bolinha { display: block; width: 12px; height: 12px; border-radius: 50%; background: currentColor; }
.tag-com-bolinha[hidden] { display: none; }
.tag-com-erro { font-size: var(--fs-corpo); color: var(--st-danger-fg); margin: 10px 0 0; }
.tag-com-linha {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 0; border-bottom: 1px solid var(--line);
}
.tag-com-linha:last-child { border-bottom: 0; }
.tag-com-linha .tag-com-usos { margin-left: auto; }
.com-etiquetas { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line); }
.com-etiquetas-topo {
  display: flex; align-items: center; gap: 6px; margin-bottom: 6px;
}
.com-etiquetas-rot {
  display: block; font-size: var(--fs-corpo-pequeno); font-weight: 600;
  color: var(--ink-2);
}
/* #4748: a engrenagem e PEQUENA de proposito. Ela e a porta do cadastro, nao a
   acao principal do compositor: quem esta escrevendo um comunicado quer escolher
   etiqueta, nao criar uma. Cresce no hover para o alvo do clique nao ser do
   tamanho do desenho. */
.com-etiquetas-gear {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; padding: 0; border: none; border-radius: 6px;
  background: none; color: var(--ink-3); cursor: pointer;
  transition: background .12s, color .12s;
}
.com-etiquetas-gear:hover { background: var(--surface-2); color: var(--ink); }
.com-etiquetas-gear:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.tag-com-lista--card { margin-top: 8px; }
/* #5291: as etiquetas na LEITURA do comunicado (o modal que a familia e a
 * gestao abrem), logo abaixo dos selos e acima do titulo. */
.tag-com-lista--leitura { margin-top: 8px; }

/* ── #5104: a galeria de capas da escola ──────────────────────────────────
 * Zero cor cravada: tudo token, os dois temas nascem certos.
 * ------------------------------------------------------------------------- */
.ban-topo { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.ban-dica { font-size: var(--fs-corpo-pequeno); color: var(--ink-2); line-height: 1.5; }
.ban-erro { font-size: var(--fs-corpo); color: var(--st-danger-fg); margin: 0 0 10px; }
.ban-vazio { font-size: var(--fs-corpo); color: var(--ink-2); line-height: 1.6; margin: 8px 0; }
.ban-grade {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(var(--piso-cartao), 1fr));
}
.ban-item { margin: 0; }
.ban-img {
  display: block; width: 100%; padding: 0; cursor: pointer;
  border: 1px solid var(--line); border-radius: 10px; overflow: hidden;
  background: var(--surface-2); transition: border-color .12s;
}
.ban-img:hover { border-color: var(--accent); }
/* 3 por 1: a MESMA proporção que o card do comunicado usa. A miniatura precisa
   mostrar o corte real, senão a pessoa escolhe pela imagem inteira e leva um
   susto quando o card corta o topo e o rodapé da arte. */
.ban-img img { display: block; width: 100%; aspect-ratio: 3 / 1; object-fit: cover; }
.ban-item figcaption {
  display: flex; align-items: baseline; gap: 7px;
  margin-top: 5px; font-size: var(--fs-corpo-pequeno);
}
.ban-nome {
  font-weight: 600; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ban-usos { color: var(--ink-3); font-size: var(--fs-legenda); margin-left: auto; }
.ban-aviso {
  font-size: var(--fs-corpo-pequeno); line-height: 1.45; margin: 5px 0 0; padding: 6px 8px;
  border-radius: 7px; border: 1px solid var(--amber-border);
  background: var(--amber-bg); color: var(--ink-2);
}

/* ── #5102: o "fixar no topo" que veio do News ─────────────────────────────── */
.com-fixar { font-size: var(--fs-corpo); color: var(--ink-2); }
.com-fixar-ate { margin-top: 8px; padding-left: 4px; }
.com-fixar-rot {
  display: block; font-size: var(--fs-corpo-pequeno); font-weight: 600;
  color: var(--ink-2); margin-bottom: 4px;
}
.com-fixar-dica { font-size: var(--fs-corpo-pequeno); color: var(--ink-3); margin: 5px 0 0; line-height: 1.45; }
/* #5110: o override "mandar por e-mail para todos" na dupla confirmação */
.com-conf-forcar {
  display: flex; align-items: flex-start; gap: 9px;
  margin-top: 14px; padding: 11px 12px;
  border: 1px solid var(--line); border-radius: 9px;
  background: var(--surface-2); font-size: var(--fs-corpo); color: var(--ink);
}
.com-conf-forcar-dica {
  display: block; font-size: var(--fs-corpo-pequeno); color: var(--ink-2);
  line-height: 1.45; margin-top: 3px;
}
/* #5110: a dica do canal na ficha da família */
.cuid-canal-dica { font-size: var(--fs-corpo-pequeno); color: var(--ink-3); margin: 5px 0 0; line-height: 1.45; }

/* #5115: a marca forense por leitor. Mora aqui (e nao so no CSS da sala)
   porque ela tambem cobre o console da escola dos investidores. */
.inv-marca { position: fixed; inset: 0; z-index: 5; pointer-events: none; opacity: .035;
  background-repeat: repeat; background-size: 420px 260px; }
.inv-marca--forte { opacity: .55; }

/* #5368: o botao de saida do estado vazio do Mural ("Limpar a busca" e, no
   futuro, os irmaos dele). Nasce classe porque o visual repete: o botao que
   alarga o periodo ja usava a mesma altura e a mesma margem, escritas inline. */
.hs-feed-vazio__acao { height: 36px; font-size: var(--fs-corpo); margin-top: 10px; }

/* #5135 - a caixa "o que a Ana mudou" da Revisao do comunicado (web/js/ comunicado-revisar-diff.js) */
.crd-caixa {
  border: 1px solid var(--line); border-radius: 11px; padding: 12px 14px;
  background: var(--surface-2); margin-bottom: 12px;
}
.crd-corpo {
  font-size: var(--fs-corpo); line-height: 1.6; color: var(--ink); overflow-wrap: anywhere;
  max-height: clamp(180px, 32vh, 360px); overflow-y: auto; overscroll-behavior: contain;
}
.crd-rotulo { font-size: var(--fs-corpo-pequeno); font-weight: 600; color: var(--ink-3); margin: 10px 0 4px; }
.crd-rotulo:first-child { margin-top: 0; }
.crd-titulo { font-size: var(--fs-corpo); font-weight: 600; line-height: 1.5; color: var(--ink); overflow-wrap: anywhere; }
.crd-extras { margin: 0; padding-left: 18px; font-size: var(--fs-corpo); line-height: 1.5; color: var(--ink); }
.crd-rem { background: var(--rose-bg); color: var(--ink); text-decoration: line-through;
  border-radius: 3px; padding: 0 1px; }
.crd-add { background: var(--green-bg); color: var(--ink); border-radius: 3px; padding: 0 1px; }
.crd-igual { color: var(--ink); }
.crd-acoes { display: flex; gap: 8px; margin-top: 11px; flex-wrap: wrap; }
/* #6053 - texto so para o leitor de tela, nos selos que sao so icone (lido, tem anexo) */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* #5306 - o editor de foto com pincel de mosaico (web/js/foto-pincel.js) e os botoes que o abrem */
.hs-modal-bg.fp-fundo { z-index: calc(var(--z-modal, 9000) + 100); align-items: center; }
.hs-modal.fp-modal { max-width: min(960px, 96vw); }
.fp-corpo { display: flex; flex-direction: column; gap: 12px; }
.fp-dica, .fp-estado { margin: 0; font-size: var(--fs-corpo); line-height: 1.45; color: var(--ink-2); }
.fp-palco {
  display: flex; align-items: center; justify-content: center; min-height: 0;
  padding: 8px; background: var(--surface-2); border: 1px solid var(--line); border-radius: 12px;
}
.fp-tela {
  display: block; width: auto; height: auto; max-width: 100%; max-height: min(50vh, 50dvh);
  border-radius: 6px; cursor: crosshair; touch-action: none; user-select: none; -webkit-user-select: none;
}
.fp-ferramentas { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px 14px; }
.fp-tamanho { flex: 1 1 200px; min-width: 0; }
.fp-tamanho-campo { width: 100%; accent-color: var(--accent); }
.fp-rodape { flex-wrap: wrap; }
.fp-aviso { flex: 1 1 220px; margin-right: auto; font-size: var(--fs-corpo-pequeno); line-height: 1.4; color: var(--ink-3); }
.fp-btn-borrar { width: 100%; height: 38px; margin-top: 8px; font-size: var(--fs-corpo); }
.fp-btn-borrar--linha { width: auto; height: 36px; margin-top: 0; gap: 7px; }

/* #6397 - a ficha do dia de um aluno (web/js/ficha-dia.js): a previa do Comunicador 2.0 e a
   Frequencia da Ficha 360 desenham com as mesmas classes */
.ficha-dia {
  display: block; padding: 14px 16px; border: 1px solid var(--line); border-radius: var(--r-card);
  background: var(--surface); color: var(--ink);
}
.ficha-dia[hidden] { display: none; }
.ficha-dia-nome { margin: 0 0 8px; font-size: var(--fs-corpo); font-weight: 700; color: var(--ink); }
.ficha-dia-linhas {
  display: flex; flex-direction: column; gap: 4px; margin: 0; padding-left: 18px;
  font-size: var(--fs-corpo); line-height: 1.5; color: var(--ink-2);
}
.ficha-dia-linhas[hidden] { display: none; }
.ficha-dia-vazio { margin: 0; font-size: var(--fs-corpo); color: var(--ink-3); }
.ficha-dia-estado { margin: 10px 0 0; font-size: var(--fs-corpo); color: var(--ink-3); }
.ficha-dia-estado--enviada { color: var(--st-success-fg); font-weight: 600; }
/* a Frequencia da Ficha 360: o dia com diario vira botao e a ficha abre abaixo do calendario */
.ficha-dia-tem { cursor: pointer; box-shadow: inset 0 0 0 2px var(--primary-soft-2); }
.ficha-dia-tem:hover { box-shadow: inset 0 0 0 2px var(--primary); }
.ficha-dia-tem:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.ficha-dia-tem--aberta { box-shadow: inset 0 0 0 3px var(--primary); }
.ficha-dia-painel { display: block; margin-top: 18px; max-width: 720px; }
.ficha-dia-painel[hidden] { display: none; }
.ficha-dia-titulo { margin: 0 0 10px; font-size: var(--fs-subtitulo); font-weight: 800; color: var(--ink); }
.ficha-dia-corpo { font-size: var(--fs-corpo); color: var(--ink-3); }
/* #6413 - a guia Ficha do dia da Ficha 360: os dias do mes com diario, a esquerda, e a ficha do
   dia escolhido, a direita (uma coluna so no celular). So token, nos temas claro e escuro. */
.ficha-dia-guia { display: block; }
.ficha-dia-guia[hidden] { display: none; }
.ficha-dia-guia-topo {
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between;
  gap: 12px; margin-bottom: 12px;
}
.ficha-dia-guia-topo[hidden] { display: none; }
.ficha-dia-guia-titulo { margin: 0; font-size: var(--fs-subtitulo); font-weight: 800; color: var(--ink); }
.ficha-dia-guia-frase { margin: 4px 0 0; max-width: 560px; font-size: var(--fs-corpo); line-height: 1.5; color: var(--ink-3); }
.ficha-dia-mes { display: flex; align-items: center; gap: 8px; }
.ficha-dia-mes[hidden] { display: none; }
.ficha-dia-mes-nome { min-width: 132px; text-align: center; font-size: var(--fs-corpo); font-weight: 700; color: var(--ink); }
.ficha-dia-guia-situacao { margin: 0 0 12px; font-size: var(--fs-corpo); color: var(--ink-3); }
.ficha-dia-guia-situacao[hidden] { display: none; }
.ficha-dia-guia-situacao--erro { color: var(--st-danger-fg); }
.ficha-dia-guia-corpo {
  display: grid; grid-template-columns: minmax(var(--piso-cartao), 260px) minmax(0, 1fr); gap: 16px; align-items: start;
}
.ficha-dia-guia-corpo[hidden] { display: none; }
@media (max-width: 560px) {
  .ficha-dia-guia-corpo { grid-template-columns: minmax(0, 1fr); }
}
.ficha-dia-dias { display: flex; flex-direction: column; gap: 6px; margin: 0; padding: 0; list-style: none; }
.ficha-dia-dias[hidden] { display: none; }
.ficha-dia-dia {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px; width: 100%;
  padding: 8px 12px; border: 1px solid var(--line); border-radius: var(--r-card);
  background: var(--surface); color: var(--ink); font: inherit; text-align: left; cursor: pointer;
}
.ficha-dia-dia[hidden] { display: none; }
.ficha-dia-dia:hover { border-color: var(--primary); }
.ficha-dia-dia:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.ficha-dia-dia--aberta { border-color: var(--primary); box-shadow: inset 0 0 0 1px var(--primary); }
.ficha-dia-dia-data { font-size: var(--fs-corpo); font-weight: 700; color: var(--ink); }
.ficha-dia-dia-estado { font-size: var(--fs-corpo-pequeno); color: var(--ink-3); }
.ficha-dia-dia-estado--enviada { color: var(--st-success-fg); font-weight: 600; }
.ficha-dia-guia .ficha-dia-painel { margin-top: 0; }

.hs-pular-conteudo {
  position:fixed; top:12px; left:12px; z-index:var(--z-dropdown);
  transform:translateY(calc(-100% - 24px)); padding:12px 16px;
  background:var(--surface); color:var(--text-1); border-radius:var(--r);
  border:1px solid var(--border-strong); font-weight:600;
}
.hs-pular-conteudo:focus {
  transform:translateY(0); outline:2px solid var(--focus); outline-offset:2px;
}
.hs-modal-bg.ci-fundo { z-index:calc(var(--z-modal, 9000) + 110); }
.ci-modal { max-width:min(660px, 94vw); }
.ci-orientacao, .ci-nome, .ci-alerta { overflow-wrap:anywhere; margin:0 0 12px; }
.ci-crianca { padding:16px 0; border-bottom:1px solid var(--line); }
.ci-nome { font-weight:700; }
.ci-alerta, .ci-erro { color:var(--rose); font-weight:600; }
.ci-lista { min-width:0; }
.ci-acoes { flex-wrap:wrap; }
.ci-acoes .hs-btn { white-space:normal; height:auto; min-height:42px; }
.ci-achados, .ci-marcadas { display:flex; flex-wrap:wrap; gap:8px; margin-top:12px; }
.ci-achados .hs-btn, .ci-marcadas .hs-btn { white-space:normal; height:auto; overflow-wrap:anywhere; }
.ci-procurar { margin-top:10px; }
/* #263: "nenhuma crianca aparece nas imagens", a confirmacao de quem envia o comunicado */
.ci-sem-crianca { display:flex; align-items:flex-start; gap:10px; padding:12px 14px; margin:0 0 12px;
  border:1px solid var(--line); border-radius:var(--r); background:var(--surface); }
.ci-sem-crianca-caixa { flex:0 0 auto; width:18px; height:18px; margin-top:2px; }
.ci-sem-crianca-rotulo { font-weight:600; overflow-wrap:anywhere; cursor:pointer; }
.ci-lista--fora { display:none; }

/* #6705 - nota de data no topo das paginas historicas que ainda contam a cifra de antes (Fernet, 128 bits) */
.nota-historica { display: block; margin: 0; padding: 10px 22px; background: var(--st-warning-soft);
  color: var(--ink); border-bottom: 1px solid var(--st-warning-bar); font-size: var(--fs-corpo); line-height: 1.55; }
.nota-historica b { color: var(--ink); }
.nota-historica a { color: var(--ink); font-weight: 700; text-decoration: underline; }

/* #278: a pergunta da aprovacao da matricula (web/js/aprovar-matricula.js), na Secretaria e no CRM */
.apm { max-width:min(520px,92vw); }
.apm-texto, .apm-ajuda { margin:0 0 10px; font-size:var(--fs-corpo); color:var(--ink-2); }
.apm-pergunta { margin:0 0 8px; font-size:var(--fs-subtitulo); font-weight:700; color:var(--ink); }
.apm-acoes { display:flex; flex-wrap:wrap; gap:8px; margin-top:14px; }
.apm-campos { display:grid; grid-template-columns:repeat(auto-fit, minmax(min(100%, var(--piso-cartao)), 1fr)); gap:10px; margin-top:8px; }
.apm-campo { margin:0; } .apm-campo .hs-select { width:100%; min-width:0; }
.apm-acesso { display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin-top:8px; }
.cg-card > .apm-acesso { margin-top:0; padding:0 18px 14px; }

/* #278: as pendencias da matricula no topo da ficha 360 (web/js/pendencias-matricula.js) */
/* #301: a barra de completude e as pendencias num bloco que abre e fecha, com o fundo de destaque enquanto falta algo */
.pmt { margin:0 0 18px; padding:14px 16px; border:1px solid var(--line); border-radius:14px; background:var(--surface); display:flex; flex-direction:column; gap:10px; }
.pmt-titulo { margin:0; font-size:var(--fs-subtitulo); font-weight:800; color:var(--ink); }
.pmt-completude { display:flex; align-items:center; gap:12px; flex-wrap:wrap; }
.pmt-barra { flex:1 1 160px; height:10px; -webkit-appearance:none; appearance:none; border:0; border-radius:99px; background:var(--line); overflow:hidden; }
.pmt-barra::-webkit-progress-bar { background:var(--line); border-radius:99px; }
.pmt-barra::-webkit-progress-value { background:var(--accent); border-radius:99px; }
.pmt-barra::-moz-progress-bar { background:var(--accent); border-radius:99px; }
.pmt-conta { font-size:var(--fs-corpo); color:var(--ink-3); }
.pmt-dobra { border:1px solid var(--amber); border-radius:10px; background:var(--amber-bg); }
.pmt-resumo { list-style:none; cursor:pointer; display:flex; align-items:center; gap:8px; padding:9px 12px; border-radius:10px; font-size:var(--fs-corpo); font-weight:700; color:var(--ink); }
.pmt-resumo::-webkit-details-marker { display:none; }
.pmt-resumo:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
.pmt-dobra[open] { background:var(--surface); }
.pmt-dobra[open] > .pmt-resumo { background:var(--amber-bg); border-bottom-left-radius:0; border-bottom-right-radius:0; }
.pmt-alerta { width:16px; height:16px; flex:none; fill:none; stroke:var(--amber); stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
.pmt-dobra > .pmt-lista, .pmt-dobra > .pmt-nota { margin-left:12px; margin-right:12px; }
.pmt-dobra > .pmt-lista { margin-top:10px; }
.pmt-dobra > :last-child { margin-bottom:12px; }
.pmt-subtitulo { margin:12px 12px 6px; font-size:var(--fs-corpo); font-weight:700; color:var(--ink-2); }
.pmt-estado { color:var(--ink-3); }
.pmt-lista { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:4px; font-size:var(--fs-corpo); color:var(--ink); }
.pmt-item--ok { color:var(--ink-3); }
.pmt-marca { display:inline-block; width:18px; }
.pmt-item { display:flex; flex-wrap:wrap; align-items:center; gap:6px; }
.pmt-acao { margin-left:auto; }
.pmt-nota { margin:10px 0 0; font-size:var(--fs-corpo); color:var(--ink-3); }

/* #338 - a frase de lista vazia e o titulo de secao das telas do console (Portaria, Sala de espera, Presenca, Enfermaria),
   que antes cada funcao escrevia com estilo na tela, cada uma num tamanho */
.hs-vazio { font-size:var(--fs-corpo); color:var(--ink-3); }
.hs-vazio--linha-toda { grid-column:1/-1; }
.hs-secao-titulo { font-size:var(--fs-subtitulo); font-weight:800; color:var(--ink); }
.hs-secao-titulo--espaco { margin:28px 0 14px; }
.enf-perfil-textos { display:flex; flex-direction:column; gap:2px; flex:1; min-width:220px; }
.enf-perfil-titulo { font-size:var(--fs-corpo); font-weight:800; color:var(--ink); }
.enf-perfil-ajuda { font-size:var(--fs-corpo-pequeno); color:var(--ink-3); }

/* ============================================================================
   #354 - AS PECAS DA CASA (Padrao Comunicador). Ordem do dono de 07/11: o Comunicador e o modelo de todas as telas.
   Sao as pecas dele com o prefixo casa- e os tokens --casa-* (tokens.css); o comportamento comum mora em web/js/casa-pecas.js;
   a regra escrita, o metodo e a ordem das telas em web/padrao-comunicador.html e docs/design-system.md.
   Nenhuma tela muda de aparencia por este bloco: so quem usa a classe casa- ganha o desenho.
   A largura: a casca recebe data-modo="colunas" (1024 px ou mais) ou "gaveta" (abaixo) do casa-pecas.js, o mesmo
   corte do Comunicador; o CSS so desenha o modo (sem corte novo nesta folha, regua #6147). O celular e o 560 da regua.
   Toda classe que declara display tem o par [hidden] logo abaixo (#4347).
   ============================================================================ */

/* #354 - 1. a casca: o cabecalho que gruda, o titulo da tela, o trio de icones e as abas da tarefa */
.casa-casca { position: relative; min-width: 0; max-width: 100%; background: var(--casa-fundo); color: var(--casa-tinta);
  font-family: var(--casa-fonte); -webkit-font-smoothing: antialiased; }
.casa-casca button { font-family: var(--casa-fonte); }
.casa-cab { position: sticky; top: 0; z-index: 30; background: var(--casa-superficie); border-bottom: 1px solid var(--casa-linha); }
.casa-cab-linha,
.casa-cab > .topo-pagina { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 12px; min-height: 58px; padding: 10px 24px 0;
  position: static; background: transparent; -webkit-backdrop-filter: none; backdrop-filter: none; border-bottom: 0; }
.casa-cab-linha[hidden] { display: none; }
.casa-cab-marca { display: flex; align-items: center; gap: 8px; flex: 1 1 auto; min-width: 0; }
.casa-cab-marca[hidden] { display: none; }
.casa-cab .casa-titulo { margin: 0; font-family: var(--casa-fonte); font-size: var(--fs-titulo); font-weight: 600; letter-spacing: -.01em;
  color: var(--casa-tinta); }

/* #354 - 2. o trio de icones a direita do titulo: i (Como funciona), olho (o que eu vejo) e engrenagem (Regras da escola) */
.casa-trio { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.casa-trio[hidden] { display: none; }
.casa-icone { width: var(--casa-altura-controle); height: var(--casa-altura-controle); display: inline-grid; place-items: center;
  flex-shrink: 0; padding: 0; border: 1px solid var(--casa-linha); border-radius: var(--casa-raio-controle);
  background: var(--casa-superficie); color: var(--casa-tinta); cursor: pointer; }
.casa-icone[hidden] { display: none; }
.casa-icone:hover { background: var(--casa-chip); }
.casa-icone svg { width: 19px; height: 19px; }

.casa-abas { display: flex; flex-wrap: wrap; gap: 4px; padding: 4px 16px 0; }
.casa-abas[hidden] { display: none; }
.casa-aba { height: 42px; padding: 0 14px; display: inline-block; line-height: 40px; border: none; border-bottom: 2px solid transparent;
  background: transparent; color: var(--casa-sub); font-size: var(--fs-corpo); font-weight: 500; cursor: pointer; white-space: nowrap; }
.casa-aba[hidden] { display: none; }
.casa-aba[aria-selected="true"] { color: var(--casa-principal-tinta); font-weight: 600; border-bottom-color: var(--casa-principal-tinta); }
.casa-aba-contador { font-variant-numeric: tabular-nums; }
/* #354 - a faixa do cabecalho: onde a barra de acao mora quando a principal tem de estar a mao em qualquer altura (a do Comunicador) */
.casa-faixa { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 16px; padding: 10px 24px; border-top: 1px solid var(--casa-linha); }
.casa-faixa[hidden] { display: none; }
.casa-faixa > .casa-barra { flex: 1 1 480px; min-width: 0; }
.casa-painel { padding: 20px 24px 60px; }

/* #354 - 3. a barra de acao: a esquerda o contexto e as acoes do conteudo; a direita UMA principal que diz o que vai
   acontecer e as secundarias como botao de contorno, mesma altura e mesma linha. Texto sem moldura nao entra na barra. */
.casa-barra { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 12px; min-width: 0; }
.casa-barra[hidden] { display: none; }
.casa-barra-contexto { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 10px; flex: 1 1 auto; min-width: 0;
  font-size: var(--fs-corpo); color: var(--casa-sub); }
.casa-barra-contexto[hidden] { display: none; }
.casa-barra-acoes { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-left: auto; }
.casa-barra-acoes[hidden] { display: none; }
.casa-btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; height: var(--casa-altura-controle);
  padding: 0 14px; border: 1px solid var(--casa-linha); border-radius: var(--casa-raio-controle); background: var(--casa-superficie);
  color: var(--casa-tinta); font-family: var(--casa-fonte); font-size: var(--fs-corpo); font-weight: 600; line-height: 1;
  cursor: pointer; white-space: nowrap; text-decoration: none; }
.casa-btn[hidden] { display: none; }
.casa-btn svg { flex-shrink: 0; }
.casa-btn--contorno:hover { background: var(--casa-chip); }
.casa-btn--principal { padding: 0 20px; border-color: transparent; background: var(--casa-principal); color: var(--casa-principal-fg); }
.casa-btn--principal:hover { filter: brightness(.95); }
.casa-btn--icone { width: var(--casa-altura-controle); padding: 0; }
.casa-btn:disabled { cursor: progress; opacity: .6; }
/* #354 - no celular (o 560 da regua) as acoes viram grade de largura igual e a principal fica sozinha na linha inteira */
@media (max-width: 560px) {
  .casa-barra-acoes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; margin-left: 0; }
  .casa-barra-acoes > .casa-btn { width: 100%; min-width: 0; }
  .casa-barra-acoes > .casa-btn--principal,
  .casa-barra-acoes > .casa-btn--contorno:nth-child(odd):nth-last-child(2) { grid-column: 1 / -1; }
}

/* #354 - 4. duas colunas: o trabalho a esquerda e o painel lateral de 352 px a direita, que gruda abaixo do cabecalho;
   no modo gaveta (abaixo de 1024 px) o painel vira gaveta, aberta pelo botao e fechada pelo X, pelo fundo ou pelo Esc */
.casa-duas { display: grid; grid-template-columns: minmax(0, 1fr) minmax(var(--piso-conteudo), var(--casa-lateral)); gap: 20px;
  align-items: start; }
.casa-duas[hidden] { display: none; }
.casa-duas-trabalho { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.casa-duas-trabalho[hidden] { display: none; }
.casa-lateral { display: flex; flex-direction: column; min-width: 0; background: var(--casa-superficie); border-radius: var(--casa-raio);
  box-shadow: var(--casa-sombra); position: sticky; top: calc(var(--casa-cab-altura, 106px) + 10px);
  max-height: calc(var(--altura-tela) - var(--casa-cab-altura, 106px) - 70px); overflow-y: auto; scrollbar-width: thin; }
.casa-lateral[hidden] { display: none; }
.casa-lateral-topo { display: flex; align-items: center; gap: 8px; border-bottom: 1px solid var(--casa-linha); }
.casa-lateral-topo[hidden] { display: none; }
.casa-lateral-abas { display: flex; flex: 1; min-width: 0; }
.casa-lateral-abas[hidden] { display: none; }
.casa-lateral-aba { flex: 1; height: 44px; border: none; border-bottom: 2px solid transparent; background: transparent;
  color: var(--casa-sub); font-size: var(--fs-corpo); font-weight: 500; cursor: pointer; }
.casa-lateral-aba[aria-selected="true"] { color: var(--casa-principal-tinta); font-weight: 600; border-bottom-color: var(--casa-principal-tinta); }
.casa-lateral-titulo { flex: 1; margin: 0; padding: 12px 16px; font-size: var(--fs-corpo); font-weight: 600; color: var(--casa-tinta); }
.casa-lateral-corpo { padding: 12px; }
.casa-icone.casa-lateral-fechar { display: none; margin-right: 8px; }
.casa-lateral-fundo { display: none; }
.casa-lateral-fundo[hidden] { display: none; }
.casa-btn.casa-gaveta-botao { display: none; margin: 0 0 14px; }
/* #354 - a altura do cabecalho chega medida pelo casa-pecas.js em degraus de 24 px (data-cab): o JS nunca escreve estilo */
.casa-casca[data-cab="96"] { --casa-cab-altura: 96px; }
.casa-casca[data-cab="120"] { --casa-cab-altura: 120px; }
.casa-casca[data-cab="144"] { --casa-cab-altura: 144px; }
.casa-casca[data-cab="168"] { --casa-cab-altura: 168px; }
.casa-casca[data-cab="192"] { --casa-cab-altura: 192px; }
.casa-casca[data-cab="216"] { --casa-cab-altura: 216px; }
.casa-casca[data-cab="240"] { --casa-cab-altura: 240px; }
.casa-casca[data-cab="264"] { --casa-cab-altura: 264px; }
.casa-casca[data-cab="288"] { --casa-cab-altura: 288px; }
.casa-casca[data-cab="312"] { --casa-cab-altura: 312px; }
.casa-casca[data-cab="336"] { --casa-cab-altura: 336px; }
.casa-casca[data-cab="360"] { --casa-cab-altura: 360px; }
.casa-casca[data-modo="gaveta"] .casa-cab { position: static; }
/* #354 - !important so aqui: ate 920 px a .topo-pagina de toda tela leva padding com !important (bloco [L1] acima) */
.casa-casca[data-modo="gaveta"] .casa-cab > .topo-pagina { padding: 10px 16px 0 !important; }
.casa-casca[data-modo="gaveta"] .casa-abas { padding: 4px 8px 0; }
.casa-casca[data-modo="gaveta"] .casa-faixa { padding: 8px 16px; }
.casa-casca[data-modo="gaveta"] .casa-painel { padding: 16px 16px 60px; }
/* #360 - a tela pode pedir so o painel em gaveta tambem em colunas (data-casa-lateral="gaveta" na casca, posto pelo JS da tela quando o
   trabalho pede a largura inteira): o painel ganha o mesmo desenho da gaveta e o resto da casca segue em colunas */
.casa-casca[data-modo="gaveta"] .casa-duas,
.casa-casca[data-casa-lateral="gaveta"] .casa-duas { grid-template-columns: minmax(0, 1fr); }
.casa-casca[data-modo="gaveta"] .casa-btn.casa-gaveta-botao,
.casa-casca[data-casa-lateral="gaveta"] .casa-btn.casa-gaveta-botao { display: inline-flex; }
.casa-casca[data-modo="gaveta"] .casa-btn.casa-gaveta-botao[hidden],
.casa-casca[data-casa-lateral="gaveta"] .casa-btn.casa-gaveta-botao[hidden] { display: none; }
.casa-casca[data-modo="gaveta"] .casa-lateral,
.casa-casca[data-casa-lateral="gaveta"] .casa-lateral { display: none; position: fixed; top: 0; right: 0; bottom: 0; width: min(400px, calc(100vw - 32px));
  max-height: none; z-index: 160; border-radius: 0; box-shadow: var(--casa-sombra-gaveta); }
.casa-casca[data-modo="gaveta"].casa--gaveta-aberta .casa-lateral,
.casa-casca[data-casa-lateral="gaveta"].casa--gaveta-aberta .casa-lateral { display: flex; }
.casa-casca[data-modo="gaveta"] .casa-icone.casa-lateral-fechar,
.casa-casca[data-casa-lateral="gaveta"] .casa-icone.casa-lateral-fechar { display: inline-grid; }
.casa-casca[data-modo="gaveta"].casa--gaveta-aberta .casa-lateral-fundo,
.casa-casca[data-casa-lateral="gaveta"].casa--gaveta-aberta .casa-lateral-fundo { display: block; position: fixed; inset: 0; z-index: 159;
  background: var(--casa-veu); }

/* #354 - 5. o grupo de opcoes: cabecalho que abre e fecha, com o nome em caixa alta e o "N ligados" na cor da escola */
.casa-grupo { border-bottom: 1px solid var(--casa-linha); }
.casa-grupo:last-child { border-bottom: 0; }
.casa-grupo-cab { width: 100%; display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 10px 16px; border: 0;
  background: transparent; color: var(--casa-sub); font-family: var(--casa-fonte); text-align: left; cursor: pointer; }
.casa-grupo-cab[hidden] { display: none; }
.casa-grupo-nome { flex: 1; font-size: var(--fs-legenda); font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.casa-grupo-conta { font-size: var(--fs-corpo-pequeno); font-weight: 600; color: var(--casa-principal-tinta); font-variant-numeric: tabular-nums; }
.casa-grupo-seta { flex-shrink: 0; transition: transform .15s; }
.casa-grupo-cab[aria-expanded="false"] .casa-grupo-seta { transform: rotate(-90deg); }
.casa-grupo-corpo { display: flex; flex-direction: column; gap: 2px; padding: 0 16px 12px; }
.casa-grupo-corpo[hidden] { display: none; }

/* #354 - 6. a linha: o nome (rotulo do interruptor), o i que abre a dica e o interruptor da casa (.hs-switch) */
.casa-linha { display: flex; align-items: center; gap: 8px; min-height: 44px; }
.casa-linha[hidden] { display: none; }
.casa-linha-nome { flex: 1; min-width: 0; font-size: var(--fs-corpo); line-height: 1.4; color: var(--casa-tinta); cursor: pointer; }
.casa-linha-i { width: 28px; height: 28px; display: inline-grid; place-items: center; flex-shrink: 0; padding: 0; border: 0;
  border-radius: 999px; background: transparent; color: var(--casa-sub); cursor: pointer; }
.casa-linha-i[hidden] { display: none; }
.casa-linha-i:hover,
.casa-linha-i[aria-expanded="true"] { background: var(--casa-chip); color: var(--casa-tinta); }
.casa-linha-dica { margin: 0 0 8px; padding: 9px 11px; border-radius: 9px; background: var(--casa-chip); font-size: var(--fs-corpo-pequeno);
  line-height: 1.5; color: var(--casa-tinta); }
.casa-linha .hs-switch-trilho { background: var(--casa-trilho); border-color: var(--casa-trilho); }
.casa-linha .hs-switch input:checked + .hs-switch-trilho { background: var(--casa-principal-tinta); border-color: var(--casa-principal-tinta); }
.casa-linha .hs-switch input:checked + .hs-switch-trilho::after { background: var(--casa-superficie); }

/* #354 - 7. o cartao de trabalho (o do Conteudo do Comunicador: o filete de cima na cor da escola) e o cartao comum */
.casa-cartao { background: var(--casa-superficie); border-radius: var(--casa-raio); box-shadow: var(--casa-sombra); padding: 18px 20px;
  min-width: 0; }
.casa-cartao--trabalho { border-top: 3px solid var(--casa-principal-tinta); }
.casa-lateral .casa-cartao,
.casa-gaveta .casa-cartao { box-shadow: none; }
.casa-cartao-titulo { margin: 0 0 6px; font-size: var(--fs-corpo); font-weight: 600; color: var(--casa-tinta); }
.casa-cartao-frase { margin: 0; font-size: var(--fs-corpo); line-height: 1.5; color: var(--casa-sub); }

/* #354 - 8. o cartao recolhivel: o cabecalho e um botao que recolhe, com a pilula da contagem; o resumo fica de pe recolhido */
.casa-recolhivel { padding: 0; overflow: hidden; }
.casa-recolhivel-cab { width: 100%; display: flex; align-items: center; gap: 12px; min-height: 56px; padding: 14px 20px; border: none;
  background: transparent; color: var(--casa-tinta); font-family: var(--casa-fonte); font-size: var(--fs-corpo); font-weight: 600;
  text-align: left; cursor: pointer; }
.casa-recolhivel-cab[hidden] { display: none; }
.casa-recolhivel-icone { color: var(--casa-principal-tinta); flex-shrink: 0; }
.casa-pilula { display: inline-flex; align-items: center; height: 24px; padding: 0 10px; border-radius: 999px;
  background: var(--casa-principal-suave); color: var(--casa-principal-tinta); font-size: var(--fs-corpo); font-weight: 600; white-space: nowrap; }
.casa-pilula[hidden] { display: none; }
.casa-recolhivel-seta { display: inline-flex; margin-left: auto; color: var(--casa-sub); transition: transform .15s; }
.casa-recolhivel-seta[hidden] { display: none; }
.casa-recolhivel-cab[aria-expanded="false"] .casa-recolhivel-seta { transform: rotate(-90deg); }
.casa-recolhivel-resumo { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 0 20px; padding: 14px 0;
  border-top: 1px solid var(--casa-linha); font-size: var(--fs-corpo); color: var(--casa-sub); }
.casa-recolhivel-resumo[hidden] { display: none; }
.casa-recolhivel-corpo { display: flex; flex-direction: column; gap: 14px; padding: 16px 20px; border-top: 1px solid var(--casa-linha);
  min-width: 0; }
.casa-recolhivel-corpo[hidden] { display: none; }

/* #354 - 9. o cartao vazio: diz o que vai aparecer ali e como comecar, com borda tracejada e sem sombra */
.casa-cartao--vazio { border: 1px dashed var(--casa-linha); box-shadow: none; }

/* #354 - 10. a gaveta do olho e das janelas laterais: o fundo e a .hs-modal-bg da casa (o Esc de hs-modal-esc.js fecha por ele) */
.hs-modal-bg.casa-gaveta-fundo { justify-content: flex-end; align-items: stretch; padding: 0; overflow: hidden; }
.casa-gaveta { display: flex; flex-direction: column; width: min(420px, 100vw); height: 100%; background: var(--casa-superficie);
  color: var(--casa-tinta); font-family: var(--casa-fonte); box-shadow: var(--casa-sombra-gaveta); }
.casa-gaveta[hidden] { display: none; }
.casa-gaveta-topo { display: flex; align-items: center; gap: 12px; padding: 16px 20px; border-bottom: 1px solid var(--casa-linha); }
.casa-gaveta-topo[hidden] { display: none; }
.casa-gaveta-titulo { margin: 0; flex: 1; font-size: var(--fs-subtitulo); font-weight: 600; }
.casa-gaveta-corpo { display: flex; flex-direction: column; gap: 12px; padding: 16px 20px; overflow-y: auto; }
.casa-gaveta-corpo[hidden] { display: none; }
.casa-gaveta-aviso { margin: 0; font-size: var(--fs-corpo-pequeno); line-height: 1.45; color: var(--casa-sub); }
/* #354 - o bloco que a pessoa escondeu no olho: classe, nunca o hidden, para nao desfazer o que a tela esconde por permissao */
.casa-escondido-pelo-olho { display: none !important; }

/* #464 - o tour da casa (web/js/casa-tour.js): o destaque na parte da tela, com o veu da casa em volta, e o balao do passo.
   A posicao e estado calculado na hora (--tour-x, --tour-y, --tour-w, --tour-h, --tour-balao-x, --tour-balao-y, escritos pelo JS);
   sem medida (celular estreito, parte fora da tela) o balao fica no meio, sobre o veu. Reusavel: o #465 da Matriz usa o mesmo. */
.casa-tour { position: fixed; inset: 0; z-index: 9000; font-family: var(--casa-fonte); }
.casa-tour[hidden] { display: none; }
.casa-tour-foco { position: fixed; left: var(--tour-x, 0); top: var(--tour-y, 0); width: var(--tour-w, 0); height: var(--tour-h, 0);
  border-radius: var(--casa-raio-controle); box-shadow: 0 0 0 200vmax var(--casa-veu); outline: 2px solid var(--casa-principal-tinta);
  outline-offset: 2px; pointer-events: none; }
.casa-tour--centro { background: var(--casa-veu); }
.casa-tour--centro .casa-tour-foco { display: none; }
.casa-tour-balao { position: fixed; left: var(--tour-balao-x, 16px); top: var(--tour-balao-y, 16px); width: min(380px, calc(100vw - 32px));
  max-height: calc(100vh - 32px); overflow-y: auto; display: flex; flex-direction: column; gap: 10px; padding: 16px 18px;
  background: var(--casa-superficie); color: var(--casa-tinta); border-radius: var(--casa-raio); box-shadow: var(--casa-sombra-gaveta); }
.casa-tour-balao[hidden] { display: none; }
.casa-tour--centro .casa-tour-balao { left: 50%; top: 50%; transform: translate(-50%, -50%); }
.casa-tour-topo { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.casa-tour-topo[hidden] { display: none; }
.casa-tour-conta { font-size: var(--fs-legenda); font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--casa-principal-tinta); }
.casa-tour-fechar { width: 32px; height: 32px; font-size: var(--fs-subtitulo); line-height: 1; }
.casa-tour-titulo { margin: 0; font-size: var(--fs-subtitulo); font-weight: 600; color: var(--casa-tinta); }
/* o titulo recebe o foco a cada passo so para o leitor de tela falar; nao e controle nem entra no Tab, entao sem anel */
.casa-tour-titulo:focus, .casa-tour-titulo:focus-visible { outline: none !important; }
.casa-tour-texto { margin: 0; font-size: var(--fs-corpo); line-height: 1.55; color: var(--casa-tinta); }
.casa-tour-fazer { margin: 0; padding: 9px 11px; border-radius: var(--casa-raio-controle); background: var(--casa-principal-suave);
  font-size: var(--fs-corpo); line-height: 1.5; color: var(--casa-tinta); }
.casa-tour-fazer[hidden] { display: none; }
.casa-tour-fazer-rotulo { display: block; margin-bottom: 2px; font-size: var(--fs-corpo-pequeno); color: var(--casa-principal-tinta); }
.casa-tour-fazer-rotulo[hidden] { display: none; }
.casa-tour-nao-mostrar { font-size: var(--fs-corpo); color: var(--casa-tinta); }
.casa-tour-barra { justify-content: flex-end; }
.casa-tour-barra .casa-barra-acoes { flex-wrap: wrap; justify-content: flex-end; }
