:root {
  color-scheme: light;
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  --cor-primaria: #2f6690;
  --cor-fundo: #f4f6f8;
  --cor-fundo-dashboard: #123f66;
  --cor-borda: #d5dbe1;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--cor-fundo);
  color: #1c2733;
}

/* ---------- Página de login ---------- */

/* Fundo em gradiente escuro, nas mesmas cores do resto da dashboard
   (--cor-fundo-dashboard / --cor-primaria), para a página de login não
   destoar visualmente do resto da app. */
body.pagina-login {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  background: linear-gradient(135deg, #0f2c47 0%, #1a4a72 50%, #2f6690 100%);
  color: white;
}

/* Logótipo da xlVISION, canto superior esquerdo da página de login. Só
   "width" é definido — "height: auto" garante que a proporção original da
   imagem se mantém sempre, sem distorção. */
.logotipo-login {
  position: fixed;
  top: 1.5rem;
  left: 1.5rem;
  z-index: 2;
  width: 160px;
  height: auto;
}

/* Camada de formas a flutuar atrás do cartão, só decorativa (aria-hidden no
   HTML) — puro CSS, sem imagens nem JS, para não pesar a página. */
.fundo-login {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.fundo-login .blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(70px);
  opacity: 0.45;
  animation: flutuar-blob 18s ease-in-out infinite;
}

.blob-1 {
  width: 420px;
  height: 420px;
  top: -140px;
  left: -120px;
  background: #3d6f9c;
}

.blob-2 {
  width: 380px;
  height: 380px;
  bottom: -160px;
  right: -100px;
  background: #1f3a56;
  animation-delay: -6s;
}

.blob-3 {
  width: 260px;
  height: 260px;
  top: 55%;
  left: 65%;
  background: #6fa8dc;
  animation-delay: -12s;
}

@keyframes flutuar-blob {
  0%, 100% {
    transform: translate(0, 0) scale(1);
  }
  33% {
    transform: translate(30px, -35px) scale(1.08);
  }
  66% {
    transform: translate(-25px, 25px) scale(0.95);
  }
}

@keyframes entrada-subida {
  from {
    opacity: 0;
    transform: translateY(18px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Caixa de autenticação: um retângulo com duas "meias-caixas" fixas (login
   sempre à direita, registo sempre à esquerda) e um painel colorido que
   desliza entre as duas para indicar o modo atual — ver
   .formulario-login/.formulario-registo/.painel-deslizante-caixa abaixo.
   Inspirado no padrão clássico de formulário de login/registo com painel
   deslizante (ex.: https://codepen.io/florin-pop/pen/emZEQvP), adaptado ao
   tema escuro/vidro fosco já usado no resto da app. */
.caixa-auth {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 700px;
  min-height: 460px;
  margin: 0 1.5rem;
  border-radius: 16px;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  border: 1px solid rgba(255, 255, 255, 0.18);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
  color: white;
  animation: entrada-subida 0.5s ease-out both;
}

.formulario-container {
  position: absolute;
  top: 0;
  width: 50%;
  height: 100%;
  display: flex;
  align-items: center;
  transition: opacity 0.4s ease-in-out;
}

.formulario-container form {
  width: 100%;
  padding: 2rem 2.5rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.formulario-container h1 {
  margin: 0 0 0.25rem;
  font-size: 1.5rem;
}

/* Login fica sempre na meia-caixa direita, registo sempre na esquerda — só
   a opacidade/pointer-events mudam consoante o modo. Nenhum dos dois se
   move: quem desliza é só o painel colorido (.painel-deslizante-caixa). */
.formulario-login {
  left: 50%;
  z-index: 2;
  opacity: 1;
}

.formulario-registo {
  left: 0;
  z-index: 1;
  opacity: 0;
  pointer-events: none;
}

#caixa-auth.modo-registo .formulario-login {
  opacity: 0;
  pointer-events: none;
  z-index: 1;
}

#caixa-auth.modo-registo .formulario-registo {
  opacity: 1;
  pointer-events: auto;
  z-index: 2;
}

/* "Esqueci a password" ocupa a mesma meia-caixa direita que .formulario-login
   (nunca as duas ao mesmo tempo) — alternado por uma classe à parte
   (.modo-esqueci) do painel deslizante login/registo, porque só se chega
   aqui a partir do login, nunca do registo, e não faz sentido nenhum o
   painel colorido deslizar por causa disto. */
.formulario-esqueci-password {
  left: 50%;
  z-index: 2;
  opacity: 0;
  pointer-events: none;
}

#caixa-auth.modo-esqueci .formulario-login {
  opacity: 0;
  pointer-events: none;
}

#caixa-auth.modo-esqueci .formulario-esqueci-password {
  opacity: 1;
  pointer-events: auto;
}

/* Repor a password a partir do link do email é um ecrã à parte, sem painel
   deslizante nem "lado" nenhum — ocupa a caixa toda em vez de uma
   meia-caixa. Começa escondido com "display: none" próprio (não o atributo
   "hidden": .formulario-container já tem "display: flex" incondicional,
   cairia na mesma armadilha de especificidade do "[hidden]" já documentada
   várias vezes nesta app — ver CLAUDE.md). `auth.js` acrescenta
   "modo-nova-password" a #caixa-auth quando a página abre com "?token=" na
   URL; nesse estado escondem-se os outros três (login/registo/esqueci) e o
   painel deslizante, e mostra-se só este. */
.formulario-nova-password {
  display: none;
  left: 0;
  width: 100%;
  z-index: 10;
}

#caixa-auth.modo-nova-password .formulario-login,
#caixa-auth.modo-nova-password .formulario-registo,
#caixa-auth.modo-nova-password .formulario-esqueci-password,
#caixa-auth.modo-nova-password .painel-deslizante-caixa {
  display: none;
}

#caixa-auth.modo-nova-password .formulario-nova-password {
  display: flex;
}

.caixa-auth label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.9rem;
  color: rgba(255, 255, 255, 0.85);
}

.form-chat input {
  padding: 0.5rem;
  border: 1px solid var(--cor-borda);
  border-radius: 4px;
  font-size: 1rem;
}

/* Inputs em vidro fosco, a condizer com a caixa — fundo claro sólido (como
   .form-chat) ficaria destacado a mais sobre o fundo escuro do login. */
.caixa-auth input {
  padding: 0.55rem 0.7rem;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 6px;
  font-size: 1rem;
  background: rgba(255, 255, 255, 0.12);
  color: white;
  transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}

.caixa-auth input::placeholder {
  color: rgba(255, 255, 255, 0.5);
}

.caixa-auth input:focus {
  outline: none;
  border-color: #6fa8dc;
  background: rgba(255, 255, 255, 0.2);
  box-shadow: 0 0 0 3px rgba(111, 168, 220, 0.3);
}

/* Ícone pequeno (pessoa / cadeado) dentro do campo, encostado à direita —
   "pointer-events: none" para o ícone nunca roubar o clique ao input por
   baixo. */
.campo-com-icone {
  position: relative;
  display: block;
}

.campo-com-icone input {
  width: 100%;
  padding-right: 2.25rem;
}

.icone-campo {
  position: absolute;
  top: 50%;
  right: 0.65rem;
  transform: translateY(-50%);
  color: rgba(255, 255, 255, 0.45);
  pointer-events: none;
}

button {
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 4px;
  background: var(--cor-primaria);
  color: white;
  cursor: pointer;
  font-size: 1rem;
  transition: transform 0.12s ease;
}

button:active {
  transform: scale(0.94);
}

.caixa-auth button[type="submit"] {
  padding: 0.65rem 1rem;
  font-weight: 600;
  transition: transform 0.12s ease, box-shadow 0.2s ease;
}

.caixa-auth button[type="submit"]:hover {
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.3);
  transform: translateY(-1px);
}

/* Painel deslizante: começa na meia-caixa esquerda (modo login) e desliza
   para a direita (translateX de 100% da sua própria largura = 50% da
   caixa) quando se muda para o modo registo. O conteúdo interno faz um
   cross-fade sincronizado, para mostrar a mensagem certa em cada lado. */
.painel-deslizante-caixa {
  position: absolute;
  top: 0;
  left: 0;
  width: 50%;
  height: 100%;
  overflow: hidden;
  z-index: 5;
  transition: transform 0.6s ease-in-out;
}

#caixa-auth.modo-registo .painel-deslizante-caixa {
  transform: translateX(100%);
}

.painel-deslizante {
  position: relative;
  width: 100%;
  height: 100%;
  background: linear-gradient(135deg, #163a5c 0%, #1f3a56 50%, #2e5c8a 100%);
}

.painel-lado {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 0.75rem;
  padding: 0 2rem;
  color: white;
  transition: opacity 0.3s ease;
}

.painel-lado h2 {
  margin: 0;
  font-size: 1.4rem;
}

.painel-lado p {
  margin: 0;
  font-size: 0.9rem;
  color: rgba(255, 255, 255, 0.85);
}

/* pointer-events:none no lado escondido é essencial: os dois ".painel-lado"
   ocupam o mesmo espaço (inset:0) sobrepostos, e "opacity:0" sozinho não
   desativa cliques — sem isto, o botão invisível por cima bloqueava sempre
   os cliques no botão visível por baixo. */
.painel-esquerdo {
  opacity: 1;
  pointer-events: auto;
}

.painel-direito {
  opacity: 0;
  pointer-events: none;
}

#caixa-auth.modo-registo .painel-esquerdo {
  opacity: 0;
  pointer-events: none;
}

#caixa-auth.modo-registo .painel-direito {
  opacity: 1;
  pointer-events: auto;
}

/* Botão "Entrar"/"Criar conta" do painel colorido — contorno em vez de
   preenchido, para não competir visualmente com o botão de submeter do
   formulário ao lado. */
.botao-contorno {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.7);
  padding: 0.55rem 1.5rem;
  border-radius: 999px;
  font-weight: 600;
  transition: background 0.2s ease, transform 0.12s ease;
}

.botao-contorno:hover {
  background: rgba(255, 255, 255, 0.15);
  transform: translateY(-1px);
}

/* "Esqueceste-te da password?"/"Voltar ao login" — parecem um link de
   texto, não um botão a sério, para não competir com o botão de submeter
   de cada formulário (mesma ideia de .botao-contorno acima, só que sem
   contorno nenhum). */
.botao-link {
  background: none;
  border: none;
  padding: 0;
  color: rgba(255, 255, 255, 0.75);
  font-size: 0.85rem;
  text-decoration: underline;
  align-self: flex-start;
  cursor: pointer;
}

.botao-link:hover {
  color: white;
}

.texto-auxiliar-auth {
  margin: -0.5rem 0 0;
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.75);
}

@media (max-width: 640px) {
  .caixa-auth {
    max-width: 340px;
    min-height: 0;
  }

  .formulario-container {
    position: static;
    width: 100%;
    transition: none;
  }

  .formulario-container form {
    padding: 2rem 1.75rem 0.5rem;
  }

  .formulario-login {
    display: flex;
  }

  .formulario-registo {
    display: none;
    opacity: 1;
    pointer-events: auto;
  }

  /* Mesma ideia de .formulario-registo acima — sem isto, "esqueci-password"
     ficava empilhado por baixo do login em vez de escondido, já que
     "position: static" (regra de cima) tira os dois do esquema de
     sobreposição por opacidade que o desktop usa. */
  .formulario-esqueci-password {
    display: none;
    opacity: 1;
    pointer-events: auto;
  }

  #caixa-auth.modo-registo .formulario-login {
    display: none;
  }

  #caixa-auth.modo-registo .formulario-registo {
    display: flex;
  }

  #caixa-auth.modo-esqueci .formulario-login {
    display: none;
  }

  #caixa-auth.modo-esqueci .formulario-esqueci-password {
    display: flex;
  }

  /* Repete o seletor completo do modo-registo (não só ".painel-deslizante-caixa")
     de propósito: a regra de desktop "#caixa-auth.modo-registo
     .painel-deslizante-caixa" tem um ID e ganha sempre a um simples
     ".painel-deslizante-caixa" aqui dentro, mesmo em telemóvel — sem repetir o
     seletor todo, o painel continuava a deslocar-se para fora do ecrã no modo
     registo (mesma armadilha de especificidade documentada no CLAUDE.md). */
  .painel-deslizante-caixa,
  #caixa-auth.modo-registo .painel-deslizante-caixa {
    position: static;
    width: 100%;
    height: auto;
    transform: none;
  }

  .painel-deslizante {
    height: auto;
  }

  .painel-lado {
    position: static;
    padding: 1.25rem 1.75rem 2rem;
    display: none;
  }

  .painel-esquerdo {
    display: flex;
  }

  #caixa-auth.modo-registo .painel-esquerdo {
    display: none;
  }

  #caixa-auth.modo-registo .painel-direito {
    display: flex;
  }
}

/* Mesma armadilha de especificidade documentada mais abaixo (ver CLAUDE.md):
   repete os seletores exatos em vez de ".caixa-auth *". */
@media (prefers-reduced-motion: reduce) {
  .caixa-auth,
  .fundo-login .blob,
  .painel-deslizante-caixa,
  .formulario-container,
  .painel-lado,
  .cartao-skill,
  .caixa-detalhe-skill {
    animation: none;
    transition: none;
  }
}

.erro {
  color: #b3261e;
  font-size: 0.9rem;
}

.caixa-auth .erro {
  color: #ff8a80;
}

.sucesso {
  color: #2e7d32;
  font-size: 0.9rem;
}

/* ---------- Dashboard ---------- */

body.pagina-dashboard {
  background: var(--cor-fundo-dashboard);
}

.topo {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 1rem 1.5rem;
  background: transparent;
  border-bottom: 1px solid rgba(255, 255, 255, 0.15);
  /* Cor de texto branca fica limitada ao cabeçalho, para não afetar modais e o painel de chat que herdariam este branco */
  color: white;
}

.info-utilizador {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: 600;
  justify-self: start;
}

.titulo-topo {
  margin: 0;
  font-size: 1.35rem;
  font-weight: 800;
  letter-spacing: 0.02em;
  color: white;
  justify-self: center;
  text-align: center;
}

.etiqueta-nivel {
  background: var(--cor-primaria);
  color: white;
  border-radius: 999px;
  padding: 0.1rem 0.6rem;
  font-size: 0.8rem;
  font-weight: normal;
}

.topo-direita {
  display: flex;
  align-items: center;
  gap: 1rem;
  justify-self: end;
}

.bloco-relogio {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  line-height: 1.3;
}

.relogio {
  font-variant-numeric: tabular-nums;
  color: #cbd5e0;
  font-size: 0.95rem;
}

.data-atual {
  font-size: 0.75rem;
  color: #8fa2b3;
}

#btn-sair {
  background: transparent;
  color: white;
  border: 1px solid white;
  padding: 0.3rem 0.7rem;
  font-size: 0.85rem;
}

/* ---------- Abas do dashboard (barra lateral esquerda) ----------
   Já foi uma faixa horizontal por baixo do cabeçalho, com sublinhado azul na
   aba ativa; passou a coluna à esquerda de .conteudo (mesmo lugar da antiga
   nav.barra-lateral, removida noutra altura) — texto pequeno e um fundo
   destacado na aba ativa, em vez do sublinhado, que não fazia sentido numa
   lista vertical. */
.abas-dashboard {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  flex: none;
  width: 190px;
  padding: 1.25rem 0.75rem;
  border-bottom: none;
  border-right: 1px solid rgba(255, 255, 255, 0.15);
}

.aba-dashboard {
  align-items: center;
  gap: 0.55rem;
  background: transparent;
  border: none;
  border-radius: 6px;
  padding: 0.5rem 0.75rem;
  color: rgba(255, 255, 255, 0.6);
  font-weight: 600;
  font-size: 0.8rem;
  text-align: left;
  transition: color 0.15s ease, background-color 0.15s ease;
}

/* "display: flex" fica só aqui, condicional a não ter o atributo "hidden" —
   um "display: flex" incondicional em ".aba-dashboard" tem a mesma
   especificidade do "[hidden] { display: none }" do próprio browser (uma
   classe e um atributo pesam o mesmo), e por vir de uma folha de estilos de
   autor ganha ao UA mesmo com o "hidden" presente. Era exatamente isto que
   escondia "Pedidos pendentes"/"Histórico de decisões"/"Histórico de
   downloads" de quem não é nível 5 — as três continuavam visíveis na barra
   lateral apesar do atributo "hidden" (foi um bug real, o mesmo já apanhado
   uma vez em #painel-detalhe-skill, ver mais abaixo). */
.aba-dashboard:not([hidden]) {
  display: flex;
}

.aba-dashboard svg {
  flex: none;
}

.aba-dashboard:hover {
  color: white;
}

.aba-dashboard:active {
  transform: none;
}

.aba-dashboard.aba-ativa {
  color: white;
  background: rgba(255, 255, 255, 0.1);
}

/* Título da aba inicial "Dashboard". Precisa de cor própria porque o
   "color: #1c2733" do body é pensado para caixas brancas, não para o fundo
   escuro de .conteudo. */
#painel-dashboard-inicial h2 {
  color: white;
  margin: 0 0 1.25rem;
}

/* ---------- Dashboard inicial: gráficos ----------
   Os próprios gráficos são SVG desenhado à mão em chat.js
   (desenharGraficoDonut()/desenharGraficoLinhas()) — sem biblioteca nenhuma,
   para não introduzir a primeira dependência externa deste projeto. Este CSS
   só trata do "cartão" à volta de cada gráfico. */
.grelha-dashboard {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 1.25rem;
}

/* "Skills por nível" e "Utilizadores por nível" empilhados nesta coluna
   estreita, ao lado do gráfico grande (.cartao-grafico-grande) — ver
   comentário em chat.html sobre porquê deixarem de estar os três lado a
   lado do mesmo tamanho. */
.coluna-graficos-pequenos {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.cartao-grafico {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 6px;
  padding: 1rem 1.25rem;
  min-width: 220px;
}

.cartao-grafico-grande {
  flex: 1;
  min-width: 320px;
}

.grafico-vazio {
  padding: 0.75rem;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.55);
  text-align: center;
}

.cartao-grafico h3 {
  margin: 0 0 0.75rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: white;
}

.marcador-legenda {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 2px;
}

/* Legenda dos donuts "Skills por nível"/"Utilizadores por nível" — uma linha
   por fatia (cor + nível + contagem), preenchida em chat.js. */
.legenda-donut {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.75);
}

.legenda-donut li {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

/* Cada aba mostra/esconde o seu painel correspondente — sem "display"
   declarado aqui, o [hidden] do browser já chega sozinho (ao contrário de
   ".caixa-historico" etc., que têm "display: flex" e por isso precisam da
   regra [hidden] explícita documentada mais abaixo). */
.painel-aba {
  width: 100%;
}

/* As caixas reaproveitadas da barra lateral (histórico, pedidos, decisões,
   "os meus pedidos") ficam com muito mais espaço aqui do que tinham
   espremidas na barra lateral — alarga-se a largura e remove-se o limite de
   altura pensado para um espaço estreito, sem mexer no resto do estilo
   (cores, layout dos itens, etc.) para não duplicar código. */
.painel-aba .caixa-historico,
.painel-aba .caixa-pedidos,
.painel-aba .caixa-decisoes,
.painel-aba .caixa-meus-pedidos,
.painel-aba .caixa-utilizadores {
  max-width: 640px;
  margin-top: 0;
}

.painel-aba .lista-historico,
.painel-aba .lista-pedidos,
.painel-aba .lista-decisoes,
.painel-aba .lista-meus-pedidos {
  max-height: none;
}

/* Ações de administração sobre skills (dentro de #painel-gerir, ver
   .botao-gerir mais abaixo) — já foram botões de largura total numa barra
   lateral fixa, removida por só servir para isto; mantido o mesmo visual
   (largura total, cores por ação) agora empilhado dentro do modal "Gerir".
   "− Utilizador"/"Mudar Nível" saíram daqui — ver .item-utilizador-acoes
   mais abaixo, dentro da aba "Utilizadores". */
#btn-criar-skill,
#btn-remover-skill {
  width: 100%;
  color: white;
  border: none;
  padding: 0.9rem 1rem;
  font-size: 0.95rem;
  border-radius: 6px;
  cursor: pointer;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

/* Mesma animação de hover dos cartões de skill (.cartao-skill:hover). */
#btn-criar-skill:hover,
#btn-remover-skill:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
  transform: translateY(-2px);
}

#btn-criar-skill {
  background: #2e7d32;
}

#btn-remover-skill {
  background: #b3261e;
}

/* "Renomear" vive agora dentro do painel de Definições, lado a lado com
   "Mudar Email"/"Mudar Password" — mantém a cor original (propositadamente
   diferente do azul mais escuro do resto da dashboard), mas já não precisa
   da largura total nem da animação de hover da lista acima, porque aqui
   dentro é só mais um botão em .definicoes-acoes (display:flex, tamanho ao
   conteúdo), tal como os do lado. */
#btn-renomear-utilizador {
  background: #2d5c8a;
}

/* ---------- Os meus pedidos (qualquer nível) ---------- */

.caixa-meus-pedidos {
  display: flex;
  flex-direction: column;
  margin-top: 0.35rem;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 6px;
  overflow: hidden;
}

.caixa-meus-pedidos-cabecalho {
  padding: 0.6rem 0.75rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: white;
  border-bottom: 1px solid rgba(255, 255, 255, 0.15);
}

.lista-meus-pedidos {
  max-height: 240px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

.item-meu-pedido {
  padding: 0.5rem 0.75rem;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.85);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.item-meu-pedido:last-child {
  border-bottom: none;
}

.item-meu-pedido-skill {
  display: block;
  font-weight: 600;
}

.item-meu-pedido-skill.estado-pendente {
  color: #ffca80;
}

.item-meu-pedido-skill.estado-aprovado,
.item-meu-pedido-skill.estado-concluido {
  color: #81c784;
}

.item-meu-pedido-skill.estado-recusado {
  color: #ff8a80;
}

.item-meu-pedido-meta {
  display: block;
  margin-top: 0.15rem;
  color: rgba(255, 255, 255, 0.55);
}

.item-meu-pedido-nota {
  display: block;
  margin-top: 0.25rem;
  font-style: italic;
  color: rgba(255, 255, 255, 0.7);
}

.meus-pedidos-vazio {
  padding: 0.75rem;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.55);
  text-align: center;
}

/* ---------- Utilizadores registados (qualquer nível) ---------- */

.caixa-utilizadores {
  display: flex;
  flex-direction: column;
  margin-top: 0.35rem;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 6px;
  overflow: hidden;
  padding-bottom: 0.5rem;
}

.caixa-utilizadores-cabecalho {
  padding: 0.6rem 0.75rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: white;
  border-bottom: 1px solid rgba(255, 255, 255, 0.15);
}

.lista-utilizadores {
  display: flex;
  flex-direction: column;
}

/* Um cartão por utilizador, não uma linha de tabela — "Mudar Nível"/"Remover"
   (só nível 5, ver .item-utilizador-acoes abaixo) ficam por baixo do nome,
   dentro do próprio cartão, tal como pedido: já não fazem parte do modal
   "Gerir" nem exigem escrever o username à mão. */
.item-utilizador {
  padding: 0.5rem 0.75rem;
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.85);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.item-utilizador:last-child {
  border-bottom: none;
}

.item-utilizador-nome {
  display: block;
  font-weight: 600;
}

.item-utilizador-meta {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.55);
}

.item-utilizador-acoes {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.4rem;
}

.item-utilizador-acoes button {
  padding: 0.3rem 0.6rem;
  font-size: 0.7rem;
  border-radius: 4px;
}

.botao-mudar-nivel-utilizador {
  background: #5c4a8a;
}

/* Por baixo da caixa de utilizadores registados (não dentro dela), tal como
   pedido — mesmo visual das ações de administração de #painel-gerir. */
.botao-criar-utilizador {
  width: 100%;
  max-width: 640px;
  margin-top: 0.6rem;
  background: #2e7d32;
  color: white;
  border: none;
  padding: 0.9rem 1rem;
  font-size: 0.95rem;
  border-radius: 6px;
  cursor: pointer;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.botao-criar-utilizador:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
  transform: translateY(-2px);
}

/* ---------- Pedidos de download pendentes (só nível 5) ---------- */

.caixa-pedidos {
  display: flex;
  flex-direction: column;
  margin-top: 0.35rem;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 6px;
  overflow: hidden;
}

.caixa-pedidos-cabecalho {
  padding: 0.6rem 0.75rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: white;
  border-bottom: 1px solid rgba(255, 255, 255, 0.15);
}

.lista-pedidos {
  max-height: 240px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

.item-pedido {
  padding: 0.5rem 0.75rem;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.85);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.item-pedido:last-child {
  border-bottom: none;
}

.item-pedido-skill {
  display: block;
  font-weight: 600;
  color: white;
}

.item-pedido-meta {
  display: block;
  margin-top: 0.15rem;
  color: rgba(255, 255, 255, 0.55);
}

/* Abre o modal #modal-validar-pedido (reaproveita .modal-caixa-detalhe-skill)
   — ver .botao-aceitar-pedido mais abaixo para o botão verde lá dentro. */
.botao-validar-pedido {
  width: 100%;
  margin-top: 0.4rem;
  padding: 0.3rem 0.5rem;
  font-size: 0.7rem;
  border-radius: 4px;
}

/* Reaproveitado também como botão "Aceitar" (verde) dentro de
   #modal-validar-pedido — só a cor de fundo importa aqui, o tamanho vem do
   botão normal nesse contexto. */
.botao-aceitar-pedido {
  background: #2e7d32;
}

.pedidos-vazio {
  padding: 0.75rem;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.55);
  text-align: center;
}

/* ---------- Histórico de decisões (só nível 5) ---------- */

.caixa-decisoes {
  display: flex;
  flex-direction: column;
  margin-top: 0.35rem;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 6px;
  overflow: hidden;
}

.caixa-decisoes-cabecalho {
  padding: 0.6rem 0.75rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: white;
  border-bottom: 1px solid rgba(255, 255, 255, 0.15);
}

.lista-decisoes {
  max-height: 240px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

.item-decisao {
  padding: 0.5rem 0.75rem;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.85);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.item-decisao:last-child {
  border-bottom: none;
}

.item-decisao-skill {
  display: block;
  font-weight: 600;
}

.item-decisao-skill.item-decisao-aprovado {
  color: #81c784;
}

.item-decisao-skill.item-decisao-recusado {
  color: #ff8a80;
}

.item-decisao-meta {
  display: block;
  margin-top: 0.15rem;
  color: rgba(255, 255, 255, 0.55);
}

.item-decisao-nota {
  display: block;
  margin-top: 0.25rem;
  font-style: italic;
  color: rgba(255, 255, 255, 0.7);
}

.decisoes-vazio {
  padding: 0.75rem;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.55);
  text-align: center;
}

/* ---------- Histórico de downloads (só nível 5) ---------- */

.caixa-historico {
  display: flex;
  flex-direction: column;
  margin-top: 0.35rem;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 6px;
  overflow: hidden;
}

.caixa-historico-cabecalho {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.6rem 0.75rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: white;
  border-bottom: 1px solid rgba(255, 255, 255, 0.15);
}

.botao-limpar-historico {
  background: transparent;
  padding: 0;
  border: none;
  color: #ff8a80;
  font-size: 0.75rem;
  font-weight: normal;
  text-decoration: underline;
}

.botao-limpar-historico:hover {
  color: #ffb4a9;
}

/* Scroll só nesta lista — a barra lateral em si não desloca. */
.lista-historico {
  max-height: 240px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

.item-historico {
  padding: 0.5rem 0.75rem;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.85);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.item-historico:last-child {
  border-bottom: none;
}

.item-historico-skill {
  display: block;
  font-weight: 600;
  color: white;
}

.item-historico-meta {
  display: block;
  margin-top: 0.15rem;
  color: rgba(255, 255, 255, 0.55);
}

.historico-vazio {
  padding: 0.75rem;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.55);
  text-align: center;
}

/* ---------- Definições da conta (qualquer nível) ---------- */

.caixa-definicoes {
  display: flex;
  flex-direction: column;
  width: min(560px, calc(100vw - 3rem));
  /* Sólida de propósito (nada de rgba/transparência) — o painel abre ao
     centro do ecrã por cima de tudo o resto (ver .modal-fundo em
     #painel-definicoes), teria de ser opaca para não deixar ver o que está
     por trás. */
  background: var(--cor-fundo-dashboard);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 10px;
  overflow: hidden;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
  transform: scale(0.92) translateY(10px);
  transition: transform 0.2s ease;
}

.modal-fundo.aberto .caixa-definicoes {
  transform: scale(1) translateY(0);
}

.caixa-definicoes-cabecalho {
  padding: 1.1rem 1.5rem;
  font-size: 1.1rem;
  font-weight: 600;
  color: white;
  border-bottom: 1px solid rgba(255, 255, 255, 0.15);
}

.definicoes-conteudo {
  display: flex;
  flex-direction: column;
  gap: 2rem;
  padding: 2rem;
}

.definicoes-info h3 {
  margin: 0 0 1rem;
  font-size: 0.9rem;
  color: rgba(255, 255, 255, 0.6);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.definicoes-info p {
  margin: 0 0 0.85rem;
  font-size: 1rem;
  color: rgba(255, 255, 255, 0.9);
}

.definicoes-info p strong {
  color: rgba(255, 255, 255, 0.6);
  font-weight: 600;
  margin-right: 0.4rem;
}

.definicoes-acoes {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

/* "Mudar Email"/"Mudar Password" ficam com o estilo padrão de botão (fundo
   sólido, sempre legível em qualquer fundo). "Fechar" precisa do seu
   próprio estilo em vez de .botao-secundario (pensado para modais de fundo
   branco: texto cinza-escuro que ficaria ilegível aqui, em cima do fundo
   escuro sólido de .caixa-definicoes). */
.botao-fechar-definicoes {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.35);
  color: rgba(255, 255, 255, 0.85);
}

.botao-fechar-definicoes:hover {
  background: rgba(255, 255, 255, 0.1);
}

/* ---------- Modal: criar utilizador ---------- */

.modal-fundo {
  position: fixed;
  inset: 0;
  background: rgba(28, 39, 51, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1100;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

.modal-fundo.aberto {
  opacity: 1;
  pointer-events: auto;
}

.modal-caixa {
  background: white;
  color: #1c2733;
  border-radius: 10px;
  padding: 1.75rem;
  width: 320px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.2);
  transform: scale(0.92) translateY(10px);
  transition: transform 0.2s ease;
}

.modal-fundo.aberto .modal-caixa {
  transform: scale(1) translateY(0);
}

.modal-caixa-detalhe-skill {
  position: relative;
  width: 700px;
  min-height: 420px;
  padding: 3rem;
  display: flex;
  flex-direction: column;
}

/* #painel-detalhe-skill continua tecnicamente um ".painel-aba" (ativado por
   ativarAba("detalhe-skill") em chat.js, sem botão próprio em
   nav.abas-dashboard) — mas visualmente deixou de "ocupar a página toda" e
   passou a aparecer como um popup centrado sobre a página anterior, que fica
   visível por baixo mas desfocada (backdrop-filter: blur, mesma técnica já
   usada em .caixa-auth para o "vidro fosco" do login) — a ideia é dar a
   sensação de abrir algo secundário por cima, sem sair de onde se estava,
   ao contrário de um fundo escurecido opaco que esconde tudo por completo.
   Fica de fora do fluxo de .conteudo via position:fixed, cobrindo inclusive
   os botões flutuantes (Gerir/Definições/chat), tal como as .modal-fundo
   desta app (mesmo z-index) — só que sem ser mesmo um modal.
   O "display: flex" fica só na regra ":not([hidden])" de propósito — um
   "#painel-detalhe-skill { display: flex }" incondicional tem mais
   especificidade (ID) do que o "[hidden] { display: none }" do próprio
   browser (atributo), por isso ganhava mesmo com o atributo "hidden"
   presente: a caixa ficava invisível (opacity/posição não mudam) mas
   continuava a ocupar o ecrã todo e a intercetar cliques nos cartões de
   skill por baixo (foi um bug real, apanhado a testar). */
#painel-detalhe-skill {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 32, 0.25);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  z-index: 1100;
}

#painel-detalhe-skill:not([hidden]) {
  display: flex;
}

/* Era a versão "página" da mesma caixa que existe em .modal-caixa-detalhe-skill
   (mesmo cabeçalho/separador/descrição/ações, partilhados via classes
   genéricas); agora que #painel-detalhe-skill já traz o próprio fundo escuro
   à volta, esta caixa branca centrada é visualmente indistinguível de um
   modal — só continua por fora de .modal-fundo porque entra/sai pelo sistema
   de abas (ativarAba), não por uma classe "aberto". */
.caixa-detalhe-skill {
  position: relative;
  width: 100%;
  max-width: 700px;
  min-height: 420px;
  padding: 3rem;
  display: flex;
  flex-direction: column;
  background: white;
  color: #1c2733;
  border-radius: 10px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
  /* Repete sozinha sempre que #painel-detalhe-skill deixa de estar [hidden]:
     abrirDetalheSkill() em chat.js só troca de aba (display none -> flex),
     não mexe em classes — uma animação normal já reinicia nesse instante,
     não é preciso nenhum JS extra para "replay". */
  animation: entrada-detalhe-skill 0.2s ease;
}

@keyframes entrada-detalhe-skill {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Saída: ao contrário da entrada, não basta uma regra CSS sozinha — esconder
   o painel (ativarAba("skills") faz hidden = display:none) já não deixa
   tempo nenhum para a transição acontecer, por isso voltarDeDetalheSkill()
   em chat.js só chama ativarAba() depois de ".a-fechar" terminar
   (animationend). "forwards" mantém o estado final (opacity:0) durante essa
   espera, senão a caixa "saltava" de volta ao fim da animação, um instante
   antes de o hidden a esconder de vez. */
#painel-detalhe-skill.a-fechar {
  animation: saida-fundo-detalhe-skill 0.15s ease forwards;
}

#painel-detalhe-skill.a-fechar .caixa-detalhe-skill {
  animation: saida-detalhe-skill 0.15s ease forwards;
}

@keyframes saida-detalhe-skill {
  from {
    opacity: 1;
    transform: translateY(0);
  }
  to {
    opacity: 0;
    transform: translateY(10px);
  }
}

@keyframes saida-fundo-detalhe-skill {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

.caixa-detalhe-skill h2 {
  margin: 0;
  flex: 1;
  min-width: 0;
}

/* Ao contrário do resto da app (.modal-acoes agrupa tudo à direita, ver
   regra genérica mais abaixo), aqui há dois grupos, um em cada ponta:
   "Voltar"/"Selecionar skill" (ou Cancelar/Guardar descrição durante a
   edição) à esquerda, "Guardar alterações" à direita quando aparece — para
   uma ação de navegação/consumo nunca se confundir com uma de gravar
   metadados. Cada grupo (`.modal-acoes-grupo`) é só um `display: flex` com
   o mesmo espaçamento entre botões que .modal-acoes já tinha. */
.caixa-detalhe-skill .modal-acoes {
  margin-top: auto;
  padding-top: 1.5rem;
  justify-content: space-between;
}

.modal-acoes-grupo {
  display: flex;
  gap: 0.5rem;
}

.cabecalho-detalhe-skill {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  /* Espaço à direita para o texto nunca ficar por baixo dos botões de
     editar/eliminar (dois agora, ver .botao-editar-descricao/.botao-eliminar-
     skill-detalhe). Espaço à esquerda pela mesma razão, desta vez para a
     bola/select de nível mínimo, que saiu desta linha e passou a sobrepor-se
     ao canto superior esquerdo da caixa (ver .bola-nivel-detalhe abaixo). */
  padding-right: 5.25rem;
  padding-left: 3rem;
}

.modal-caixa-detalhe-skill h2 {
  margin: 0;
  flex: 1;
  min-width: 0;
}

.bola-nivel {
  flex: none;
  border-radius: 50%;
  background: #6b7684;
  color: white;
  align-items: center;
  justify-content: center;
  font-weight: 700;
}

/* "display: flex" fica condicional a não ter "hidden" — mesma armadilha de
   especificidade já documentada várias vezes nesta app (ver
   .etiqueta-categoria acima). Não fazia diferença enquanto só
   ".bola-nivel-cartao" usava esta classe (nunca alterna "hidden", é só
   criada quando já se sabe que é preciso), mas agora ".bola-nivel-skill"
   também alterna "hidden" em abrirDetalheSkill() (só um de "bola" ou
   "select" fica visível de cada vez, consoante o nível de quem vê o
   detalhe) — sem esta guarda, a bola ficava visível por cima do select. */
.bola-nivel:not([hidden]) {
  display: flex;
}

.bola-nivel-skill {
  width: 32px;
  height: 32px;
  font-size: 0.95rem;
}

/* Sobreposta ao canto superior esquerdo da caixa de detalhe — simétrica aos
   botões de editar/eliminar, que ocupam o canto superior direito (mesmo
   "top"). Partilhada pela bola só-leitura e pelo <select> equivalente (só
   um dos dois visível de cada vez, ver comentário em chat.html). */
.bola-nivel-detalhe {
  position: absolute;
  top: 1.5rem;
  left: 1.5rem;
}

/* <select> com a mesma forma da bola de nível (círculo, número centrado) em
   vez de pílula como .select-estado-skill — só nível 5 o vê (ver
   podeGerirEstadoSkill em chat.js), para mudar o nível mínimo da skill sem
   modal à parte. "text-align-last" centra o valor escolhido (o "text-align"
   sozinho só afeta as opções da lista, não o valor fechado). Mesma
   armadilha de "hidden" que .bola-nivel acima — também alterna consoante o
   nível de quem vê o detalhe. */
.select-nivel-skill:not([hidden]) {
  display: flex;
}

.select-nivel-skill {
  width: 32px;
  height: 32px;
  font-size: 0.95rem;
  border: none;
  border-radius: 50%;
  color: white;
  background: #6b7684;
  font-weight: 700;
  text-align: center;
  text-align-last: center;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  padding: 0;
}

/* Mesma bola, em miniatura, sobreposta ao canto do cartão da grelha — para o
   nível mínimo ser visível sem ser preciso abrir o detalhe da skill. */
.bola-nivel-cartao {
  position: absolute;
  top: 6px;
  left: 6px;
  width: 20px;
  height: 20px;
  font-size: 0.68rem;
}

/* Etiqueta de categoria — usada tanto num cartão da grelha (dentro de
   .textos-skill, entre o nome e a descrição) como no cabeçalho do detalhe da
   skill (#detalhe-skill-categoria, que tem "hidden" no HTML e é
   desescondido em chat.js quando a skill tem categoria). Só aparece quando a
   skill tem categoria (ver rotuloCategoria() em chat.js) — skills criadas
   antes desta coluna existir ficam sem etiqueta nenhuma, não com "null"
   escrito.
   "display: inline-block" fica só condicional a não ter "hidden" — mesma
   armadilha de especificidade já documentada em #painel-detalhe-skill/
   .aba-dashboard/.botao-editar-descricao/.botao-gerir (uma classe e um
   atributo pesam o mesmo, e uma regra de autor incondicional ganha ao
   "[hidden]" do browser mesmo com o atributo presente). O cartão da grelha
   nunca usa "hidden" nesta classe (só existe no DOM quando já há rótulo),
   por isso não precisava da guarda por si só — mas a regra é partilhada
   pelas duas, e mais vale estar sempre certa do que confiar em nunca reutilizar
   esta classe nalgum sítio com "hidden". */
.etiqueta-categoria {
  align-self: flex-start;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.65rem;
  font-weight: 600;
  color: white;
  background: #6b7684;
}

.etiqueta-categoria:not([hidden]) {
  display: inline-block;
}

/* No cartão da grelha, o grupo de etiquetas (ver .badges-categoria-cartao
   abaixo) sai do fluxo normal e fica sobreposto ao canto inferior direito —
   simétrico à bola de nível mínimo, que já ocupa o canto superior esquerdo
   (.bola-nivel-cartao). */
.etiqueta-categoria-design {
  background: #ba68c8;
}

.etiqueta-categoria-coding {
  background: #5b9bd5;
}

.etiqueta-categoria-process {
  background: #4db6ac;
}

/* Uma skill pode ter várias categorias (ver Skill.categorias em models.py),
   mas o cartão da grelha só tem espaço para uma etiqueta de cada vez sem
   voltar a arriscar sobreposição com a descrição (ver a faixa reservada em
   .cartao-skill acima). Por isso só se mostra a primeira categoria
   (etiqueta normal, colorida) e, se houver mais, uma segunda etiqueta
   pequena e neutra tipo "+1" ao lado — a lista completa fica só um clique
   de distância, no detalhe da skill. Este `<div>` é que fica ancorado ao
   canto (não cada etiqueta individualmente), para as duas ficarem coladas
   uma à outra sem ser preciso saber a largura de cada uma de antemão. */
.badges-categoria-cartao {
  position: absolute;
  bottom: 8px;
  right: 8px;
  display: flex;
  align-items: center;
  gap: 4px;
}

.etiqueta-categoria-extra {
  padding: 0.1rem 0.4rem;
  border-radius: 999px;
  font-size: 0.65rem;
  font-weight: 600;
  color: white;
  background: #6b7684;
  flex: none;
}

/* Lista de etiquetas de categoria no cabeçalho do detalhe — ao contrário do
   cartão da grelha (só a primeira + "+N"), aqui há espaço para mostrar
   todas, uma etiqueta normal por categoria, com quebra de linha se não
   couberem (flex-wrap). Serve tanto para a versão só-leitura
   (#detalhe-skill-categorias) como para o próprio grupo de "chips"
   editáveis (#detalhe-skill-categorias-editor, ver .chip-categoria abaixo)
   — os dois têm exatamente a mesma disposição, só o conteúdo é que muda
   consoante o nível de quem vê (ver abrirDetalheSkill() em chat.js).
   "display" condicional a não ter "hidden" — mesma armadilha de
   especificidade já documentada várias vezes nesta app (ver
   .etiqueta-categoria acima): tanto a versão só-leitura como a de "chips"
   alternam "hidden" consoante o nível de quem vê e (a só-leitura) se há
   alguma categoria para mostrar. */
.lista-categorias-detalhe:not([hidden]) {
  display: flex;
}

.lista-categorias-detalhe {
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
}

/* "Chip" clicável para ligar/desligar uma categoria no detalhe da skill —
   só nível 5 o vê. Mesma forma de pílula da etiqueta só-leitura, mas
   sempre visível (as três categorias fixas, ver CATEGORIAS_VALIDAS no
   backend) em vez de aparecer/desaparecer: inativo é um contorno neutro,
   ativo ganha a cor da própria categoria (.chip-categoria-ativa.etiqueta-
   categoria-<categoria>, reaproveitando as mesmas cores de sempre em vez
   de as duplicar) — mesma ideia de toggle dos filtros da grelha
   (.filtro-categoria/.categoria-ativa), só que aqui cada categoria liga-se
   e desliga-se de forma independente das outras, não são mutuamente
   exclusivas. Mudar fica só em memória até "Guardar alterações" (ver
   #btn-guardar-alteracoes-skill) — não há pedido nenhum ao clicar um chip
   por si só. */
.chip-categoria {
  padding: 0.1rem 0.6rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid var(--cor-borda);
  background: white;
  color: #4a5560;
}

.chip-categoria-ativa {
  border-color: transparent;
  color: white;
}

.chip-categoria-ativa.etiqueta-categoria-design {
  background: #ba68c8;
}

.chip-categoria-ativa.etiqueta-categoria-coding {
  background: #5b9bd5;
}

.chip-categoria-ativa.etiqueta-categoria-process {
  background: #4db6ac;
}

/* Checkboxes de categoria no formulário "Criar skill" — substituem o
   antigo <select> único, para escolher zero, uma ou várias categorias sem
   Ctrl/Cmd+clique (ver #modal-criar-skill em chat.html). Fieldset sem a
   borda por omissão do browser, para não destacar demasiado dentro do
   resto do formulário (que usa só <label> simples). Em linha (não
   empilhadas) — pedido explícito, para caber "Categorias  Design Coding
   Process" numa única linha em vez de uma por baixo da outra; "flex-wrap"
   deixa quebrar para uma segunda linha sozinho se o modal ficar estreito
   a mais, sem precisar de media query nenhuma. */
.checkboxes-categorias {
  border: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.9rem;
}

.checkboxes-categorias legend {
  font-size: 0.85rem;
  font-weight: 600;
  padding: 0;
  margin: 0;
}

.opcao-checkbox {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-weight: 400;
  cursor: pointer;
}

/* Fieldset "Tipo" (interna/externa, ver Skill.tipo em models.py) no mesmo
   formulário — escolha única, por isso rádios em vez de checkboxes (o
   próprio HTML já impede mais que um marcado). Mesmo layout horizontal e
   mesmas classes-irmãs de .checkboxes-categorias/.opcao-checkbox acima, só
   que com nomes próprios porque o conteúdo é um conceito diferente
   (categoria vs. tipo), não uma reafectação da mesma classe. */
.opcoes-radio-tipo {
  border: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.9rem;
}

.opcoes-radio-tipo legend {
  font-size: 0.85rem;
  font-weight: 600;
  padding: 0;
  margin: 0;
}

.opcao-radio {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-weight: 400;
  cursor: pointer;
}

/* Etiqueta de estado do ciclo de vida da skill (registada/análise/ativa/
   inativa — ver ESTADOS_VALIDOS em skills_service.py, não confundir com o
   estado de um pedido de aprovação). Mesma base visual da categoria; usada
   tanto no cartão da grelha (canto superior direito, único ainda livre —
   inferior esquerdo tem o nível mínimo, inferior direito a categoria) como
   no cabeçalho do detalhe (#detalhe-skill-estado, só leitura).
   "display" fica condicional a não ter "hidden" pela mesma armadilha de
   especificidade já documentada em #painel-detalhe-skill/.etiqueta-categoria
   acima — #detalhe-skill-estado alterna "hidden" em abrirDetalheSkill(). */
.etiqueta-estado {
  align-self: flex-start;
  padding: 0.2rem 0.65rem;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 600;
  color: white;
  background: #6b7684;
}

.etiqueta-estado:not([hidden]) {
  display: inline-block;
}

.etiqueta-estado-cartao {
  position: absolute;
  top: 8px;
  right: 8px;
}

.etiqueta-estado-registada {
  background: #78909c;
}

.etiqueta-estado-analise {
  background: #f0a63a;
}

.etiqueta-estado-ativa {
  background: #43a047;
}

.etiqueta-estado-inativa {
  background: #b3261e;
}

/* Etiqueta "Interna"/"Externa" (Skill.tipo em models.py) — mesma base
   visual da etiqueta de estado/categoria, mas só usada no cabeçalho do
   detalhe (#detalhe-skill-tipo): de propósito, nunca aparece no cartão da
   grelha, ver nota em chat.html. Sem editor nenhum, por isso não há uma
   variante "select-tipo-skill" equivalente a select-estado-skill logo a
   seguir. Mesma armadilha de especificidade do "hidden" já documentada
   várias vezes nesta app — #detalhe-skill-tipo alterna "hidden" em
   abrirDetalheSkill() (chat.js). */
.etiqueta-tipo {
  align-self: flex-start;
  padding: 0.2rem 0.65rem;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 600;
  color: white;
  background: #6b7684;
}

.etiqueta-tipo:not([hidden]) {
  display: inline-block;
}

.etiqueta-tipo-interna {
  background: #37474f;
}

.etiqueta-tipo-externa {
  background: #6d4c41;
}

/* <select> equivalente à etiqueta de estado, mas editável — só nível 5 o vê
   (ver podeGerirEstadoSkill em chat.js), para mudar o estado da skill sem
   precisar de um modal à parte. Mesmas cores de fundo da etiqueta, para não
   parecer um elemento à parte quando se alterna entre os dois. Mesma
   armadilha de especificidade do "hidden" que .etiqueta-estado acima —
   também alterna "hidden" consoante o nível de quem vê o detalhe. */
.select-estado-skill:not([hidden]) {
  display: inline-block;
}

.select-estado-skill {
  align-self: flex-start;
  padding: 0.2rem 1.55rem 0.2rem 0.65rem;
  border: none;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 600;
  color: white;
  background-color: #6b7684;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.4rem center;
  background-size: 0.85rem;
}

.select-estado-skill.etiqueta-estado-registada {
  background-color: #78909c;
}

.select-estado-skill.etiqueta-estado-analise {
  background-color: #f0a63a;
}

.select-estado-skill.etiqueta-estado-ativa {
  background-color: #43a047;
}

.select-estado-skill.etiqueta-estado-inativa {
  background-color: #b3261e;
}

.modal-caixa-detalhe-skill .modal-acoes {
  margin-top: auto;
  padding-top: 1.5rem;
}

.info-validar-pedido {
  margin: 0 0 1rem;
  color: #4a5560;
  font-size: 0.9rem;
}

.separador-detalhe-skill {
  border: none;
  border-top: 3px solid #5b9bd5;
  margin: 0.9rem 0 1.25rem;
}

.botao-editar-descricao {
  position: absolute;
  top: 1.5rem;
  right: 1.5rem;
  width: 34px;
  height: 30px;
  padding: 0;
  border-radius: 6px;
  align-items: center;
  justify-content: center;
  background: #4a5560;
}

/* "display: flex" fica só condicional a não ter "hidden" — mesma armadilha
   de especificidade já documentada em #painel-detalhe-skill/.aba-dashboard
   (uma classe e um atributo pesam o mesmo, e uma regra de autor incondicional
   ganha ao "[hidden]" do browser mesmo com o atributo presente). Sem isto,
   este botão de editar a descrição aparecia a **qualquer** nível, não só
   nível 5 (foi um bug real, reportado a testar). */
.botao-editar-descricao:not([hidden]) {
  display: flex;
}

/* Ao lado do lápis de editar a descrição, mesma forma e tamanho, só que à
   esquerda dele e a vermelho (ação destrutiva) — atalho para eliminar esta
   skill em concreto a partir do próprio detalhe (ver #btn-eliminar-skill-
   detalhe em chat.html), sem ter de escrever o nome à mão no modal do
   painel "Gerir" (esse continua a existir tal como estava). */
.botao-eliminar-skill-detalhe {
  position: absolute;
  top: 1.5rem;
  right: 4.25rem;
  width: 34px;
  height: 30px;
  padding: 0;
  border-radius: 6px;
  align-items: center;
  justify-content: center;
  background: #b3261e;
}

/* "display: flex" condicional a não ter "hidden" — mesma armadilha de
   especificidade de ".botao-editar-descricao" ao lado (ver comentário lá). */
.botao-eliminar-skill-detalhe:not([hidden]) {
  display: flex;
}

.descricao-detalhe-skill,
.descricao-detalhe-skill-editar {
  margin: 0 0 1rem;
  line-height: 1.5;
  padding: 0.9rem 1rem;
  border: 1px solid var(--cor-borda);
  border-radius: 8px;
  /* Altura fixa (não só máxima) para que a caixa tenha sempre o mesmo tamanho
     em modo leitura e em modo edição, independentemente do tamanho do texto. */
  height: 220px;
  overflow-y: auto;
}

.descricao-detalhe-skill {
  color: #4a5560;
  background: var(--cor-fundo);
  white-space: pre-wrap;
}

.descricao-detalhe-skill-editar {
  color: #1c2733;
  background: white;
  border-color: var(--cor-primaria);
  resize: vertical;
  font-family: inherit;
  font-size: 1rem;
}

.modal-caixa h2 {
  margin: 0 0 1rem;
  font-size: 1.1rem;
}

.modal-caixa form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.modal-caixa label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.9rem;
}

.modal-caixa input,
.modal-caixa select {
  padding: 0.5rem;
  border: 1px solid var(--cor-borda);
  border-radius: 4px;
  font-size: 1rem;
}

.modal-acoes {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
}

.botao-secundario {
  background: transparent;
  color: #4a5560;
  border: 1px solid var(--cor-borda);
}

.botao-perigo {
  background: #b3261e;
}

/* ---------- Corpo: skills ---------- */

.corpo {
  display: flex;
  min-height: calc(100vh - 65px);
}

.conteudo {
  flex: 1;
  background: transparent;
  padding: 1.75rem 2.5rem;
}

.grelha-skills {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1rem;
}

/* Mesmo "vidro fosco" dos campos da página de login (.caixa-auth input),
   por ser o mesmo tipo de fundo escuro — um input sólido claro destacaria
   a mais aqui. */
.campo-pesquisa-skills {
  display: block;
  width: 100%;
  max-width: 360px;
  margin-bottom: 1.25rem;
  padding: 0.55rem 0.9rem;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 6px;
  font-size: 0.95rem;
  background: rgba(255, 255, 255, 0.08);
  color: white;
  transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}

.campo-pesquisa-skills::placeholder {
  color: rgba(255, 255, 255, 0.5);
}

.campo-pesquisa-skills:focus {
  outline: none;
  border-color: #6fa8dc;
  background: rgba(255, 255, 255, 0.14);
  box-shadow: 0 0 0 3px rgba(111, 168, 220, 0.3);
}

/* Filtro por categoria — um botão de cada vez fica "ativo" (.categoria-ativa),
   mutuamente exclusivos (ver chat.js). "Todas" (data-categoria="") volta a
   mostrar tudo. */
.filtro-categorias-skills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1.25rem;
}

.filtro-categoria {
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.3);
  color: rgba(255, 255, 255, 0.75);
  padding: 0.3rem 0.9rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.filtro-categoria:hover {
  color: white;
}

.filtro-categoria.categoria-ativa {
  background: var(--cor-primaria);
  border-color: var(--cor-primaria);
  color: white;
}

.pesquisa-skills-vazio {
  color: rgba(255, 255, 255, 0.6);
  font-size: 0.9rem;
}

/* align-items:flex-start (em vez de center) + padding-top/bottom generosos
   reservam duas faixas horizontais inteiras — uma no topo (para a bola de
   nível e a etiqueta de estado) e outra em baixo (para a etiqueta de
   categoria) — em que nunca há texto, seja qual for o nome/descrição da
   skill. Ao contrário de só reservar espaço à direita (tentativa anterior:
   ver histórico do git), isto não obriga a estreitar a largura do nome
   nem da descrição — só empurra o bloco de texto para começar depois da
   faixa de cima, e garante que ele nunca cresce o suficiente para tocar na
   faixa de baixo (ver o valor de "height" abaixo, com folga de sobra até
   para uma descrição a ocupar as duas linhas permitidas). Sem isto, uma
   descrição de duas linhas ou um nome comprido a truncar em "..." podiam
   ficar por baixo da etiqueta de categoria/estado (bug real, reportado a
   testar com "auditoria-seguranca" e reproduzido também com um nome mais
   comprido e o estado "Registada", a etiqueta mais larga das quatro). */
.cartao-skill {
  position: relative;
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 0.9rem;
  text-align: left;
  color: #1c2733;
  background: white;
  width: 240px;
  height: 128px;
  box-sizing: border-box;
  padding: 32px 1.25rem 28px;
  border: 1px solid var(--cor-borda);
  border-radius: 8px;
  cursor: pointer;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.cartao-skill:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
  transform: translateY(-2px);
}

/* Feedback imediato ao clicar, antes de abrir o detalhe (ver
   entrada-detalhe-skill mais abaixo para a animação do próprio painel) —
   mesma ideia do "button:active { transform: scale(0.94) }" genérico, só que
   mais subtil porque o cartão é maior. */
.cartao-skill:active {
  transform: scale(0.98);
}

.cartao-skill svg {
  flex: none;
  color: var(--cor-primaria);
}

.textos-skill {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}

.nome-skill {
  font-size: 0.95rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.descricao-skill {
  font-size: 0.78rem;
  color: #6b7684;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ---------- Botão flutuante de definições ---------- */

/* Mesma "forma" do botão de chat (ver .botao-chat logo abaixo), só que no
   canto oposto — abre/fecha o próprio #painel-definicoes flutuante, tal como
   o botão de chat abre/fecha o #painel-chat. */
.botao-definicoes {
  position: fixed;
  left: 2rem;
  bottom: 2rem;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
  padding: 0;
  z-index: 1000;
  transition: transform 0.15s ease;
}

.botao-definicoes:hover {
  transform: rotate(30deg);
}

.botao-definicoes.ativo {
  transform: rotate(30deg) scale(0.92);
}

/* Botão "Gerir" — só nível 5 (ver chat.js). Ao contrário dos outros dois
   botões flutuantes (círculos só com ícone), este tem texto visível, por
   isso é uma pílula em vez de um círculo; fica ao lado do de Definições, na
   mesma linha, com a mesma altura. Abre #painel-gerir como um modal simples
   (sem a lógica especial de "botão coberto pelo fundo opaco" de
   Definições, porque este botão fica ao lado de onde a caixa abre, não por
   baixo dela). */
.botao-gerir {
  position: fixed;
  left: 5rem;
  bottom: 2rem;
  height: 40px;
  align-items: center;
  gap: 0.4rem;
  padding: 0 1rem;
  border-radius: 20px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
  font-weight: 600;
  font-size: 0.8rem;
  z-index: 1000;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.botao-gerir:hover {
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.28);
  transform: translateY(-2px);
}

/* "display: flex" fica só condicional a não ter "hidden" — mesma armadilha
   de especificidade já documentada em #painel-detalhe-skill/.aba-dashboard/
   .botao-editar-descricao. Sem isto, o botão "Gerir" aparecia a **qualquer**
   nível, não só nível 5 (foi um bug real, apanhado na mesma sessão em que
   os outros três foram corrigidos). */
.botao-gerir:not([hidden]) {
  display: flex;
}

/* ---------- Botão flutuante de chat ---------- */

.botao-chat {
  position: fixed;
  right: 2rem;
  bottom: 2rem;
  width: 58px;
  height: 58px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
  padding: 0;
  z-index: 1000;
  transition: transform 0.2s ease;
}

.botao-chat.ativo {
  transform: scale(0.92) rotate(-8deg);
}

.painel-chat {
  position: fixed;
  right: 2rem;
  bottom: 6rem;
  width: min(460px, calc(100vw - 3rem));
  height: min(72vh, 720px);
  display: flex;
  flex-direction: column;
  z-index: 999;
  opacity: 0;
  transform: translateY(2rem) scale(0.96);
  pointer-events: none;
  transform-origin: bottom right;
  transition: opacity 0.28s ease, transform 0.28s ease;
  background: white;
  color: #1c2733;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.25);
  border: 1px solid var(--cor-borda);
  border-radius: 12px;
  padding: 0.5rem;
}

.painel-chat.aberto {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}

/* #painel-definicoes usa a classe .modal-fundo (a mesma dos outros modais da
   app, ex. #modal-remover-utilizador) — fundo escuro opaco a cobrir o resto
   do ecrã, caixa centrada. O botão de engrenagem continua no mesmo sítio
   (canto inferior esquerdo, ver .botao-definicoes); só o painel em si é que
   passa a abrir ao centro, em vez de flutuar junto ao botão. */

.mensagens {
  flex: 1;
  overflow-y: auto;
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.mensagem {
  max-width: 85%;
  padding: 0.5rem 0.75rem;
  border-radius: 10px;
  line-height: 1.4;
  font-size: 0.9rem;
}

.mensagem.utilizador {
  align-self: flex-end;
  background: var(--cor-primaria);
  color: white;
}

.mensagem.assistente {
  align-self: flex-start;
  background: var(--cor-fundo);
  border: 1px solid var(--cor-borda);
}

.botao-download-skill {
  margin-top: 0.5rem;
  padding: 0.4rem 0.8rem;
  font-size: 0.85rem;
}

.form-chat {
  display: flex;
  gap: 0.5rem;
  padding: 0.75rem 0;
}

.form-chat input {
  flex: 1;
  padding: 0.8rem 1rem;
  font-size: 1rem;
  border-radius: 8px;
}

.form-chat button {
  padding: 0.5rem 1rem;
  border-radius: 8px;
}
