:root {
  /*
    VIDRO LIQUIDO — o sistema visual desde 07/09/2026.

    A ideia inteira cabe em tres camadas, e cada token abaixo pertence a uma:

      1. O FUNDO AMBIENTE. Um gradiente de manchas suaves, fixo atras de tudo
         (body::before). Ele existe para o vidro ter O QUE desfocar: vidro em
         cima de branco chapado e so um retangulo cinza.
      2. O VIDRO. Superficies translucidas com `backdrop-filter`. So os
         CONTAINERS sao de vidro — barra lateral, colunas, tiles, barras de
         ferramentas, modais. Os itens dentro deles (cards, linhas de tarefa,
         dias do calendario) sao translucidos SEM blur, de proposito: vidro
         dentro de vidro custa uma composicao por elemento, e um board com
         cinquenta cards ficaria arrastando o scroll. E a mesma regra que a
         Apple segue: uma camada de vidro por vez.
      3. A TINTA. Texto, hairlines e acentos. Sao os unicos tokens que mudam de
         verdade entre claro e escuro; o vidro so troca de opacidade.

    CLARO E ESCURO. O bloco `:root` e o tema claro completo. O bloco
    `@media (prefers-color-scheme: dark)` redefine so o que muda, e vale quando
    o <html> NAO tem `data-theme="light"`; o bloco `[data-theme="dark"]` repete
    a mesma lista para o botao de tema vencer o sistema nos dois sentidos. Quem
    escreve `data-theme` e o admin/tema.js, antes da primeira pintura. Um token
    NOVO precisa nascer nos tres lugares se mudar no escuro — um token definido
    so dentro de um bloco de tema some no outro.

    NAO HA MAIS COR CHAPADA NESTE ARQUIVO FORA DAQUI. As slate (#f1f5f9,
    #e2e8f0, #64748b...) que o arquivo usava soltas viraram tokens em
    07/09/2026, e e por isso que o tema escuro funciona: uma cor escrita direto
    numa regra e uma cor que nao troca de tema. Se precisar de uma cor nova,
    ela entra aqui, com o par escuro.

    ATENCAO AO EDITAR POR SCRIPT: este e o PRIMEIRO `:root` do arquivo, e ha
    um segundo mais abaixo (os tokens de evento do calendario). Um "troque o
    corpo do :root" ingenuo acerta este aqui e apaga o sistema inteiro — ja
    aconteceu em 07/09/2026, no proprio dia em que ele nasceu.
  */

  /* Tipografia. A pilha comeca no sistema (SF Pro no Mac, Segoe no Windows) e
     cai para a Inter, que e carregada do Google Fonts para os dois ficarem
     parecidos onde a do sistema nao existe. Display e a mesma familia, mais
     apertada — o titulo se distingue pelo peso e pelo tracking, nao por trocar
     de fonte. */
  --font: -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --font-display: var(--font);

  /* Fundo ambiente e as manchas que o vidro desfoca. */
  --bg: #e9ecf3;
  --blob-1: rgba(96, 141, 255, 0.70);
  --blob-2: rgba(170, 120, 255, 0.55);
  --blob-3: rgba(50, 200, 205, 0.50);
  --blob-4: rgba(255, 160, 110, 0.42);

  /* Tinta. */
  --ink: #14161c;
  --ink-2: #3b4150;
  --muted: #6b7280;
  --faint: #9aa1ae;
  --on-accent: #ffffff;

  /* Vidro. `glass` e o container comum; `glass-strong` e o que precisa de
     mais opacidade para o texto ser lido por cima de qualquer fundo (modais,
     barra lateral); `glass-soft` e o painel interno que so precisa se
     distinguir do container. `surface` e o item SEM blur dentro do vidro. */
  --glass: rgba(255, 255, 255, 0.55);
  --glass-strong: rgba(255, 255, 255, 0.76);
  --glass-soft: rgba(255, 255, 255, 0.34);
  --glass-border: rgba(255, 255, 255, 0.70);
  --glass-border-strong: rgba(255, 255, 255, 0.95);
  --glass-highlight: inset 0 1px 0 rgba(255, 255, 255, 0.80);
  --blur: 22px;
  --blur-strong: 34px;
  --saturate: 170%;
  --surface: rgba(255, 255, 255, 0.72);
  --surface-2: rgba(255, 255, 255, 0.46);
  --surface-3: rgba(20, 22, 28, 0.05);
  --card-bg: var(--surface);
  --hover-wash: rgba(20, 22, 28, 0.05);
  /* Os dois do esqueleto de carga: o bloco parado e a faixa que varre por
     cima dele. O bloco e mais forte que `surface-3` de proposito — ele precisa
     ler como 'conteudo que ainda nao chegou', e nao como fundo. */
  --esqueleto: rgba(20, 22, 28, 0.08);
  --esqueleto-brilho: rgba(255, 255, 255, 0.60);

  /* Hairlines. Sempre em alpha, para sentar em cima de qualquer vidro. */
  --line: rgba(20, 22, 28, 0.09);
  --line-strong: rgba(20, 22, 28, 0.16);
  --border: var(--line);

  /* Acento e semanticos. Cada um tem o trio bg/ink/border em alpha, que e o
     que os chips, selos e estados de campo usam. */
  --accent: #3478f6;
  --accent-ink: #1d5fd6;
  --accent-bg: rgba(52, 120, 246, 0.14);
  --accent-border: rgba(52, 120, 246, 0.35);
  --accent-ring: 0 0 0 3px rgba(52, 120, 246, 0.22);
  --primary: var(--accent);

  --success: #1f9d61;
  --success-ink: #157a49;
  --success-bg: rgba(34, 160, 107, 0.14);
  --success-border: rgba(34, 160, 107, 0.38);

  --warning: #e0900a;
  --warning-ink: #9a5b00;
  --warning-bg: rgba(245, 158, 11, 0.16);
  --warning-border: rgba(245, 158, 11, 0.42);

  --danger: #e5484d;
  --danger-ink: #b42328;
  --danger-bg: rgba(229, 72, 77, 0.13);
  --danger-border: rgba(229, 72, 77, 0.36);

  --violet: #7c5cf6;
  --violet-ink: #5b3fd1;
  --violet-bg: rgba(124, 92, 246, 0.14);
  --violet-border: rgba(124, 92, 246, 0.38);

  --teal: #14b8a6;

  /* Raios. O vidro e redondo; o raio cresce com o tamanho da peca. */
  --r-xs: 8px;
  --r-sm: 12px;
  --r-md: 16px;
  --r-lg: 22px;
  --r-xl: 28px;
  --radius: var(--r-sm);

  --space-8: 8px;
  --space-12: 12px;
  --space-16: 16px;
  --space-24: 24px;

  /* Sombras. Suaves e difusas: o vidro flutua, nao pesa. */
  --shadow-sm: 0 1px 2px rgba(15, 18, 28, 0.05), 0 2px 10px rgba(15, 18, 28, 0.04);
  --shadow-md: 0 6px 18px rgba(15, 18, 28, 0.09), 0 2px 6px rgba(15, 18, 28, 0.05);
  --shadow-lg: 0 24px 60px rgba(15, 18, 28, 0.18), 0 8px 20px rgba(15, 18, 28, 0.08);

  /* Tipos de projeto: o mesmo trio, um por tipo. */
  --project-type-estrategia-bg: var(--accent-bg);
  --project-type-estrategia-ink: var(--accent-ink);
  --project-type-estrategia-border: var(--accent-border);
  --project-type-treinamento-bg: var(--success-bg);
  --project-type-treinamento-ink: var(--success-ink);
  --project-type-treinamento-border: var(--success-border);
  --project-type-desenvolvimento-bg: rgba(249, 115, 22, 0.15);
  --project-type-desenvolvimento-ink: #b4530a;
  --project-type-desenvolvimento-border: rgba(249, 115, 22, 0.40);
}

/* O tema escuro so redefine o que muda. Duas vezes, pelo motivo escrito no
   comentario do :root: uma para o sistema, outra para o botao. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0d0f15;
    --blob-1: rgba(70, 110, 255, 0.42);
    --blob-2: rgba(140, 90, 255, 0.34);
    --blob-3: rgba(30, 170, 180, 0.30);
    --blob-4: rgba(255, 130, 90, 0.18);
    --ink: #f1f2f6;
    --ink-2: #c9cdd8;
    --muted: #9aa1b0;
    --faint: #6f7684;
    --glass: rgba(30, 33, 42, 0.58);
    --glass-strong: rgba(28, 31, 40, 0.80);
    --glass-soft: rgba(255, 255, 255, 0.045);
    --glass-border: rgba(255, 255, 255, 0.10);
    --glass-border-strong: rgba(255, 255, 255, 0.18);
    --glass-highlight: inset 0 1px 0 rgba(255, 255, 255, 0.09);
    --surface: rgba(255, 255, 255, 0.07);
    --surface-2: rgba(255, 255, 255, 0.04);
    --surface-3: rgba(255, 255, 255, 0.07);
    --hover-wash: rgba(255, 255, 255, 0.07);
    --esqueleto: rgba(255, 255, 255, 0.10);
    --esqueleto-brilho: rgba(255, 255, 255, 0.08);
    --line: rgba(255, 255, 255, 0.09);
    --line-strong: rgba(255, 255, 255, 0.17);
    --accent: #5b8dff;
    --accent-ink: #9bbaff;
    --accent-bg: rgba(91, 141, 255, 0.18);
    --accent-border: rgba(91, 141, 255, 0.42);
    --accent-ring: 0 0 0 3px rgba(91, 141, 255, 0.30);
    --success-ink: #6fd3a3;
    --success-bg: rgba(34, 160, 107, 0.20);
    --warning-ink: #f5c05a;
    --warning-bg: rgba(245, 158, 11, 0.20);
    --danger-ink: #ff8a8e;
    --danger-bg: rgba(229, 72, 77, 0.20);
    --violet-ink: #b9a6ff;
    --violet-bg: rgba(124, 92, 246, 0.22);
    --project-type-desenvolvimento-ink: #ffab74;
    --project-type-desenvolvimento-bg: rgba(249, 115, 22, 0.20);
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.30), 0 2px 10px rgba(0, 0, 0, 0.25);
    --shadow-md: 0 8px 22px rgba(0, 0, 0, 0.40), 0 2px 6px rgba(0, 0, 0, 0.30);
    --shadow-lg: 0 28px 70px rgba(0, 0, 0, 0.60), 0 8px 20px rgba(0, 0, 0, 0.40);
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --bg: #0d0f15;
  --blob-1: rgba(70, 110, 255, 0.42);
  --blob-2: rgba(140, 90, 255, 0.34);
  --blob-3: rgba(30, 170, 180, 0.30);
  --blob-4: rgba(255, 130, 90, 0.18);
  --ink: #f1f2f6;
  --ink-2: #c9cdd8;
  --muted: #9aa1b0;
  --faint: #6f7684;
  --glass: rgba(30, 33, 42, 0.58);
  --glass-strong: rgba(28, 31, 40, 0.80);
  --glass-soft: rgba(255, 255, 255, 0.045);
  --glass-border: rgba(255, 255, 255, 0.10);
  --glass-border-strong: rgba(255, 255, 255, 0.18);
  --glass-highlight: inset 0 1px 0 rgba(255, 255, 255, 0.09);
  --surface: rgba(255, 255, 255, 0.07);
  --surface-2: rgba(255, 255, 255, 0.04);
  --surface-3: rgba(255, 255, 255, 0.07);
  --hover-wash: rgba(255, 255, 255, 0.07);
  --esqueleto: rgba(255, 255, 255, 0.10);
  --esqueleto-brilho: rgba(255, 255, 255, 0.08);
  --line: rgba(255, 255, 255, 0.09);
  --line-strong: rgba(255, 255, 255, 0.17);
  --accent: #5b8dff;
  --accent-ink: #9bbaff;
  --accent-bg: rgba(91, 141, 255, 0.18);
  --accent-border: rgba(91, 141, 255, 0.42);
  --accent-ring: 0 0 0 3px rgba(91, 141, 255, 0.30);
  --success-ink: #6fd3a3;
  --success-bg: rgba(34, 160, 107, 0.20);
  --warning-ink: #f5c05a;
  --warning-bg: rgba(245, 158, 11, 0.20);
  --danger-ink: #ff8a8e;
  --danger-bg: rgba(229, 72, 77, 0.20);
  --violet-ink: #b9a6ff;
  --violet-bg: rgba(124, 92, 246, 0.22);
  --project-type-desenvolvimento-ink: #ffab74;
  --project-type-desenvolvimento-bg: rgba(249, 115, 22, 0.20);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.30), 0 2px 10px rgba(0, 0, 0, 0.25);
  --shadow-md: 0 8px 22px rgba(0, 0, 0, 0.40), 0 2px 6px rgba(0, 0, 0, 0.30);
  --shadow-lg: 0 28px 70px rgba(0, 0, 0, 0.60), 0 8px 20px rgba(0, 0, 0, 0.40);
  color-scheme: dark;
}

* {
  box-sizing: border-box;
}

.hidden {
  display: none !important;
}

/*
  A MESMA ESCONDIDA, MAS ANTES DE O JAVASCRIPT EXISTIR.

  `.hidden` acima e o mecanismo de sempre, e quem o poe e tira nas views e o
  admin/js/rotas.js. O problema e QUANDO: rotas.js e modulo, modulo e adiado, e o
  navegador pinta antes de ele rodar. Nessa janela — o tempo de buscar treze
  arquivos de JS pela rede — as quatro views estao todas sem `.hidden` e aparecem
  EMPILHADAS, cada uma espremida num pedaco da altura da tela.

  Isso sempre existiu e nunca apareceu, porque as quatro nasciam vazias. Em
  15/09/2026 cada uma ganhou esqueleto de carga, e o empilhamento virou uma tela
  de blocos cinzentos repetidos, que se le como a pagina carregando duas vezes.

  O `data-rota` e escrito no <html> por um script CLASSICO no <head> do
  index.html — antes do <body> existir, portanto antes do primeiro pixel. As
  regras abaixo escondem por atributo a view que nao e a da rota, e param de
  importar no instante em que o roteador assume: ele reescreve o mesmo atributo a
  cada troca, na mesma linha em que mexe na classe.

  O `!important` e obrigatorio pelo mesmo motivo do `.hidden`: o #view-pipeline
  carrega `display: flex` em atributo `style`, e regra sem `!important` nao vence
  estilo inline.

  E o `html[data-rota]` na frente de cada seletor e o degrau de seguranca: se o
  script do <head> nao rodar, o atributo nao existe, NENHUMA destas regras casa,
  e a tela volta a se comportar como antes — feia por um instante, nunca vazia.
*/
html[data-rota]:not([data-rota="pipeline"]) #view-pipeline,
html[data-rota]:not([data-rota="tarefas"]) #view-tarefas,
html[data-rota]:not([data-rota="calendario"]) #view-calendario,
html[data-rota]:not([data-rota="cerebro"]) #view-cerebro,
html[data-rota]:not([data-rota="telemetria"]) #view-telemetria {
  display: none !important;
}

html {
  background: var(--bg);
}

body {
  margin: 0;
  height: 100vh;
  overflow: hidden;
  font-family: var(--font);
  color: var(--ink);
  background-color: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/*
  O FUNDO AMBIENTE. Um pseudo-elemento fixo com quatro manchas radiais, atras
  de tudo (z-index negativo), e a unica coisa "colorida" da tela quando ela
  esta vazia. As superficies de vidro desfocam ISTO. Ele e `position: fixed` e
  nao no `body` porque o `.app-container` rola por dentro e o fundo precisa
  ficar parado: mancha que rola junto com o kanban vira listra.

  `will-change` nao esta aqui de proposito: o fundo nao anima, e prometer
  animacao ao compositor gasta memoria de textura para nada.
*/
body::before {
  content: "";
  position: fixed;
  inset: -10vh -10vw;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(42% 48% at 12% 10%, var(--blob-1), transparent 70%),
    radial-gradient(38% 42% at 88% 14%, var(--blob-2), transparent 70%),
    radial-gradient(44% 46% at 78% 90%, var(--blob-3), transparent 70%),
    radial-gradient(30% 34% at 18% 86%, var(--blob-4), transparent 70%),
    var(--bg);
}

/*
  A RECEITA DO VIDRO, em uma classe utilitaria e nos seletores que a recebem.
  Quem precisa de vidro lista o seletor aqui em vez de repetir as cinco linhas:
  assim o blur, a borda-luz e o realce interno mudam num lugar so.

  `-webkit-backdrop-filter` continua necessario para o Safari que o Cesar usa
  no Mac. A ordem (o prefixo antes do padrao) e a que evita que uma versao
  antiga ignore os dois.
*/
.glass,
.kanban-column,
.board-toolbar,
.modal-content,
.auth-card,
.custom-dropdown,
.view-empty,
.task-compose,
.tarefas-grupo,
.loader-content,
.sidebar-tooltip {
  background: var(--glass);
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-highlight), var(--shadow-sm);
}

/* Background shapes removed for cleaner look */
.bg-shape {
  display: none;
}

/*
  A trava de tela serve para DOIS casos hoje, e nenhum deles e basic auth:

    - 401, sessao ausente ou expirada. O callApi trava o board e abre a tela de
      login em seguida — o showAuthGate do app.js chama lockBoard ANTES do
      showModal, e e por isso que o `:not(#auth-gate)` da regra abaixo existe.
    - 403 da verificacao de origem da admin-api (garantirMesmaOrigem, em
      selfhosted/api/main.ts). Esse trava sem abrir login, porque entrar de novo
      nao resolveria: nao e credencial que esta faltando.

  Ate 06/09/2026 este comentario dizia que a tela de login "nao existe mais" e
  que o 401 vinha do basic auth do Caddy. As duas coisas morreram no mesmo dia:
  o basic_auth saiu do Caddyfile e a tela de login e hoje a PRINCIPAL usuaria
  desta trava. Nao apague estas regras achando que sao resto de um fluxo morto.

  Por que travar em vez de so avisar: o drop de card e OTIMISTA. O handler muta
  o board, redesenha, e so depois chama a API; quando a chamada falha, quem
  desfaz e um fetchBoard de reconciliacao — que, com a credencial recusada,
  falha tambem e volta calado. Sem esta regra a coluna "Fechado" fica mostrando,
  com confete, um card que o banco tem em "Proposta".

  Os <dialog> entram na regra porque sao IRMAOS do .app-container, e nao filhos:
  esconder so o .app-container deixaria um modal de card aberto na frente, com
  auto-save disparando a cada tecla contra uma API que recusa. `display: none`
  num <dialog open> leva junto o ::backdrop dele, que tambem vive fora deste
  elemento. O #global-loader entra pelo mesmo motivo.

  MAS `display: none` NAO FECHA UM DIALOG. Um <dialog> aberto por showModal()
  continua com `open` e continua bloqueando o documento inteiro mesmo sem pintar
  um pixel: todo no fora dele segue INERTE, sem aceitar clique nem tecla. Isto
  foi MEDIDO no navegador, e nao deduzido — com o modal de card aberto e a
  classe `auth-locked` no body, dois cliques reais de mouse numa caixa <div>
  filha do <body> registraram ZERO cliques, e o hit test no centro do botao
  devolvia o <html>. Era o estado real depois de um 403 com um card aberto: um
  aviso legivel com o botao "Recarregar" morto, e nenhuma saida na pagina.

  E a caixa de aviso NAO ficava por cima por ser filha do <body> — e o
  contrario: dialog modal vive na camada de topo e pinta acima de qualquer
  z-index do documento; ser filha do <body> e o que a punha embaixo.

  A correcao nao esta neste arquivo: a caixa de aviso virou um <dialog> tambem
  (veja showWarningBox no app.js), e entra na camada de topo pelo mesmo caminho.
  O lockBoard continua NAO fechando os dialogs de proposito — fechar o modal de
  card dispararia o auto-save de despedida contra a API que acabou de recusar, e
  jogaria fora o texto digitado que o index.html promete preservar.
*/
.app-container {
  display: flex;
  height: 100vh;
  width: 100vw;
  overflow: hidden;
  transition: opacity 0.3s ease;
}

body.auth-locked .app-container {
  opacity: 0;
  pointer-events: none;
  user-select: none;
}

/*
  As DUAS excecoes sao obrigatorias, e cada uma esconde uma pagina preta sem
  saida atras dela.

  `:not(#auth-gate)` — a propria tela de login e um <dialog open>, e o body ganha
  `auth-locked` no mesmo instante em que ela abre, porque quem a abre chama
  lockBoard antes. Sem a excecao, esta regra apagaria justamente a unica coisa
  que devia continuar na tela.

  `:not(#warning-box)` — a caixa de aviso da trava tambem e um <dialog>, aberto
  com showModal() para entrar na camada de topo e continuar CLICAVEL por cima do
  modal de card (veja showWarningBox no app.js). Sem a excecao, a trava
  esconderia o unico aviso que explica a trava, junto com o botao "Recarregar"
  que e a saida dela.
*/
body.auth-locked dialog[open]:not(#auth-gate):not(#warning-box),
body.auth-locked #global-loader {
  display: none;
}

/* O ::backdrop do aviso de trava fica transparente: ele nao precisa escurecer
   nada (o .app-container ja esta em opacity 0) e escurecer esconderia a tela de
   login, caso as duas estejam abertas ao mesmo tempo. */
#warning-box::backdrop {
  background: transparent;
}

.app {
  flex: 1;
  /* O 20px da esquerda e maior que os 16px de antes porque a barra encostou na
     borda: sem a margem dela, era a primeira coluna do board que ficava a um
     fio da divisoria. */
  padding: 18px 22px 14px 20px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-width: 0;
}

/* Sidebar Styles */

.project-task-group {
  margin-bottom: 24px;
  border-radius: 12px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  overflow: hidden;
}

.project-task-group-header {
  padding: 12px 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.project-task-group-header h4 {
  margin: 0;
  font-size: 0.85rem;
  color: var(--ink);
}

.project-task-group-header .client-name {
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
}

.global-task-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--line);
  font-size: 0.9rem;
  transition: background 0.2s;
  cursor: grab;
}

.global-task-item:hover {
  background: var(--accent-bg);
}

.global-task-item.dragging {
  opacity: 0.55;
}

.global-task-item.reorder-target {
  outline: 2px dashed var(--accent-border);
  outline-offset: -2px;
}

.project-task-group.dragging {
  opacity: 0.65;
}

.project-task-group-header {
  cursor: grab;
}

.global-task-item input[type="checkbox"] {
  margin-top: 3px;
}

.global-task-item span {
  flex: 1;
  color: var(--ink-2);
}

.global-task-item.done span {
  text-decoration: line-through;
  opacity: 0.5;
}

.eyebrow {
  margin: 0;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 0.66rem;
  font-weight: 700;
  color: var(--muted);
}

h1 {
  margin: 4px 0 0;
  font-family: var(--font-display);
  font-size: 1.55rem;
  letter-spacing: -0.025em;
  color: var(--ink);
  font-weight: 700;
}

.btn-link {
  border: none;
  background: transparent;
  color: var(--ink);
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
  padding: 0;
}

.btn {
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 9px 16px;
  font-size: 0.88rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition:
    background 0.2s ease,
    border-color 0.2s ease,
    box-shadow 0.2s ease,
    transform 0.15s ease;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.btn:active {
  transform: scale(0.97);
}

.btn-primary {
  background: var(--accent);
  color: var(--on-accent);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.35),
    0 6px 16px rgba(52, 120, 246, 0.28);
}

.btn-primary:hover {
  background: var(--accent-ink);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.35),
    0 10px 22px rgba(52, 120, 246, 0.34);
}

.btn-secondary {
  background: var(--surface);
  border-color: var(--glass-border);
  color: var(--ink);
  box-shadow: var(--glass-highlight), var(--shadow-sm);
}

.btn-secondary:hover {
  border-color: var(--line-strong);
  background: var(--glass-strong);
}

.btn-danger {
  background: var(--danger);
  color: var(--on-accent);
  border-color: transparent;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3);
}

.btn-danger:hover {
  background: var(--danger-ink);
  border-color: transparent;
}

.kanban-board {
  display: flex;
  gap: 12px;
  overflow-x: hidden;
  padding: 4px 2px 6px;
  flex: 1;
  min-height: 0;
  align-items: stretch;
}

.kanban-column {
  flex: 1;
  min-width: 100px;
  height: 100%;
  max-height: 100%;
  border-radius: var(--r-lg);
  display: flex;
  flex-direction: column;
  position: relative;
  overflow: hidden;
  transition:
    flex-basis 0.3s cubic-bezier(0.4, 0, 0.2, 1),
    width 0.3s cubic-bezier(0.4, 0, 0.2, 1),
    border-color 0.2s ease,
    box-shadow 0.2s ease;
}

/*
  A cor da coluna vem do JS como `--column-color` no proprio <article>
  (renderColumn, em pipeline.js). Ela aparece em dois lugares, e nos dois como
  luz e nao como barra: um brilho difuso no topo do vidro, que e o que diz "esta
  coluna e azul" sem pintar um retangulo, e o ponto ao lado do titulo, que
  continua legivel com a coluna minimizada. O `color-mix` e o que permite
  derivar o tom translucido de uma cor chapada que o banco guarda como hex.
*/
.kanban-column::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 120px;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--column-color, var(--muted)) 22%, transparent),
    transparent
  );
}

/*
  A faixa do topo carrega DUAS pilulas: quantas propostas, e quanto elas somam.
  Ela deixou de ser um `justify-content: center` com um filho unico e virou uma
  linha com gap — o par continua centrado, e o `gap` e o que diz que sao duas
  leituras da mesma coluna, e nao um numero partido ao meio.

  O `pointer-events: none` da faixa e antigo e continua certo para o dinheiro,
  que nao tem nada a dizer no hover. A contagem TEM (o `title` com "7
  propostas"), entao ela devolve o ponteiro para si mesma logo abaixo; sem isso
  o tooltip nunca apareceria, porque o hover nem chegaria no elemento.
*/
.column-top-total {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 12px 0 6px;
  width: 100%;
  pointer-events: none;
  position: relative;
}

/*
  As duas pilulas dividem a mesma moldura de proposito: mesma superficie, mesma
  borda de vidro, mesmo raio e mesma sombra. O que as separa e a TINTA — o valor
  em `--ink` porque e o numero que o olho procura, a contagem em `--muted`
  porque ela contextualiza o valor em vez de competir com ele.

  O `font-size` da contagem esta escrito aqui em vez de herdado: o do valor sai
  de um acidente de cascata (duas regras `.card-value` de mesma especificidade,
  onde vence a ultima do arquivo), e amarrar a contagem a isso deixaria as duas
  pilulas de tamanhos diferentes no dia em que alguem mexesse la.
*/
.column-count,
.column-total.card-value {
  background: var(--surface);
  border: 1px solid var(--glass-border);
  border-radius: 999px;
  padding: 4px 14px;
  margin: 0;
  white-space: nowrap;
  display: inline-block;
  box-shadow: var(--glass-highlight), var(--shadow-sm);
  font-weight: 600;
  color: var(--ink);
}

.column-count {
  padding: 4px 10px;
  font-size: 1rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

/* ---------------------------------------------------------------------------
   A VIRADA PARA A MÉDIA
   ---------------------------------------------------------------------------

   Clicar na faixa do topo vira as pílulas em torno do eixo horizontal e mostra,
   no verso, o total dividido pela contagem. Clicar de novo desvira. TODAS as
   colunas viram juntas, porque comparar a média de uma coluna com o total da
   vizinha não quer dizer nada — a leitura só serve se o board inteiro estiver
   na mesma unidade.

   O ESTADO NÃO MORA NO DOM e nem no localStorage: mora numa variável do
   admin/js/pipeline.js, relida a cada `renderColumn`. É o que faz a virada
   sobreviver ao redesenho que vem depois de cada auto-save — sem isso, o board
   voltaria sozinho para o total no meio da leitura. E é o que faz ela NÃO
   sobreviver ao F5, que é o certo: a média é uma pergunta do momento, não uma
   preferência de tela como o tema ou o Modo Privacidade.

   O `pointer-events: auto` aqui é o que devolve o ponteiro que o
   `.column-top-total` tira de todos os filhos.
*/
.column-medida {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
  pointer-events: auto;
  border-radius: 999px;
  /* A perspectiva mora no PAI do que gira. No próprio elemento girado ela não
     tem efeito nenhum, e a virada sai chapada, sem profundidade. */
  perspective: 700px;
}

.column-medida:focus-visible {
  outline: none;
  box-shadow: var(--accent-ring);
}

.column-medida-faces {
  display: grid;
  transform-style: preserve-3d;
  transition: transform 0.55s cubic-bezier(0.4, 0.1, 0.2, 1);
}

.column-medida.is-media .column-medida-faces {
  transform: rotateX(180deg);
}

/*
  As duas na MESMA célula da grade: é assim que a caixa fica do tamanho da face
  mais larga e nenhuma das duas sai do lugar quando a outra aparece.
*/
.column-medida-face {
  grid-area: 1 / 1;
  justify-self: center;
  display: flex;
  align-items: center;
  gap: 6px;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

/* O verso nasce virado, para chegar de frente quando o conjunto girar 180°. */
.column-medida-verso {
  transform: rotateX(180deg);
}

/*
  A pílula da média é a mesma moldura das outras duas — não há desenho novo
  nesta feature, só um terceiro conteúdo na mesma peça. O rótulo vai junto
  porque, sem ele, "R$ 80.000,00" sozinho no topo da coluna seria lido como o
  total: é o mesmo lugar, o mesmo formato e a mesma cor.
*/
.column-average.card-value {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  background: var(--surface);
  border: 1px solid var(--glass-border);
  border-radius: 999px;
  padding: 4px 14px;
  margin: 0;
  white-space: nowrap;
  box-shadow: var(--glass-highlight), var(--shadow-sm);
  font-size: 1rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.column-average-rotulo {
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Quem pediu menos movimento troca a virada por uma troca seca: o verso ainda
   aparece, e o giro não acontece. */
@media (prefers-reduced-motion: reduce) {
  .column-medida-faces {
    transition: none;
  }
}

/* Hide total in collapsed state to keep it clean */
.kanban-column.collapsed .column-top-total {
  display: none;
}

.column-header-inner {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
}

.kanban-column:hover {
  border-color: var(--glass-border-strong);
  box-shadow: var(--glass-highlight), var(--shadow-md);
}

.kanban-column.collapsed {
  flex: 0 0 52px;
  width: 52px;
  min-width: 52px;
  overflow: hidden;
}

.kanban-column.collapsed .cards,
.kanban-column.collapsed .column-total {
  /* We want to show the title rotated, so we don't hide it entirely here, 
     but actually we might need to change how we display it.
     Let's hide the original title structure and show a rotated one?
     Or reuse the existing one. For simplicity with existing JS, 
     let's target the inner elements. */
  display: none;
}

.kanban-column.collapsed .column-header {
  height: 100%;
  flex-direction: column;
  justify-content: flex-start;
  padding: 16px 0;
  gap: 16px;
  align-items: center;
}

.kanban-column.collapsed .column-header-inner {
  flex-direction: column;
  gap: 24px;
}

.kanban-column.collapsed .column-title-btn {
  display: block;
  /* Show it */
  writing-mode: vertical-rl;
  text-orientation: mixed;
  transform: rotate(180deg);
  /* Text runs bottom to top */
  white-space: nowrap;
  padding: 10px 6px;
  width: auto;
}

.kanban-column.collapsed .column-collapse-btn {
  transform: rotate(180deg);
  /* Arrow points up/expand */
  margin-bottom: 0;
}

.column-header {
  border-bottom: 0;
  padding: 6px 10px 8px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: relative;
}

.column-title-btn {
  width: auto;
  border: none;
  background: transparent;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 0.95rem;
  text-transform: capitalize;
  letter-spacing: -0.01em;
  font-weight: 700;
  padding: 6px 10px 6px 8px;
  border-radius: 999px;
  cursor: pointer;
  text-align: left;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.column-title-btn::before {
  content: "";
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: 0 0 auto;
  background: var(--column-color, var(--muted));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--column-color, var(--muted)) 22%, transparent);
}

.column-title-btn:hover {
  background: var(--hover-wash);
}

.column-collapse-btn {
  background: var(--surface);
  border: 1px solid var(--glass-border);
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  cursor: pointer;
  color: var(--muted);
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
  box-shadow: var(--glass-highlight), var(--shadow-sm);
  flex-shrink: 0;
}

.column-collapse-btn:hover {
  background: var(--ink);
  color: var(--bg);
  border-color: var(--ink);
}

.column-collapse-btn svg {
  width: 14px;
  height: 14px;
}

.column-total {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--muted);
  background: var(--surface-2);
  padding: 4px 8px;
  border-radius: 20px;
  min-width: 24px;
}

.cards {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 2px 10px 12px;
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  min-height: 0;
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;
  position: relative;
}

.cards::-webkit-scrollbar {
  width: 6px;
}

.cards::-webkit-scrollbar-thumb {
  background-color: var(--line-strong);
  border-radius: 20px;
  border: 2px solid transparent;
  background-clip: content-box;
}

.card {
  position: relative;
  background: var(--card-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--r-md);
  min-height: unset;
  padding: 14px 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 7px;
  box-shadow: var(--glass-highlight), var(--shadow-sm);
  transition:
    transform 0.2s cubic-bezier(0.25, 0.8, 0.25, 1),
    box-shadow 0.2s ease,
    border-color 0.2s ease;
  animation: card-enter 300ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

.card:hover {
  transform: translateY(-2px);
  box-shadow: var(--glass-highlight), var(--shadow-md);
  border-color: var(--glass-border-strong);
}

.card.dragging {
  opacity: 0.5;
}

.cards.drag-over {
  background: var(--accent-bg);
  outline: 2px dashed var(--accent-border);
  outline-offset: -3px;
  border-radius: var(--r-md);
}

.drop-indicator {
  height: 14px;
  border-radius: 8px;
  background: var(--accent-bg);
  border: 1px dashed var(--accent-border);
  flex: 0 0 auto;
}

/* Close celebration */
.closure-celebration-layer {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 9998;
  overflow: hidden;
}

.confetti-piece {
  position: absolute;
  top: -16px;
  width: 8px;
  height: 12px;
  border-radius: 2px;
  opacity: 0.85;
  animation: confetti-fall 1.45s ease-out forwards;
}

.firework-burst {
  position: absolute;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: rgba(250, 204, 21, 0.9);
  box-shadow:
    0 -22px 0 -3px rgba(250, 204, 21, 0.75),
    0 22px 0 -3px rgba(59, 130, 246, 0.75),
    22px 0 0 -3px rgba(239, 68, 68, 0.75),
    -22px 0 0 -3px rgba(16, 185, 129, 0.75),
    16px 16px 0 -3px rgba(245, 158, 11, 0.75),
    -16px 16px 0 -3px rgba(236, 72, 153, 0.75),
    16px -16px 0 -3px rgba(59, 130, 246, 0.75),
    -16px -16px 0 -3px rgba(16, 185, 129, 0.75);
  animation: firework-pop 520ms ease-out forwards;
}

@keyframes confetti-fall {
  0% {
    transform: translate3d(0, 0, 0) rotate(0deg);
    opacity: 0.9;
  }
  100% {
    transform: translate3d(var(--drift), 96vh, 0) rotate(var(--rot));
    opacity: 0;
  }
}

@keyframes firework-pop {
  0% {
    transform: scale(0.2);
    opacity: 0;
  }
  35% {
    transform: scale(1);
    opacity: 0.9;
  }
  100% {
    transform: scale(1.18);
    opacity: 0;
  }
}

@keyframes card-enter {
  from {
    opacity: 0;
    transform: translateY(8px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.card-head {
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: space-between;
}

.card-head-main {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

.card-client,
.card-project,
.card-contact,
.card-value {
  margin: 0;
}

.card-value {
  font-size: 0.95rem;
  align-self: flex-start;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  background: var(--surface-3);
  padding: 4px 10px;
  border-radius: 999px;
}

.card-client {
  font-size: 0.72rem;
  line-height: 1.4;
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.card-project {
  font-size: 1rem;
  line-height: 1.3;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin-bottom: 2px;
}

.inline-editing {
  outline: none;
  background: var(--accent-bg);
  border-radius: 4px;
  padding: 1px 4px;
  min-width: 30px;
  cursor: text;
}

.card-project-types {
  position: absolute;
  bottom: 10px;
  right: 10px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
}

.project-type-badge {
  display: inline-flex;
  align-items: center;
  height: 14px;
  max-width: 14px;
  min-width: 14px;
  border-radius: 999px;
  border: 1px solid transparent;
  overflow: hidden;
  cursor: default;
  opacity: 0.8;
  transition: max-width 0.3s ease, padding 0.3s ease, opacity 0.2s ease;
}

.project-type-badge:hover {
  max-width: 140px;
  padding: 2px 8px;
  opacity: 1;
}

.project-type-badge-label {
  font-size: 0.65rem;
  font-weight: 600;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.1s ease;
}

.project-type-badge:hover .project-type-badge-label {
  opacity: 1;
  transition: opacity 0.15s ease 0.12s;
}

.project-type-badge.project-type-estrategia {
  background: var(--project-type-estrategia-bg);
  border-color: var(--project-type-estrategia-border);
}

.project-type-badge.project-type-estrategia .project-type-badge-label {
  color: var(--project-type-estrategia-ink);
}

.project-type-badge.project-type-treinamento {
  background: var(--project-type-treinamento-bg);
  border-color: var(--project-type-treinamento-border);
}

.project-type-badge.project-type-treinamento .project-type-badge-label {
  color: var(--project-type-treinamento-ink);
}

.project-type-badge.project-type-desenvolvimento {
  background: var(--project-type-desenvolvimento-bg);
  border-color: var(--project-type-desenvolvimento-border);
}

.project-type-badge.project-type-desenvolvimento .project-type-badge-label {
  color: var(--project-type-desenvolvimento-ink);
}

.card-attention-flag {
  width: 16px;
  height: 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--warning);
  flex: 0 0 auto;
}

.card-contact {
  font-size: 0.8rem;
  color: var(--muted);
  opacity: 0.8;
  font-style: italic;
}

.card-value {
  font-size: 1rem;
  align-self: flex-start;
  font-weight: 500;
  color: var(--muted);
  background: var(--surface-3);
  padding: 4px 8px;
  border-radius: 6px;
}

.card-remove {
  border: none;
  background: transparent;
  width: 20px;
  height: 20px;
  font-size: 1.1rem;
  color: var(--faint);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  opacity: 0;
  transition: all 0.2s;
}

.card:hover .card-remove {
  opacity: 1;
}

.card-remove:hover {
  background: var(--danger-bg);
  color: var(--danger);
}

@media (max-width: 1024px) {
  .btn {
    flex: 1;
  }

  .kanban-board {
    grid-template-columns: repeat(6, minmax(250px, 1fr));
  }
}

/* Modal Styles */
dialog {
  border: none;
  border-radius: var(--r-xl);
  padding: 0;
  box-shadow: var(--shadow-lg);
  max-width: 800px;
  background: transparent;
  color: var(--ink);
}

dialog::backdrop {
  background: rgba(8, 10, 18, 0.38);
  -webkit-backdrop-filter: blur(10px) saturate(120%);
  backdrop-filter: blur(10px) saturate(120%);
}

.modal-content {
  display: flex;
  flex-direction: column;
  background: var(--glass-strong);
  -webkit-backdrop-filter: blur(var(--blur-strong)) saturate(var(--saturate));
  backdrop-filter: blur(var(--blur-strong)) saturate(var(--saturate));
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-highlight);
  width: 100%;
  max-width: 2000px;
  max-height: 90vh;
  border-radius: var(--r-xl);
  position: relative;
  overflow: hidden;
}

.modal-header {
  padding: 22px 24px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--line);
}

.modal-header h2 {
  margin: 0;
  font-size: 1.2rem;
  letter-spacing: -0.02em;
  font-family: var(--font-display);
}

.btn-close {
  width: 30px;
  height: 30px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-3);
  border: none;
  border-radius: 999px;
  font-size: 1.05rem;
  cursor: pointer;
  line-height: 1;
  padding: 0;
  color: var(--muted);
  transition: background 0.15s ease, color 0.15s ease;
}

.btn-close:hover {
  background: var(--hover-wash);
  color: var(--ink);
}

.modal-body {
  padding: 24px;
  flex: 1;
  min-height: 0;
}

.card-modal-grid {
  display: grid;
  grid-template-columns: 1fr 1.5fr;
  gap: 40px;
  align-items: start;
}

@media (max-width: 768px) {
  .card-modal-grid {
    grid-template-columns: 1fr;
    gap: 20px;
  }
}

.form-group {
  margin-bottom: 16px;
}

.form-group label {
  display: block;
  margin-bottom: 6px;
  font-weight: 600;
  font-size: 0.82rem;
  color: var(--muted);
}

.form-group input,
.form-group select {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  font-family: inherit;
  font-size: 0.95rem;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

/*
  Foco e placeholder de TODO campo do app, num lugar so. O anel e o mesmo azul
  do acento em alpha, e nao um outline chapado: e o unico estado de foco que
  senta bem em cima do vidro claro e do escuro sem precisar de dois valores.
*/
input:not([type="checkbox"]):not([type="radio"]):focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--accent-ring);
}

input::placeholder,
textarea::placeholder {
  color: var(--faint);
}

select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  padding-right: 30px !important;
}

.modal-section {
  margin-top: 0;
}

.modal-section h3 {
  font-size: 0.9rem;
  margin-bottom: 8px;
  font-weight: 600;
  color: var(--muted);
}

.add-item-row {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}

.add-item-row input {
  flex: 1;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  font-family: inherit;
}

.btn-icon {
  background: var(--ink);
  color: var(--bg);
  border: none;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  font-size: 1.15rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  transition: transform 0.15s ease, opacity 0.15s ease;
}

.btn-icon:hover {
  opacity: 0.85;
}

.notes-list,
.tasks-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.note-item,
.task-item {
  background: var(--surface);
  padding: 8px 12px;
  border-radius: var(--r-sm);
  font-size: 0.95rem;
  display: flex;
  align-items: center;
  gap: 8px;
}

.task-item.completed span {
  text-decoration: line-through;
  opacity: 0.6;
}

.modal-actions {
  padding: 14px 20px;
  border-top: 1px solid var(--line);
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 12px;
  background: var(--surface-2);
}

.auto-save-status {
  margin-right: auto;
  font-size: 0.8rem;
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 20px;
  transition: opacity 0.3s ease;
}

.auto-save-status:empty {
  visibility: hidden;
}

.auto-save-status[data-state="saving"] {
  color: var(--muted);
}

.auto-save-status[data-state="saved"] {
  color: var(--success-ink);
}

.auto-save-status[data-state="error"] {
  color: var(--danger-ink);
}

.auto-save-status[data-state="pending"] {
  color: var(--warning-ink);
}

@keyframes auto-save-spin {
  to { transform: rotate(360deg); }
}

.auto-save-status .auto-save-spinner {
  width: 14px;
  height: 14px;
  border: 2px solid var(--line-strong);
  border-top-color: var(--muted);
  border-radius: 50%;
  animation: auto-save-spin 0.6s linear infinite;
}

/* Indicators */
.card-indicators {
  display: flex;
  gap: 6px;
  margin-top: 4px;
}

.indicator-notes,
.indicator-tasks {
  font-size: 0.8rem;
  display: inline-block;
  opacity: 0.6;
}

/* Timeline Modal Section */
.timeline-section {
  border-top: 1px solid var(--border);
  padding-top: 16px;
  margin-top: 24px;
}

.timeline-content {
  position: relative;
  margin-top: 16px;
  padding-left: 24px;
  transition: all 0.3s ease;
  max-height: 1000px;
  /* Large enough */
  overflow: hidden;
}

.timeline-content.collapsed {
  max-height: 0;
  margin-top: 0;
  opacity: 0;
}

.section-header .toggle-icon {
  transition: transform 0.3s ease;
  font-size: 0.8rem;
  color: var(--muted);
}

.timeline-content:not(.collapsed) ~ .section-header .toggle-icon {
  transform: rotate(180deg);
}

.timeline-item {
  position: relative;
  margin-bottom: 16px;
  font-size: 0.85rem;
}

.timeline-item::before {
  content: "";
  position: absolute;
  left: -21px;
  top: 4px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--line-strong);
  border: 2px solid var(--surface);
  z-index: 1;
}

.timeline-item .event-date {
  font-size: 0.75rem;
  color: var(--muted);
  display: block;
  margin-bottom: 2px;
}

.timeline-item .event-text {
  color: var(--ink);
  line-height: 1.4;
}

/* Card details modal layout */
#card-modal {
  width: calc(100vw - 6vh);
  height: 94vh;
  margin: auto;
  max-width: none;
  max-height: none;
  border-radius: var(--r-xl);
  background: transparent;
  overflow: visible;
}

#card-modal .card-modal-content {
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  border-radius: var(--r-xl);
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

#card-modal .modal-header {
  padding: 18px 22px 14px;
}

#card-modal .card-modal-body {
  padding: var(--space-12) var(--space-16);
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-height: 0;
}

#card-modal .card-modal-workspace {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: 1fr 4fr;
  gap: 16px;
  overflow: hidden;
}

#card-modal .modal-panel {
  display: flex;
  height: 100%;
  flex-direction: column;
  min-height: 0;
}

#card-modal .principal-panel-content {
  flex: 1;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: var(--space-16);
  overflow-y: auto;
  min-height: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--glass-soft);
}

#card-modal .kanbito-shell {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--glass-soft);
  overflow: hidden;
}

#card-modal .kanbito-shell-header {
  padding: 12px 14px 10px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
}

#card-modal .kanbito-shell-header h3 {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
  color: var(--ink);
  font-family: var(--font-display);
}

#card-modal .kanbito-shell-body {
  flex: 1;
  min-height: 0;
  padding: 12px;
  display: flex;
  flex-direction: column;
}

#card-modal .kanbito-board {
  --kanbito-cols: 5;
  display: grid;
  grid-template-columns: repeat(var(--kanbito-cols), minmax(0, 1fr));
  gap: var(--space-12);
  min-height: 0;
  overflow-x: hidden;
  overflow-y: hidden;
  flex: 1;
}

#card-modal .project-types-selector {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

#card-modal .project-type-chip {
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink-2);
  padding: 6px 12px;
  border-radius: 999px;
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

#card-modal .project-type-chip:hover {
  border-color: var(--line-strong);
}

#card-modal .project-type-chip.selected {
  border-color: transparent;
}

#card-modal .project-type-chip.project-type-estrategia.selected {
  background: var(--project-type-estrategia-bg);
  color: var(--project-type-estrategia-ink);
  border-color: var(--project-type-estrategia-border);
}

#card-modal .project-type-chip.project-type-treinamento.selected {
  background: var(--project-type-treinamento-bg);
  color: var(--project-type-treinamento-ink);
  border-color: var(--project-type-treinamento-border);
}

#card-modal .project-type-chip.project-type-desenvolvimento.selected {
  background: var(--project-type-desenvolvimento-bg);
  color: var(--project-type-desenvolvimento-ink);
  border-color: var(--project-type-desenvolvimento-border);
}

#card-modal .kanbito-column {
  min-width: 0;
  height: 100%;
  display: flex;
  min-height: 0;
  transition: transform 0.2s ease;
}

#card-modal .kanbito-column:hover {
  transform: translateY(-1px);
}

#card-modal .kanbito-column-card {
  background: var(--surface-2);
  border: 1px solid var(--glass-border);
  border-radius: var(--r-md);
  padding: var(--space-12);
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  min-height: 0;
  width: 100%;
  box-shadow: var(--glass-highlight);
  transition:
    border-color 0.2s ease,
    box-shadow 0.2s ease;
}

#card-modal .kanbito-column:hover .kanbito-column-card {
  border-color: var(--glass-border-strong);
}

#card-modal .kanbito-column-card--locked {
  background: transparent;
  border-style: dashed;
  opacity: 0.5;
}

#card-modal .kanbito-column-card--locked .btn-close:not(.allow-open) {
  display: none;
}

#card-modal .kanbito-column-card--locked .add-item-row input,
#card-modal .kanbito-column-card--locked .add-item-row button,
#card-modal .kanbito-column-card--locked .hidden-file-input {
  opacity: 0.5;
  pointer-events: none;
}

#card-modal .kanbito-column-card--locked .add-item-row input {
  background: var(--surface-3);
}

#card-modal .kanbito-section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

#card-modal .kanbito-lock-badge {
  display: none !important;
}

#card-modal .file-add-row {
  align-items: center;
}

#card-modal .file-add-row input {
  min-width: 0;
}

#card-modal .hidden-file-input {
  display: none;
}

#card-modal .file-name-hint {
  margin: var(--space-8) 0 0;
  font-size: 0.8rem;
  color: var(--muted);
  min-height: 1rem;
}

#card-modal .document-item {
  background: var(--surface);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-highlight), var(--shadow-sm);
  padding: 10px;
  border-radius: var(--r-sm);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}

#card-modal .document-item:hover {
  transform: translateY(-1px);
  border-color: var(--line-strong);
  box-shadow: var(--shadow-md);
}

#card-modal .document-item-text {
  font-size: 0.85rem;
  color: var(--ink-2);
}

#card-modal .document-item-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

#card-modal .form-group {
  margin-bottom: 0;
}

#card-modal .form-group label,
#card-modal .modal-section h3,
#card-modal .section-label {
  display: block;
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--muted);
  margin-bottom: var(--space-8);
}

#card-modal .list-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  min-height: 0;
}

#card-modal .add-item-row {
  margin-top: 0;
}

#card-modal .add-item-row input {
  min-width: 0;
}

#card-modal .notes-list,
#card-modal .tasks-list,
#card-modal .documents-list,
#card-modal .billing-list {
  flex: 1;
  min-height: 0;
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow-y: auto;
  padding-right: 4px;
}

#card-modal .note-item,
#card-modal .task-item {
  background: var(--surface);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-highlight), var(--shadow-sm);
  border-radius: var(--r-sm);
  padding: 10px;
  transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}

#card-modal .note-item:hover,
#card-modal .task-item:hover {
  transform: translateY(-1px);
  border-color: var(--line-strong);
  box-shadow: var(--shadow-md);
}

#card-modal .inline-edit-input {
  width: 100%;
  min-width: 0;
  padding: 6px 8px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-xs);
  font-size: 0.84rem;
  background: var(--surface);
  color: var(--ink);
}

@keyframes pulse {
  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0.45;
  }
}

#card-modal .kanbito-timeline-section {
  margin-top: 12px;
}

#card-modal .timeline-section {
  border-top: 1px solid var(--line);
  padding-top: var(--space-8);
  min-height: 48px;
  flex: 0 0 auto;
}

#card-modal .timeline-header {
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

#card-modal .timeline-header.expanded .toggle-icon {
  transform: rotate(180deg);
}

#card-modal .timeline-content {
  margin-top: var(--space-8);
  max-height: 210px;
  overflow-y: auto;
  transition: max-height 0.2s ease, margin-top 0.2s ease, opacity 0.2s ease;
}

#card-modal .timeline-content.collapsed {
  max-height: 0;
  margin-top: 0;
  opacity: 0;
  overflow: hidden;
  pointer-events: none;
}

#card-modal .note-item,
#card-modal .task-item,
#card-modal .document-item {
  cursor: grab;
}

#card-modal .kanbito-column-card--locked .note-item,
#card-modal .kanbito-column-card--locked .task-item,
#card-modal .kanbito-column-card--locked .document-item {
  cursor: default;
}

#card-modal .reorder-target {
  outline: 2px dashed var(--line-strong);
  outline-offset: 2px;
}

#card-modal .modal-saving-overlay {
  position: absolute;
  inset: 0;
  background: var(--glass);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: inherit;
}

#card-modal .modal-saving-overlay.hidden {
  display: none;
}

#card-modal .modal-saving-caption {
  display: block;
  margin-top: 4px;
  font-size: 0.8rem;
  color: var(--muted);
}

#card-modal .attention-toggle-group {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

#card-modal .switch-toggle {
  position: relative;
  display: inline-block;
  width: 42px;
  height: 24px;
}

#card-modal .switch-toggle input {
  opacity: 0;
  width: 0;
  height: 0;
}

#card-modal .switch-slider {
  position: absolute;
  inset: 0;
  background: var(--line-strong);
  border-radius: 999px;
  transition: background 0.2s ease;
}

#card-modal .switch-slider::before {
  content: "";
  position: absolute;
  width: 18px;
  height: 18px;
  left: 3px;
  top: 3px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  transition: transform 0.2s ease;
}

#card-modal .switch-toggle input:checked + .switch-slider {
  background: var(--warning);
}

#card-modal .switch-toggle input:checked + .switch-slider::before {
  transform: translateX(18px);
}

@media (max-width: 920px) {
  #card-modal .principal-panel-shell {
    flex-basis: 320px;
    min-width: 320px;
    max-width: 320px;
  }
}

@media (max-width: 768px) {
  #card-modal {
    width: 96vw;
    height: 96vh;
    max-height: 96vh;
    border-radius: 16px;
  }

  #card-modal .card-modal-content {
    width: 100%;
    height: 100%;
    border-radius: 16px;
  }

  #card-modal .card-modal-workspace {
    display: flex;
    flex-direction: column;
    overflow-y: auto;
  }

  #card-modal .principal-panel-shell,
  #card-modal .principal-panel-shell.collapsed {
    flex: 0 0 auto;
    width: 100%;
    min-width: 0;
    max-width: none;
  }

  #card-modal .principal-panel-shell.collapsed .principal-panel-header h3 {
    writing-mode: initial;
    text-orientation: initial;
    transform: none;
    margin-top: 0;
  }

  #card-modal .kanbito-panel-shell {
    min-height: 60vh;
  }

  #card-modal .kanbito-shell-body {
    padding: 10px;
  }

  #card-modal .kanbito-board {
    grid-template-columns: 1fr;
    overflow-x: hidden;
    overflow-y: auto;
  }

  #card-modal .kanbito-column {
    height: auto;
  }

  #card-modal .kanbito-column-card {
    height: auto;
    min-height: 220px;
  }

  #card-modal .notes-list,
#card-modal .tasks-list,
#card-modal .documents-list,
#card-modal .billing-list {
    max-height: 240px;
  }
}

.timeline-item .event-details {
  font-style: italic;
  color: var(--muted);
  font-size: 0.8rem;
}

/* Privacy Mode */
.privacy-enabled .card-client,
.privacy-enabled .card-value,
.privacy-enabled .card-contact,
.privacy-enabled .project-task-group-header .client-name,
.privacy-enabled .tel-privado {
  filter: blur(6px);
  pointer-events: none;
  user-select: none;
}

/* O ESTADO LIGADO DO OLHO MORA NO BLOCO DA BARRA LATERAL, e nao mais aqui.
   Ate 07/09/2026 esta regra pintava o botao de ink solido com `!important` nas
   tres declaracoes, porque na topbar ele era um `.btn-icon` e precisava vencer o
   `background: var(--ink)` que a classe ja dava. Na barra lateral o botao e um
   `.sidebar-btn`, que nasce transparente, entao nao ha nada para vencer — e o
   `!important` deixou de ser defesa para virar armadilha: ele ganhava, calado,
   da regra ambar que distingue "privacidade ligada" de "voce esta aqui".
   Procure `#privacy-toggle.active` no bloco da barra lateral. */

/* Color Palette */
.color-palette {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 12px;
  margin-top: 8px;
}

.color-option {
  width: 100%;
  aspect-ratio: 1;
  border-radius: 50%;
  cursor: pointer;
  border: 3px solid transparent;
  transition: all 0.2s ease;
  padding: 0;
  box-shadow: var(--shadow-sm);
}

.color-option:hover {
  transform: scale(1.1);
}

.color-option.selected {
  border-color: var(--ink);
  transform: scale(1.2);
}

/* Custom Dropdown Styles */
.dropdown-group {
  position: relative;
}

.custom-dropdown {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  border-radius: var(--r-sm);
  max-height: 220px;
  overflow-y: auto;
  z-index: 1000;
  box-shadow: var(--glass-highlight), var(--shadow-md);
  display: none;
  padding: 4px;
}

.custom-dropdown.active {
  display: block;
}

.dropdown-item {
  padding: 8px 10px;
  border-radius: var(--r-xs);
  cursor: pointer;
  font-size: 0.9rem;
  color: var(--ink);
  transition: background 0.1s;
}

.dropdown-item:hover {
  background: var(--hover-wash);
}

.dropdown-item:not(:last-child) {
  border-bottom: 0;
}

/* ---------------------------------------------------------------------------
   ESTADOS DE CARREGAMENTO
   ---------------------------------------------------------------------------

   Sao DOIS, e a diferenca entre eles e a unica coisa que importa aqui.

   1. A TELA AINDA NAO TEM NADA (abrir o admin, ou um F5). O que falta e o dado
      de `get-board-data`, e a tela inteira depende dele. Aqui NAO entra overlay
      nenhum: entra o ESQUELETO DE CARGA, que e o desenho da tela desenhado
      vazio. Ele esta escrito no index.html, dentro do proprio container de cada
      view, entao ja esta na PRIMEIRA PINTURA — antes de qualquer modulo rodar.
      Quem o apaga e o primeiro render de cada view, que limpa o container; a
      rede de seguranca e o `limparEsqueletos()` do ui.js, para o caminho em que
      o render nunca acontece porque a carga falhou.

      ATE 15/09/2026 ERA O CONTRARIO, e era feio: o overlay bloqueante cobria e
      desfocava a pagina inteira enquanto o board vinha, com uma caixa no centro
      escrita "Processando alteracoes..." — frase de gravacao, numa hora em que
      nada estava sendo gravado —, e atras dela a barra de busca boiando sozinha
      numa pagina vazia. Carregar pela primeira vez nao e uma operacao que
      precise bloquear ninguem: nao ha o que proteger de um clique.

   2. A TELA JA TEM DADO E ALGO ESTA SENDO GRAVADO (salvar card, apagar, mover,
      subir anexo). Aqui o overlay bloqueante e o certo, e pelo motivo que o
      primeiro caso nao tem: existe uma tela util embaixo, e clicar nela no meio
      da escrita produz uma segunda escrita contra um estado que ja mudou. E o
      unico uso do #global-loader hoje.

   NAO REAPROVEITE UM PELO OUTRO. Overlay onde deveria haver esqueleto esconde a
   tela que nao existe; esqueleto onde deveria haver overlay deixa clicavel o
   que esta sendo gravado.
*/

.global-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(8, 10, 18, 0.18);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
  transition: opacity 0.3s, visibility 0.3s;
}

.global-overlay.hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* A caixa entra no grupo `.glass` la em cima, entao o fundo, a borda e a sombra
   vem de la — e mudam junto com o resto do sistema quando ele mudar. */
.loader-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  min-width: 220px;
  max-width: 320px;
  padding: 24px 28px 22px;
  border-radius: var(--r-lg);
  text-align: center;
}

/*
  A MARCA NO LUGAR DA BARRINHA. O que girava aqui ate 15/09/2026 era uma barra
  de 4px com um retangulo azul deslizando — o indicador generico que vem em
  qualquer template, e que nao dizia de quem era a tela.

  Agora quem espera e o Ñ, no mesmo distintivo de tinta que ancora a barra
  lateral: mesmo fundo `--ink`, mesma proporcao de raio (40/13 virou 52/17) e o
  mesmo traco arredondado do wordmark oficial. A pagina inteira esta desfocada
  atras; o unico ponto nitido e a marca.
*/
.loader-marca {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 17px;
  background: var(--ink);
  color: var(--bg);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), var(--shadow-sm);
}

.loader-marca svg {
  width: 23px;
  height: auto;
  display: block;
  overflow: visible;
}

/*
  O Ñ SE DESENHA, e a espera e o proprio tracado. O truque que dispensa medir o
  caminho e o `pathLength="1"` que os dois <path> carregam no HTML: com ele o
  navegador reescala o comprimento real para 1, e `stroke-dasharray: 1` com
  `stroke-dashoffset` de 1 a 0 vale para qualquer curva sem uma linha de JS.

  O til sai com atraso de proposito — o corpo da letra e escrito primeiro e o
  til pousa depois, que e a ordem em que a mao escreve. O ciclo apaga com
  `opacity` e so entao devolve o dash ao inicio: com o traco ja invisivel, a
  volta nao aparece.
*/
.loader-marca path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: marca-tracar 2s ease-in-out infinite;
}

.loader-marca .loader-til {
  animation-delay: 0.22s;
}

@keyframes marca-tracar {
  0% {
    stroke-dashoffset: 1;
    opacity: 1;
  }

  45% {
    stroke-dashoffset: 0;
    opacity: 1;
  }

  72% {
    stroke-dashoffset: 0;
    opacity: 1;
  }

  90% {
    stroke-dashoffset: 0;
    opacity: 0;
  }

  91% {
    stroke-dashoffset: 1;
    opacity: 0;
  }

  100% {
    stroke-dashoffset: 1;
    opacity: 1;
  }
}

.loader-content p {
  margin: 0;
  font-weight: 600;
  color: var(--ink);
  font-size: 0.9rem;
  line-height: 1.35;
}

/* ---------------------------------------------------------------------------
   ESQUELETO DE CARGA
   ---------------------------------------------------------------------------

   CUIDADO COM A PALAVRA: neste projeto "esqueleto" ja significava outra coisa —
   o `montarEsqueleto` do calendario, que e a ARMACAO de nos que o modulo monta
   uma vez e repinta depois. Essas classes sao outra familia: sao os blocos
   cinzentos que ocupam o lugar do dado enquanto ele nao chegou.

   A REGRA DE UM ESQUELETO BOM E RESERVAR A MEDIDA CERTA. Por isso as colunas
   falsas do pipeline reusam `.kanban-column` e as celulas falsas do calendario
   reusam `.cal-dia`: o vidro, a largura e a altura sao os do componente de
   verdade, e a troca pelo dado nao mexe o layout. O que muda e so o conteudo —
   blocos no lugar de texto.

   Tudo aqui e `aria-hidden` no HTML. Leitor de tela nao le enfeite de espera; o
   que ele le e o `role="status"` do #global-loader e as mensagens de cada view.
*/
.esqueleto-bloco {
  display: block;
  position: relative;
  overflow: hidden;
  border-radius: var(--r-xs);
  background: var(--esqueleto);
}

/* A varredura e um brilho que atravessa o bloco, e nao o bloco piscando: piscar
   chama atencao para si, atravessar diz "esta vindo". */
.esqueleto-bloco::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    transparent,
    var(--esqueleto-brilho),
    transparent
  );
  animation: esqueleto-varrer 1.6s infinite;
}

@keyframes esqueleto-varrer {
  to {
    transform: translateX(100%);
  }
}

/*
  QUEM PEDIU MENOS MOVIMENTO NAO RECEBE MOVIMENTO NENHUM. Sao tres animacoes em
  loop na tela ao mesmo tempo (a varredura de cada bloco, o tracado da marca e o
  brilho do topo das colunas), e e exatamente o tipo de tela que o
  `prefers-reduced-motion` existe para desligar. O esqueleto continua no lugar,
  parado; a marca fica desenhada inteira.
*/
@media (prefers-reduced-motion: reduce) {
  .esqueleto-bloco::after {
    animation: none;
    opacity: 0;
  }

  .loader-marca path {
    animation: none;
    stroke-dashoffset: 0;
  }
}

/* --- Esqueleto: pipeline --- */

.esqueleto-coluna .column-top-total {
  pointer-events: none;
}

/* As medidas sao as das duas pilulas de verdade: 29px de altura, e a largura
   que "7" e "R$ 240.000,00" ocupam. */
.esqueleto-pilula-conta,
.esqueleto-pilula-valor {
  height: 29px;
  border-radius: 999px;
}

.esqueleto-pilula-conta {
  width: 34px;
}

.esqueleto-pilula-valor {
  width: 132px;
}

.esqueleto-titulo {
  height: 15px;
  width: 96px;
  margin: 6px 10px 8px 8px;
  border-radius: 999px;
}

/* Mesma caixa do `.card` — mesmo fundo, borda, raio, respiro e sombra —, sem o
   hover e sem a animacao de entrada, que sao de card que alguem pode pegar. */
.esqueleto-card {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 14px 14px 16px;
  background: var(--card-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--r-md);
  box-shadow: var(--glass-highlight), var(--shadow-sm);
}

.esqueleto-linha {
  height: 10px;
  border-radius: 999px;
}

.esqueleto-linha-cliente {
  width: 62%;
  height: 12px;
}

.esqueleto-linha-projeto {
  width: 84%;
}

.esqueleto-linha-valor {
  width: 44%;
  height: 14px;
  margin-top: 2px;
}

/* --- Esqueleto: tarefas --- */

/* O grupo, o cabecalho e a pilha sao as classes DE VERDADE (`.tarefas-grupo` e
   companhia, no <style> da view, dentro do index.html). O que esta aqui e so o
   miolo: os blocos que ocupam o lugar do nome do card, da contagem e de cada
   linha de tarefa. */

.esqueleto-tarefa-nome {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1;
  min-width: 0;
  /* O `min-height: 2.7em` do `.tarefas-grupo-nome`: e o que mantem os
     cabecalhos das colunas todos na mesma altura, com nome de uma ou de duas
     linhas. */
  min-height: 2.7em;
}

.esqueleto-tarefa-quantidade {
  flex: 0 0 auto;
  width: 26px;
  height: 18px;
  border-radius: 999px;
}

/* Mesma caixa do `.tarefa-linha`, sem o hover nem o transform. */
.esqueleto-tarefa {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 11px 12px;
  border: 1px solid var(--glass-border);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--glass-highlight), var(--shadow-sm);
}

.esqueleto-tarefa-marcador {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  border-radius: 4px;
  margin-top: 3px;
}

.esqueleto-tarefa-corpo {
  display: flex;
  flex-direction: column;
  gap: 7px;
  flex: 1;
  min-width: 0;
}

.esqueleto-tarefa-selo {
  width: 64px;
  height: 17px;
  border-radius: 999px;
}

/* --- Esqueleto: calendario --- */

.esqueleto-cal-titulo {
  height: 20px;
  width: 190px;
}

.esqueleto-cal-btn,
.esqueleto-cal-seta {
  height: 32px;
  border-radius: 999px;
}

.esqueleto-cal-btn {
  width: 64px;
}

.esqueleto-cal-seta {
  width: 32px;
}

.esqueleto-cal-resumo {
  height: 11px;
  width: 260px;
}

/* O numero do dia sai por pseudo-elemento, e nao por um <span> em cada celula:
   sao 35 celulas, e 35 blocos escritos a mao no index.html seriam 35 linhas
   dizendo a mesma coisa. */
.esqueleto-cal-dia::before {
  content: "";
  display: block;
  width: 16px;
  height: 11px;
  border-radius: 4px;
  background: var(--esqueleto);
}

/* --- Pipeline: filtros e selos de card --- */

.board-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
  padding: 8px;
  border-radius: 999px;
}

.board-search-input {
  flex: 1 1 260px;
  min-width: 180px;
  padding: 8px 14px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--surface);
  font-family: inherit;
  font-size: 0.85rem;
  color: var(--ink);
  box-shadow: var(--glass-highlight);
}

.board-filter-select {
  padding: 8px 14px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--surface);
  font-family: inherit;
  font-size: 0.85rem;
  color: var(--ink);
  box-shadow: var(--glass-highlight);
}

.board-filter-toggle,
.board-filter-clear {
  padding: 8px 14px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: transparent;
  font-family: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

.board-filter-toggle:hover,
.board-filter-clear:hover {
  background: var(--hover-wash);
  color: var(--ink);
}

.board-filter-toggle.active {
  background: var(--ink);
  border-color: transparent;
  color: var(--bg);
}

.board-filter-summary {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--muted);
  padding: 0 8px;
}

.card-pipeline-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}

.card-forecast,
.card-lost,
.card-internal {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.7rem;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--muted);
  white-space: nowrap;
}

.card-forecast::before {
  content: "\1F4C5";
  font-size: 0.7rem;
}

.card-forecast[data-state="soon"] {
  background: var(--warning-bg);
  border-color: var(--warning-border);
  color: var(--warning-ink);
}

.card-forecast[data-state="overdue"] {
  background: var(--danger-bg);
  border-color: var(--danger-border);
  color: var(--danger-ink);
}

.card-lost {
  background: var(--danger-bg);
  border-color: var(--danger-border);
  color: var(--danger-ink);
}

/* Projeto interno: a pilula neutra, sem cor de estado. Ela nao avisa nada,
   so explica por que o card nao pesa no rodape da coluna. */
.card-internal {
  border-style: dashed;
}

/* Projeto interno: o que é de venda some, o que é só dele aparece. A classe
   mora no <dialog>, posta por `aplicarModoInterno` em pipeline.js. */
#card-modal.modo-interno .so-venda,
#card-modal:not(.modo-interno) .so-interno {
  display: none !important;
}

#card-modal .rotulo-opcional {
  font-weight: 400;
  color: var(--muted);
}

#card-modal .internal-toggle-group {
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}

#card-modal .attention-toggle-group label .field-hint {
  display: block;
  margin-top: 2px;
  font-weight: 400;
}

.field-hint {
  margin: 6px 0 0;
  font-size: 0.72rem;
  line-height: 1.35;
  color: var(--muted);
}

.field-hint[data-state="soon"] {
  color: var(--warning-ink);
  font-weight: 600;
}

.field-hint[data-state="overdue"] {
  color: var(--danger-ink);
  font-weight: 600;
}

#card-modal .form-group textarea,
.form-group textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  font-family: inherit;
  font-size: 0.9rem;
  resize: vertical;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.field-invalid {
  border-color: var(--danger) !important;
  background: var(--danger-bg);
}

/* Modo Privacidade: o ponderado e numero financeiro como qualquer outro valor,
   e hoje ele so aparece na dica do campo de probabilidade — os dois lugares que
   ele tinha no board (selo do card, rodape da coluna) sairam em 15/09/2026. */
.privacy-enabled .field-hint-money {
  filter: blur(5px);
  pointer-events: none;
  user-select: none;
}

/* O selo de perda vaza pelo TOOLTIP, e nao pelo texto. Na tela ele mostra so a
   palavra "Perdido"; o que ele carrega no atributo `title` e o motivo inteiro,
   ate 500 caracteres de texto livre escritos pelo Cesar ("ficou com a
   concorrente, nossa proposta estava 40% acima"). Tooltip nativo aparece por
   cima de tudo e NAO e afetado por `filter` — entao borrar o selo nao
   resolveria; o que suprime o tooltip e nao ser alvo de hover.

   Por isso aqui e so `pointer-events`, sem blur: a palavra "Perdido" nao e
   segredo (a coluna ja diz isso, e ela continua legivel) e apaga-la tiraria
   contexto de quem esta apresentando. Os selos vizinhos de valor so nao vazam
   tooltip porque o `pointer-events: none` da regra acima os desativa de tabela.

   Se um dia o motivo sair do `title` e passar a viver so no modal, esta regra
   pode sair junto. */
.privacy-enabled .card-lost {
  pointer-events: none;
}

/* ---------------------------------------------------------------------------
   TELA DE LOGIN
   ---------------------------------------------------------------------------

   O visual e o mesmo que existia no tempo do Supabase — cartao claro flutuando
   sobre um fundo escuro com formas organicas —, readaptado para o par
   usuario/senha e para a paleta que o resto do board usa hoje: os mesmos tokens
   de vidro, a mesma tipografia, o mesmo acento. O ponto do desenho e esse: quem
   abre admin.almn.ai tem de reconhecer o produto na primeira tela, e nao um
   formulario de biblioteca.

   Ela substitui a caixinha cinza nativa do `basic_auth`, que o navegador
   desenhava fora da pagina e que nao aceitava uma linha de estilo.

   O fundo e ESCURO de proposito. O board e claro; a tela de login ser o
   negativo dele torna obvio, de relance, que o app ainda nao abriu — util
   principalmente no caso chato, o da sessao que expira com o board ja na tela.
--------------------------------------------------------------------------- */

/*
  #auth-gate e um <dialog>, e o app.js o abre com showModal(). Ele fica na
  CAMADA DE TOPO do navegador, que passa por cima de qualquer z-index — e por
  cima tambem do modal de card, que e o motivo de ele ser um <dialog> (a nota
  esta no index.html). O `z-index` abaixo nao manda em nada enquanto ele estiver
  aberto por showModal; fica so para o caso de alguem um dia abrir com o
  atributo `open`, que nao usa a camada de topo.

  As tres primeiras declaracoes existem para desfazer o estilo que o navegador
  aplica a todo <dialog>: `width` e `height` de `fit-content`, `max-width` e
  `max-height` de `calc(100% - 6px - 2em)`, `border: solid`, `padding: 1em` e
  `margin: auto`. Sem isso a tela fica uma caixinha com borda no meio do vazio,
  que e exatamente a estetica de que estamos fugindo.
*/
.auth-gate {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  border: 0;
  border-radius: 0;
  z-index: 12000;
  overflow-y: auto;
  background:
    radial-gradient(48% 52% at 14% 18%, rgba(88, 130, 255, 0.55), transparent 70%),
    radial-gradient(40% 46% at 84% 12%, rgba(150, 110, 255, 0.42), transparent 70%),
    radial-gradient(46% 50% at 74% 88%, rgba(40, 190, 200, 0.42), transparent 70%),
    radial-gradient(34% 40% at 16% 84%, rgba(255, 150, 110, 0.28), transparent 70%),
    linear-gradient(160deg, #0b0e1a, #131a2e);
  padding: 24px;
  color: var(--ink);
}

/*
  O `display: flex` fica AQUI, e nao na regra acima, por uma armadilha classica
  de <dialog>: fechado, ele so nao aparece porque o navegador lhe da
  `display: none`. Escrever `display: flex` no seletor sem `[open]` sobrescreve
  esse padrao e deixa a tela de login permanentemente na frente do board.
*/
.auth-gate[open] {
  display: flex;
  align-items: center;
  justify-content: center;
}

/*
  O ::backdrop e a camada que o navegador pinta atras de um dialog modal. Aqui
  o proprio dialog ja cobre a viewport inteira, entao ele quase nunca aparece —
  quase: quando a sessao cai com o modal de card aberto, ha DOIS dialogs
  empilhados, e este fundo e o que impede o modal de baixo de vazar pelas
  bordas em telas muito baixas, em que o gate rola.
*/
.auth-gate::backdrop {
  background: rgba(8, 10, 18, 0.9);
}

.auth-ambient {
  position: absolute;
  inset: -16vh -8vw;
  pointer-events: none;
  filter: blur(6px);
}

.auth-shape {
  position: absolute;
  opacity: 0.55;
  border-radius: 24% 38% 31% 45%;
  background: linear-gradient(
    145deg,
    rgba(180, 225, 255, 0.35),
    rgba(90, 120, 255, 0.18)
  );
  animation: float-organic 20s ease-in-out infinite alternate;
}

.auth-shape.shape-1 {
  width: 280px;
  height: 280px;
  left: 8%;
  top: 14%;
  animation-duration: 22s;
}

.auth-shape.shape-2 {
  width: 220px;
  height: 220px;
  right: 12%;
  top: 10%;
  clip-path: polygon(50% 0%, 90% 24%, 100% 70%, 66% 100%, 26% 86%, 0 38%);
  animation-duration: 18s;
}

.auth-shape.shape-3 {
  width: 320px;
  height: 320px;
  left: 22%;
  bottom: -8%;
  animation-duration: 24s;
}

.auth-shape.shape-4 {
  width: 240px;
  height: 240px;
  right: 28%;
  bottom: -6%;
  clip-path: polygon(8% 25%, 75% 0, 100% 68%, 35% 100%, 0 75%);
  animation-duration: 17s;
}

.auth-shape.shape-5 {
  width: 180px;
  height: 180px;
  right: 40%;
  top: 34%;
  animation-duration: 16s;
}

@keyframes float-organic {
  0% {
    transform: translate3d(0, 0, 0) rotate(0deg) scale(1);
  }
  50% {
    transform: translate3d(16px, -26px, 0) rotate(8deg) scale(1.08);
  }
  100% {
    transform: translate3d(-22px, 18px, 0) rotate(-7deg) scale(0.95);
  }
}

.auth-card {
  position: relative;
  z-index: 1;
  width: min(420px, 100%);
  margin: auto;
  background: var(--glass-strong);
  -webkit-backdrop-filter: blur(var(--blur-strong)) saturate(var(--saturate));
  backdrop-filter: blur(var(--blur-strong)) saturate(var(--saturate));
  border: 1px solid var(--glass-border);
  border-radius: var(--r-xl);
  box-shadow: var(--glass-highlight), 0 40px 90px rgba(4, 8, 20, 0.45);
  padding: 30px 28px 26px;
}

.auth-logo {
  width: 150px;
  height: auto;
  display: block;
  margin: 0 auto 24px;
  color: var(--ink);
}

/* Os campos herdam .form-group do resto do app; o que muda aqui e so o alvo de
   toque e o anel de foco, que num cartao isolado precisa ser visivel. */
/* ---------------------------------------------------------------------------
   TILT — o cartão inclina seguindo o ponteiro (js/tilt.js), portado do
   TiltCard do CTX001-RecrutAI. O facho é um brilho radial que acompanha o
   cursor por cima do vidro; some quando o ponteiro sai.
   --------------------------------------------------------------------------- */
.tilt-facho {
  position: absolute;
  inset: 0;
  z-index: 10;
  overflow: hidden;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.3s;
}

.tilt-sobre .tilt-facho {
  opacity: 1;
}

.tilt-facho span {
  position: absolute;
  left: var(--facho-x, 50%);
  top: var(--facho-y, 50%);
  width: 200%;
  height: 200%;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, rgba(255, 255, 255, 0.15) 0%, transparent 40%);
}

/* will-change só enquanto o ponteiro está em cima: permanente, ele prende o
   cartão numa camada composta própria o tempo todo (no CTX001 isso fez um
   modal de z-index maior abrir ATRÁS do painel). */
.tilt-sobre {
  will-change: transform;
}

.auth-card .form-group {
  margin-bottom: 10px;
}

.auth-card .auth-input {
  padding: 12px 14px;
}

.auth-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--accent-ring);
}

.auth-submit-btn {
  width: 100%;
  padding: 12px 16px;
  margin-top: 4px;
  font-size: 0.95rem;
}

.auth-submit-btn:disabled {
  cursor: progress;
  opacity: 0.72;
}

/* O disco girando so existe enquanto o botao esta em .is-loading. Ele e a
   metade visivel da trava de duplo submit; a outra metade e o `disabled`. */
.auth-spinner {
  display: none;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-top-color: #fff;
  animation: auth-spin 0.7s linear infinite;
}

.auth-submit-btn.is-loading .auth-spinner {
  display: inline-block;
}

@keyframes auth-spin {
  to {
    transform: rotate(360deg);
  }
}

/* No fim do cartao, e some quando vazia: nenhum bloco vazio. Como nada vem
   depois dela, aparecer nao empurra botao nenhum de baixo do cursor. */
.auth-message {
  margin: 16px 0 0;
  font-size: 0.85rem;
  line-height: 1.4;
  text-align: center;
  color: var(--muted);
}

.auth-message:empty {
  display: none;
}

.auth-message-error {
  color: var(--danger-ink);
  font-weight: 600;
}

/* "ou" entre a senha e o Google: uma linha de cada lado. */
.auth-divisor {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 16px 0;
  font-size: 0.75rem;
  color: var(--faint);
}

.auth-divisor::before,
.auth-divisor::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--line);
}

.auth-google-btn {
  width: 100%;
  padding: 11px 16px;
  font-size: 0.95rem;
  text-decoration: none;
  box-sizing: border-box;
}

/* As formas de fundo sao decoracao pura: para quem pediu menos movimento no
   sistema, elas param onde estao. */
@media (prefers-reduced-motion: reduce) {
  .auth-shape {
    animation: none;
  }

  .auth-spinner {
    animation-duration: 2s;
  }
}

@media (max-width: 720px) {
  .auth-card {
    padding: 24px 18px 20px;
  }

  .auth-shape {
    opacity: 0.45;
  }
}

/* ===========================================================================
   AS TRES VIEWS: PIPELINE, TAREFAS E CALENDARIO
   ===========================================================================

   Tudo daqui para baixo foi ACRESCENTADO na rodada que quebrou a pagina unica
   em tres views roteadas por hash (#/pipeline, #/tarefas, #/calendario). Nenhuma
   regra acima desta linha foi tocada, e essa foi a instrucao mais importante da
   rodada: o pipeline esta no ar em admin.almn.ai e qualquer alteracao em regra
   existente e risco de producao sem beneficio nenhum para as telas novas.

   Se voce precisar mudar o visual de algo que o pipeline ja usava, prefira
   escrever uma regra NOVA com uma classe NOVA aqui embaixo a editar a de cima.
   O arquivo fica maior; o pipeline continua igual. Esse foi o negocio.

   O ROTEAMENTO NAO APARECE NO CSS. O hash e lido pelo JavaScript, que mostra uma
   view e esconde as outras. O que este arquivo oferece e so o suficiente para
   isso funcionar sem quebrar a altura do board: veja .app-view logo abaixo, que
   e a unica regra desta secao capaz de estragar o pipeline se estiver errada.

   VOCABULARIO. As telas novas reaproveitam de proposito o que ja existe:

     .btn, .btn-primary, .btn-secondary   botoes
     .btn-icon                            o "+" quadrado das linhas de adicionar
     .add-item-row                        campo + botao "+" lado a lado
     .board-search-input                  campo de busca
     .board-filter-select                 select de filtro
     .board-filter-toggle / -clear        botoes de filtro
     .field-hint                          texto de apoio abaixo de um campo
     .hidden                              esconder (display: none !important)

   Nao ha versao "de tarefas" desses controles, e nao deve haver: eles ja tem a
   cara certa, e duplica-los faria as telas divergirem com o tempo.
   ------------------------------------------------------------------------- */

/*
  Segundo bloco :root, e nao uma edicao do primeiro. Ele so DECLARA tokens
  novos — nao redefine nenhum dos que ja existiam —, entao a cascata nao tem o
  que resolver e o pipeline nao ve diferenca. Mante-lo separado deixa obvio, em
  qualquer diff futuro, o que nasceu nesta rodada.

  As duas familias de cor sao as duas unicas coisas com data no banco hoje
  (cards.expected_close_date e tasks.due_date), e o calendario precisa que voce
  distinga uma da outra de relance:

    - fechamento e AZUL, a mesma familia do --accent. E dinheiro previsto; e o
      assunto principal do board.
    - tarefa e VIOLETA, familia que o board nao usa em card nenhum, entao nao
      colide com nada que voce ja le como valor.

  Atrasado e vencendo reaproveitam o vermelho e o ambar de .card-forecast, de
  novo para nao inventar significado: se um selo esta vermelho no pipeline
  porque passou da data, ele fica vermelho no calendario pelo mesmo motivo.
*/
/* Os tokens de evento do calendario e dos estados de prazo derivam dos
   semanticos do primeiro :root, e por isso trocam de tema junto com ele. */
:root {
  --evento-fechamento-bg: var(--accent-bg);
  --evento-fechamento-ink: var(--accent-ink);
  --evento-fechamento-border: var(--accent-border);
  --evento-tarefa-bg: var(--violet-bg);
  --evento-tarefa-ink: var(--violet-ink);
  --evento-tarefa-border: var(--violet-border);
  --estado-vencendo-bg: var(--warning-bg);
  --estado-vencendo-ink: var(--warning-ink);
  --estado-vencendo-border: var(--warning-border);
  --estado-atrasado-bg: var(--danger-bg);
  --estado-atrasado-ink: var(--danger-ink);
  --estado-atrasado-border: var(--danger-border);
}

/* ---------------------------------------------------------------------------
   A BARRA LATERAL — navegacao entre as views e acoes de sessao
   ---------------------------------------------------------------------------

   ATE 07/09/2026 ISTO ERA UMA PILULA NA TOPBAR. As tres views moravam num
   controle segmentado (`.view-nav` / `.view-nav-btn`) dentro de
   `.topbar-actions`, ao lado do olho e do sair. As tres regras sairam junto com
   a marcacao: se voce for procura-las por causa de um `class="view-nav-btn"`
   que sobrou em algum lugar, elas nao existem mais — o gancho agora e
   `.sidebar-btn`.

   O QUE A MUDANCA COMPROU. A pilula era filha da topbar, e a topbar e do
   pipeline: em `#/tarefas` e `#/calendario` ela continuava mostrando "Pipeline
   Comercial e Delivery" com a navegacao pendurada nela. A barra e irma do
   `.app`, entao ela e a unica coisa da tela que nao pertence a nenhuma view —
   que e exatamente o que uma navegacao deve ser.

   SO ICONE, E O ROTULO E OBRIGATORIO. Um icone sem nome e um enigma. Cada botao
   carrega `aria-label` (leitor de tela) e `data-label` (o balao do hover, logo
   abaixo). Nao ponha `title`: o balao nativo do navegador apareceria por cima
   do nosso, com atraso proprio, dizendo a mesma coisa duas vezes.

   ELA E MOLDURA, E NAO CONTEUDO — e ate 09/09/2026 ela nao parecia.

   A barra nasceu com a receita visual de um CARTAO: entrava no grupo `.glass`
   la em cima (borda nos quatro lados, sombra de flutuacao), tinha o mesmo
   `--r-lg` da `.kanban-column` e boiava com 12px de margem em volta. Encostada
   nas oito colunas do board, que tem exatamente esse desenho, ela virava a
   NONA — uma coluna estreita e sem cards. Quem olhava de relance procurava o
   titulo dela.

   O conserto e de POSICAO E DE FORMA, e nao de cor:

     - COLADA nas tres bordas da janela, sem margem. Cartao flutua dentro da
       janela; moldura E a janela. So isso ja tira a barra do ritmo do board.
     - CANTO RETO. Raio e o que diz "isto e um objeto solto". A barra nao e.
     - UMA LINHA SO, a da direita, no lugar do contorno de quatro lados. Ela nao
       CONTORNA a barra: ela SEPARA a navegacao do conteudo, que e outra coisa.
       E ela usa `--line-strong`, e nao o `--line` das bordas de cartao: esta
       linha e a unica marca de onde a moldura acaba, e a 9% de opacidade sobre
       vidro borrado ela sumia. Divisoria que nao se ve nao divide nada.
     - SEM SOMBRA. Sombra promete que ha algo por baixo, e nao ha: a barra e
       irma do `.app` num flex, o conteudo fica ao LADO, nunca embaixo.

   O BORRAO FICA, e e ele que mantem a barra no mesmo idioma do resto — o fundo
   ambiente continua atravessando. O que ela deixou de ser e um cartao.
*/
.app-sidebar {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  width: 64px;
  padding: 14px 0;
  background: var(--glass-strong);
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  border-right: 1px solid var(--line-strong);
  overflow: visible;
  z-index: 5;
}

.sidebar-logo {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  margin-bottom: 10px;
  border-radius: 13px;
  background: var(--ink);
  color: var(--bg);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), var(--shadow-sm);
  pointer-events: none;
  user-select: none;
}

.sidebar-logo svg {
  width: 18px;
  height: auto;
  display: block;
}

.sidebar-group {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}

/* O `margin-top: auto` e o unico separador entre as duas naturezas de icone: em
   cima o que troca de tela, embaixo o que mexe na sessao. Uma linha divisoria
   faria o mesmo trabalho com mais tinta. */
.sidebar-footer {
  margin-top: auto;
}

.sidebar-btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 42px;
  height: 42px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 14px;
  background: transparent;
  color: var(--muted);
  font-family: inherit;
  text-decoration: none;
  cursor: pointer;
  transition:
    background 0.2s ease,
    color 0.2s ease,
    border-color 0.2s ease,
    box-shadow 0.2s ease;
}

.sidebar-btn:hover {
  background: var(--hover-wash);
  color: var(--ink);
}

/*
  Quatro seletores para o estado ligado porque ha quatro marcacoes plausiveis, e
  a barra nao pode depender de qual delas o JavaScript escolheu:

    .active               o que o rotas.js e o ui.js poem hoje;
    [aria-current="page"] o certo para link de navegacao, e o rotas.js poe os dois;
    [aria-current="true"] a mesma ideia escrita da outra forma;
    [aria-selected]       o certo se um dia isto virar role="tablist".

  `[aria-current="page"]` e escrito com o valor, e nao so `[aria-current]`, de
  proposito: `aria-current="false"` e a forma correta de dizer "nao e a atual", e
  o seletor sem valor casaria com ela e acenderia os tres icones ao mesmo tempo.
*/
.sidebar-btn.active,
.sidebar-btn[aria-current="page"],
.sidebar-btn[aria-current="true"],
.sidebar-btn[aria-selected="true"] {
  background: var(--surface);
  border-color: var(--glass-border-strong);
  color: var(--accent);
  box-shadow: var(--glass-highlight), var(--shadow-sm);
}

/* PRIVACIDADE LIGADA NAO E "VOCE ESTA AQUI". O ui.js poe `.active` no
   #privacy-toggle para dizer que o borrao esta ligado, e a regra acima pintaria
   isso com a mesma cor da view aberta — dois significados na mesma tinta, num
   lugar onde a pessoa le a cor antes do icone. O ambar separa os dois. */
#privacy-toggle.active {
  background: var(--warning-bg);
  border-color: var(--warning-border);
  color: var(--warning-ink);
}

.sidebar-btn-danger:hover {
  background: var(--danger-bg);
  color: var(--danger-ink);
}

.sidebar-btn:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--accent-ring);
}

/*
  O BALAO DE ROTULO. Ele le o `data-label` do proprio botao, entao nao ha texto
  repetido no CSS e nenhum botao pode ficar sem rotulo por esquecimento — quem
  omitir o atributo ganha um balao vazio, que e visivel na primeira passada de
  mouse.

  `pointer-events: none` nos dois pseudo-elementos porque um balao que recebe o
  mouse pode ficar entre o cursor e o botao, e o hover comecaria a piscar.
*/
.sidebar-btn::after {
  content: attr(data-label);
  position: absolute;
  left: calc(100% + 12px);
  top: 50%;
  transform: translateY(-50%);
  padding: 7px 11px;
  border-radius: 10px;
  background: var(--glass-strong);
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-highlight), var(--shadow-md);
  color: var(--ink);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease;
  z-index: 10;
}

/* A setinha. Um quadrado girado, ancorado no mesmo `left` do balao menos a
   metade da propria diagonal. */
.sidebar-btn::before {
  content: none;
}

.sidebar-btn:hover::after,
.sidebar-btn:hover::before,
.sidebar-btn:focus-visible::after,
.sidebar-btn:focus-visible::before {
  opacity: 1;
}

/* ---------------------------------------------------------------------------
   O CONTAINER DE VIEW — a regra que pode quebrar o pipeline
   ---------------------------------------------------------------------------

   LEIA ANTES DE MEXER. Ate esta rodada o #kanban-board era filho DIRETO de
   `.app`, e a corrente de altura era:

     .app (flex column, overflow hidden)
       -> #kanban-board (flex: 1; min-height: 0)
            -> .cards (flex: 1; overflow-y: auto)

   Envolver o board numa `<section class="app-view">` mete um elo novo no meio
   dessa corrente. Um elo que nao seja flex-column com `flex: 1` e
   `min-height: 0` faz o board parar de ser limitado pela altura da janela: as
   colunas crescem com o conteudo, `.cards` nunca chega a rolar por dentro, e a
   pagina inteira estoura para baixo de um <body> que e `overflow: hidden` — ou
   seja, os cards do fim da coluna ficam inalcancaveis, sem barra de rolagem
   nenhuma. Nao aparece erro; some conteudo.

   O `min-height: 0` e o detalhe que se esquece: por padrao um item flex tem
   `min-height: auto` e se recusa a encolher abaixo do conteudo, e e ele que
   transforma "cabe na tela e rola por dentro" em "empurra tudo para fora".

   NAO ponha padding nem margin aqui. O respiro ja e o `padding: 24px 32px 16px`
   do `.app`; qualquer coisa a mais desloca o pipeline em relacao a hoje, e o
   contrato desta rodada e que ele fique identico.
*/
.app-view {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  /* Mesmo overflow do `.app`: quem rola sao as areas internas (as colunas do
     board, o .view-body das telas novas), nunca a view inteira. */
  overflow: hidden;
}

/*
  Duas formas de esconder uma view, porque ha duas maneiras comuns de faze-lo e
  as duas precisam vencer o `display: flex` acima:

    - a classe `.hidden` ja existe neste arquivo com `!important`, entao ganha
      sozinha. Nao precisa de regra; esta anotada aqui so para voce nao procurar.
    - o atributo `hidden` NAO ganha: `[hidden] { display: none }` da folha do
      navegador perde para qualquer `display` de autor, por menos especifico que
      seja. Sem a regra abaixo, `secao.hidden = true` no JavaScript nao esconde
      nada e as tres views aparecem empilhadas.
*/
.app-view[hidden] {
  display: none;
}

/*
  A barra lateral "Tarefas Globais" e movel do PIPELINE: ela agrega as tarefas
  dos cards do board. Ao lado da view de Tarefas, que mostra as mesmas tarefas
  em tela cheia e ainda por cima as avulsas, ela viraria uma segunda lista das
  mesmas coisas — duas verdades na mesma tela, e nenhuma explicando por que
  discordam. No calendario ela so rouba largura da grade.

  O gancho e `data-view` no <body>, que e o lugar natural para o roteador anotar
  a view corrente. Enquanto ninguem escrever esse atributo a regra e inerte, e
  hoje ninguem escreve: e por isso que ela nao muda nada no pipeline atual.

  SE VOCE DISCORDAR, apague estas quatro linhas. Nada mais depende delas.
*/

/* ---------------------------------------------------------------------------
   CABECALHO, BARRA DE FERRAMENTAS E CORPO DAS VIEWS NOVAS
   ---------------------------------------------------------------------------

   NAO HA MAIS CABECALHO GLOBAL desde 07/09/2026 — a topbar que repetia o nome
   do produto nas tres telas saiu, e quem diz onde voce esta e a marca de "voce
   esta aqui" da barra lateral. Cada view diz o proprio nome e, no subtitulo, o
   que ela de fato faz. O subtitulo nao e enfeite: e ali que fica escrito o que
   a tela entrega, para ela nao prometer mais do que faz.
*/
.view-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-16);
  flex-wrap: wrap;
  margin-bottom: 14px;
  padding-bottom: var(--space-12);
  border-bottom: 1px solid var(--line);
}

.view-header-text {
  min-width: 0;
}

.view-title {
  margin: 4px 0 0;
  font-family: var(--font-display);
  font-size: 1.35rem;
  letter-spacing: -0.02em;
  font-weight: 700;
  color: var(--ink);
}

.view-subtitle {
  margin: 6px 0 0;
  /* 70ch porque linha de texto muito longa em tela larga fica dificil de ler, e
     este e o paragrafo que explica o escopo da tela — o que voce menos quer que
     seja pulado. */
  max-width: 70ch;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--muted);
}

.view-header-actions {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  flex-wrap: wrap;
}

/*
  Com rota por hash, o jeito honesto de escrever "va para o pipeline" e
  <a href="#/pipeline" class="btn btn-secondary">, e nao um <button> com
  listener. Acontece que `.btn` nasceu para <button>, que nao sublinha nada, e
  num <a> o sublinhado do navegador atravessa: o botao fica com um risco embaixo
  do texto. Foi visto na tela do estado vazio.

  A correcao fica AQUI, presa aos containers das telas novas, em vez de virar um
  `text-decoration: none` dentro do proprio `.btn` — mexer no `.btn` mexeria em
  todo botao do pipeline, e o contrato desta rodada e nao encostar nele.
*/
.view-header-actions .btn,
.view-empty-actions .btn,
.view-toolbar .btn {
  text-decoration: none;
}

/* Mesma forma da .board-toolbar do pipeline, com nome proprio: assim as telas
   novas nao ficam dependendo de uma classe do board para se organizar, mas os
   CONTROLES de dentro continuam sendo os mesmos (.board-search-input,
   .board-filter-select, .board-filter-toggle, .board-filter-clear). */
.view-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-8);
  margin-bottom: var(--space-12);
}

/*
  O unico elemento que rola nas telas novas. O <body> e `height: 100vh;
  overflow: hidden`, entao sem uma area de rolagem interna o conteudo que passa
  da dobra simplesmente some.

  `padding-right: 4px` e o mesmo respiro que as listas do modal de card usam
  para a barra de rolagem nao encostar no conteudo.
*/
.view-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: 4px;
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;
}

.view-body::-webkit-scrollbar {
  width: 6px;
}

.view-body::-webkit-scrollbar-thumb {
  background-color: var(--line-strong);
  border-radius: 20px;
  border: 2px solid transparent;
  background-clip: content-box;
}

/* ---------------------------------------------------------------------------
   ESTADOS VAZIOS
   ---------------------------------------------------------------------------

   Esta e a primeira coisa que voce vai ver nas duas telas novas, porque no
   primeiro dia nao existe uma linha com data no banco: `tasks.due_date` acabou
   de nascer vazia e poucos cards tem `expected_close_date` preenchido.

   Um vazio que so diz "nada aqui" transforma uma tela correta em tela quebrada
   aos olhos de quem abre. Por isso a caixa tem quatro partes, e a terceira e a
   que importa:

     .view-empty-icon   um simbolo, so para a caixa nao ser um bloco de texto
     .view-empty-title  o que esta vazio, em uma frase
     .view-empty-text   POR QUE esta vazio — de onde o dado viria
     .view-empty-steps  o que fazer para preencher, em passos numerados

   A borda tracejada e o mesmo sinal de "espaco a preencher" que o board ja usa
   no .drop-indicator do arrastar.
*/
.view-empty {
  margin: clamp(20px, 7vh, 80px) auto;
  max-width: 540px;
  padding: 28px 26px 24px;
  border-radius: var(--r-lg);
  text-align: center;
}

.view-empty-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  margin-bottom: var(--space-12);
  border-radius: 50%;
  background: var(--surface-3);
  border: 1px solid var(--border);
  font-size: 1.15rem;
  color: var(--muted);
}

.view-empty-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--ink);
}

.view-empty-text {
  margin: var(--space-8) 0 0;
  font-size: 0.85rem;
  line-height: 1.55;
  color: var(--muted);
}

/*
  Passos alinhados a ESQUERDA dentro de uma caixa centralizada: lista numerada
  com texto centralizado e quase ilegivel, porque o olho perde o inicio da
  linha seguinte. O contraste com o resto da caixa e proposital.
*/
.view-empty-steps {
  counter-reset: passo-vazio;
  list-style: none;
  margin: var(--space-16) 0 0;
  padding: var(--space-12) 0 0;
  border-top: 1px solid var(--border);
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.view-empty-steps li {
  counter-increment: passo-vazio;
  position: relative;
  padding-left: 30px;
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--ink-2);
}

.view-empty-steps li::before {
  content: counter(passo-vazio);
  position: absolute;
  left: 0;
  top: 0;
  width: 20px;
  height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--surface-3);
  border: 1px solid var(--border);
  font-size: 0.68rem;
  font-weight: 700;
  color: var(--muted);
}

.view-empty-actions {
  display: flex;
  justify-content: center;
  gap: var(--space-8);
  margin-top: var(--space-16);
}

/*
  Variante para o vazio que NAO e "o banco esta vazio", e sim "o filtro nao
  achou nada". Sao situacoes diferentes e merecem peso diferente: a primeira
  ensina a preencher, a segunda so avisa e sai da frente, porque abaixo dela
  costuma haver conteudo (a barra de filtros, outros grupos).
*/
.view-empty.is-compact {
  margin: var(--space-12) 0;
  max-width: none;
  padding: 16px 18px;
  text-align: left;
  box-shadow: none;
}

.view-empty.is-compact .view-empty-icon {
  display: none;
}

.view-empty.is-compact .view-empty-title {
  font-size: 0.9rem;
}

/* ---------------------------------------------------------------------------
   CHIPS
   ---------------------------------------------------------------------------

   Mesma pilula de .card-forecast / .card-lost, com nome generico porque nas
   telas novas ela nao vive dentro de um card. Os estados
   sao os mesmos do pipeline e querem dizer a mesma coisa — se um prazo fica
   vermelho no board, fica vermelho aqui, e pelo mesmo motivo.
*/
.chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--muted);
  font-size: 0.7rem;
  font-weight: 600;
  white-space: nowrap;
}

.chip[data-state="vencendo"] {
  background: var(--estado-vencendo-bg);
  border-color: var(--estado-vencendo-border);
  color: var(--estado-vencendo-ink);
}

.chip[data-state="atrasado"] {
  background: var(--estado-atrasado-bg);
  border-color: var(--estado-atrasado-border);
  color: var(--estado-atrasado-ink);
}

.chip[data-state="feito"] {
  background: var(--success-bg);
  border-color: var(--success-border);
  color: var(--success-ink);
}

/* O chip que aponta para o card de origem. Azul da mesma familia do evento de
   fechamento: nas duas telas, azul quer dizer "isto vem de um card". */
.chip-card {
  background: var(--evento-fechamento-bg);
  border-color: var(--evento-fechamento-border);
  color: var(--evento-fechamento-ink);
}

/* Tarefa sem card. Fica NEUTRA de proposito: "avulsa" nao e problema nem
   destaque, e so a ausencia de vinculo — pintar de vermelho ou ambar sugeriria
   um pendura que nao existe. */
.chip-avulsa {
  background: var(--surface-3);
  border-style: dashed;
  border-color: var(--line-strong);
  color: var(--muted);
}

/* ---------------------------------------------------------------------------
   VIEW DE TAREFAS
   ---------------------------------------------------------------------------

   E a barra lateral "Tarefas Globais" em tela cheia, e com duas coisas que ela
   nao tem: as tarefas AVULSAS (as de `card_id` nulo) e a data (`due_date`).

   O desenho segue o par que o board ja usa — fundo claro agrupando cartoes
   brancos. Aqui o agrupamento e leve (so um titulo com filete embaixo) porque a
   lista pode ficar longa e um painel por grupo encheria a tela de moldura.
*/
.task-compose {
  padding: var(--space-12) 14px;
  margin-bottom: var(--space-16);
  border-radius: var(--r-md);
}

/*
  A linha de criar reaproveita `.add-item-row` (campo + botao "+"), a mesma do
  modal de card. Duas coisas precisam ser corrigidas por cima dela, e as duas sao
  regras NOVAS com especificidade maior — a `.add-item-row` original continua
  intacta para o modal.

  1. `flex-wrap`. No modal a linha tem so dois filhos e nunca quebra, entao ela
     nasceu sem wrap. Aqui sao quatro (titulo, data, card, botao) e em tela
     estreita eles precisam poder descer de linha; sem isto o `flex: 1 1 100%`
     do bloco de 720px nao tem efeito nenhum — os itens so encolhem juntos, e a
     data fica com 200px em vez de ocupar a linha. Isto foi MEDIDO: antes desta
     regra, a 700px de largura, data e select ficavam com 201px cada.
  2. `flex` nos campos auxiliares. A regra `.add-item-row input` manda `flex: 1`
     em TODO input de dentro; sem as duas declaracoes abaixo a data fica do
     tamanho do titulo da tarefa e o "+" se espreme no canto. Especificidade
     0,2,0 contra 0,1,1 da original: ganham sem precisar de !important.
*/
.task-compose .add-item-row {
  flex-wrap: wrap;
}

.add-item-row .task-compose-date {
  flex: 0 0 auto;
  width: 150px;
}

.add-item-row .task-compose-select {
  flex: 0 1 220px;
  min-width: 0;
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-family: inherit;
  font-size: 0.9rem;
  color: var(--ink);
  background: var(--surface);
}

.task-group {
  margin-bottom: var(--space-24);
}

.task-group-header {
  display: flex;
  align-items: baseline;
  gap: var(--space-8);
  margin-bottom: 10px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}

.task-group-title {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--ink);
}

/* Mesma tipografia do `.project-task-group-header .client-name` da barra
   lateral: maiuscula pequena e muda, o nome do cliente como etiqueta e nao como
   titulo. */
.task-group-sub {
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.task-group-count {
  margin-left: auto;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--surface-3);
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--muted);
}

.task-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}

/*
  Tres colunas: caixa de marcar, conteudo, acoes. `align-items: start` para a
  caixa continuar alinhada com a PRIMEIRA linha do texto quando o titulo quebra
  em duas.

  CUIDADO COM O NOME: `.task-item` ja existe neste arquivo e e outra coisa (o
  item de checklist dentro do modal de card, com fundo cinza chapado). Nao troque
  um pelo outro; a linha da view de tarefas e `.task-row`.
*/
.task-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: start;
  gap: var(--space-12);
  padding: var(--space-12) 14px;
  background: var(--surface);
  border: 1px solid var(--glass-border);
  border-radius: var(--r-md);
  box-shadow: var(--glass-highlight), var(--shadow-sm);
  transition:
    transform 0.2s ease,
    border-color 0.2s ease,
    box-shadow 0.2s ease;
}

.task-row:hover {
  transform: translateY(-1px);
  border-color: var(--glass-border-strong);
  box-shadow: var(--glass-highlight), var(--shadow-md);
}

.task-row-check {
  width: 17px;
  height: 17px;
  margin: 2px 0 0;
  accent-color: var(--accent);
  cursor: pointer;
}

.task-row-main {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.task-row-title {
  margin: 0;
  font-size: 0.92rem;
  line-height: 1.4;
  color: var(--ink-2);
  /* O texto da tarefa vem do banco e pode ser uma frase longa sem espacos
     (um link colado, por exemplo); sem isto ele estoura a largura da linha. */
  overflow-wrap: anywhere;
}

.task-row-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}

/* Duas classes para o mesmo estado porque o arquivo ja tem as duas convencoes
   vivas: `.global-task-item.done` na barra lateral e `.task-item.completed` no
   modal. Aceitar as duas evita que a tela nova fique certa so por sorte. */
.task-row.done .task-row-title,
.task-row.completed .task-row-title {
  text-decoration: line-through;
  opacity: 0.5;
}

.task-row-actions {
  display: flex;
  align-items: center;
  gap: 6px;
}

/*
  Some ate o hover, igual ao `.card-remove` do board: apagar e a acao mais
  destrutiva da tela e nao deve ficar convidando o clique numa lista longa.

  O `:focus-visible` e obrigatorio junto: sem ele o botao existe para o mouse e
  nao existe para o teclado, porque quem chega nele com Tab nao ve onde parou.
*/
.task-row-remove {
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--faint);
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition:
    opacity 0.2s ease,
    background 0.2s ease,
    color 0.2s ease;
}

.task-row:hover .task-row-remove,
.task-row-remove:focus-visible {
  opacity: 1;
}

.task-row-remove:hover {
  background: var(--danger-bg);
  color: var(--danger);
}

/* ---------------------------------------------------------------------------
   O CALENDARIO NAO MORA MAIS AQUI
   ---------------------------------------------------------------------------

   Ate 07/09/2026 este ponto do arquivo tinha ~230 linhas de `.calendar-*`
   — `.calendar-shell`, `.calendar-day`, `.calendar-event`, `.calendar-legend` e
   companhia. NENHUMA delas jamais pintou um pixel: a view que foi ao ar usa
   classes `.cal-*`, declaradas no <style> da propria secao, no index.html. Eram
   dois calendarios escritos, e o que este arquivo descrevia nao era o que a tela
   mostrava.

   O estrago nao era so peso morto. Aquele bloco era o unico leitor do trio
   `--evento-tarefa-*`, logo acima — o que fazia o token parecer vivo e usado
   enquanto o calendario de verdade pintava a tarefa de cinza neutro. Quem fosse
   trocar a cor da tarefa mexeria aqui e nao veria diferenca nenhuma na tela.
   (O `--evento-fechamento-*` nunca esteve nessa situacao: o `.chip-card`, mais
   abaixo, sempre o leu.)

   OS TOKENS FICARAM, e agora sao lidos de verdade: as regras
   `.cal-item[data-tipo="..."]` do index.html apontam para eles, e sao o outro
   lado da tabela TIPOS de admin/js/calendario.js. Para acrescentar um tipo, leia
   o comentario daquela tabela — ele lista os quatro passos na ordem.

   O bloco inteiro esta no historico do git, se algum dia o calendario voltar
   para ca.
*/

/* ---------------------------------------------------------------------------
   MODO PRIVACIDADE NAS TELAS NOVAS
   ---------------------------------------------------------------------------

   O botao de privacidade fica na barra lateral, que e comum as tres views: se
   ele borrar o board e deixar nome de cliente legivel na tela de tarefas ou no
   calendario, o botao passa a mentir — e o momento em que ele e usado
   (apresentacao com a tela compartilhada) e exatamente o momento em que trocar
   de aba e natural.

   POR ISSO O DADO SENSIVEL PRECISA DE CLASSE PROPRIA nas telas novas. Nome de
   cliente e valor nao podem ficar soltos dentro do texto de uma linha: envolva
   num <span> com uma classe que este bloco alcance, senao ele nao tem como
   chegar la.

   ONDE ISSO E FEITO HOJE: nos <style> das proprias views, no index.html —
   `.privacy-enabled .tarefas-grupo-nome-card` na tela de Tarefas e
   `.privacy-enabled .cal-privado` no Calendario. As regras abaixo sao as do
   par `.task-*`, que descreve uma tela de tarefas que nunca foi ao ar; elas
   ficam porque o raciocinio do `title`, logo abaixo, vale para as duas.

   E ATENCAO AO `title`: o tooltip nativo do navegador NAO e afetado por
   `filter`. Tanto o item do calendario quanto o cabecalho da coluna de tarefas
   usam `title` para mostrar o texto que nao coube — e um `title` com nome de
   cliente vaza inteiro com a privacidade ligada. Quem monta o `title` e o
   JavaScript, e e la que essa decisao mora; este arquivo nao consegue defender
   voce disso. (O mesmo raciocinio ja esta escrito no bloco do `.card-lost`,
   mais acima.)
*/
.privacy-enabled .task-group-sub,
.privacy-enabled .task-row-client,
.privacy-enabled .task-row-value {
  filter: blur(5px);
  pointer-events: none;
  user-select: none;
}

/* ---------------------------------------------------------------------------
   TELAS ESTREITAS
   ------------------------------------------------------------------------- */

@media (max-width: 1024px) {
  .view-header {
    align-items: flex-start;
  }
}

@media (max-width: 720px) {
  /* A BARRA CONTINUA NA TELA, so mais estreita. Ela nao vira menu de hamburguer
     e nao some: escondida atras de um botao, a navegacao passaria a custar dois
     toques em vez de um, e 52px numa tela de 720 e menos de 8% da largura — o
     board perde menos do que a navegacao perderia. */
  .app-sidebar {
    width: 52px;
    padding: 12px 0;
  }

  .sidebar-btn {
    width: 36px;
    height: 36px;
  }

  /* O balao sai no toque. Num aparelho sem mouse o `:hover` gruda no ultimo
     elemento tocado, e o rotulo ficaria aceso sobre o board depois do clique,
     sem nada que o apague. O `aria-label` continua servindo o leitor de tela. */
  .sidebar-btn::after,
  .sidebar-btn::before {
    display: none;
  }

  .add-item-row .task-compose-date,
  .add-item-row .task-compose-select {
    /* Numa linha estreita os campos auxiliares passam a ocupar a largura toda:
       um campo de data de 150px ao lado de um titulo espremido nao serve a
       nenhum dos dois. */
    flex: 1 1 100%;
    width: auto;
  }
}

/* Quem pediu menos movimento no sistema nao deve ganhar cartao pulando a cada
   passagem do mouse. O mesmo cuidado que as formas da tela de login ja tomam. */
@media (prefers-reduced-motion: reduce) {
  .task-row,
  .sidebar-btn {
    transition: none;
  }

  .task-row:hover {
    transform: none;
  }
}

/* ===========================================================================
   DETALHE DA TAREFA: O AUTOR DO COMENTARIO SEM DEPENDER DE COR
   ===========================================================================

   LEIA ANTES DE MEXER, PORQUE ESTE BLOCO NAO E A FOLHA DO DETALHE.

   O visual do `<dialog id="tarefa-detalhe">` — casca, cabecalho, secoes, campo
   de descricao, cartao de comentario, botao de apagar — mora num <style> dentro
   do index.html, logo acima da propria marcacao do dialog, pela mesma convencao
   que a view de Tarefas e o Calendario ja seguem: naquela rodada o styles.css
   tinha outro dono, e duas maos no mesmo arquivo e como se perde edicao.

   O que este bloco faz e SOMAR a essa folha o unico canal que ela nao tem: uma
   distincao de autor que sobreviva sem cor. Ele nao redesenha nada e nao repete
   nada. Se um dia aquele <style> for recortado para ca, junte estas regras nas
   de la em vez de deixar as duas metades separadas.

   POR QUE ELAS GANHAM A CASCATA. O <style> do index.html vem DEPOIS do
   <link rel="stylesheet"> no documento, entao em empate de especificidade ele
   vence. Todo seletor daqui comeca por `#tarefa-detalhe` de proposito: um id
   (1,x,x) ganha de qualquer seletor de classe de la, e a ordem deixa de
   importar. Nao troque esse prefixo por classe achando que e ruido.

   ---------------------------------------------------------------------------
   O QUE FOI MEDIDO
   ---------------------------------------------------------------------------

   A folha do index.html distingue humano de agente por TRES coisas, e as tres
   sao cor: o trilho da borda esquerda, o fundo do cartao e a cor do nome. Medido
   no navegador, com o dialog aberto e um comentario de cada tipo na tela, a
   razao de contraste ENTRE as duas versoes de cada canal era:

     trilho da esquerda   1,83 : 1    (#cbd5e1 contra #a78bfa)
     fundo do cartao      1,05 : 1    (#f8fafc contra #f5f3ff)
     cor do nome          1,46 : 1    (#334155 contra #6d28d9)

   E forma e peso eram IDENTICOS nos dois: mesmo border-radius, mesmo estilo de
   borda, mesmo font-weight, mesmo text-transform.

   Em escala de cinza, 1,05 e 1,46 sao o mesmo pixel: o fundo e o nome
   simplesmente desaparecem como sinal. Sobra o trilho, a 1,83 — abaixo dos 3:1
   que se pede de um elemento nao textual. Ou seja: num monitor ruim, com o
   brilho baixo, ou para quem tem deuteranopia, os tres comentarios da conversa
   ficavam iguais.

   Isso importa mais aqui do que pareceria hoje, que todo comentario e humano. No
   dia em que a camada de agente entrar (docs/plano-camada-de-agente.md), "quem
   escreveu isto" deixa de ser enfeite e vira a primeira pergunta de quem le a
   conversa. A resposta nao pode depender de o monitor estar bom.

   As duas regras abaixo acrescentam os dois canais que faltavam, e nenhum dos
   dois e cor:

     FORMA   um marcador antes do nome: disco CHEIO para pessoa, quadrado
             VAZADO para agente. Circulo contra quadrado, preenchido contra
             contornado — se enxerga em cinza, de longe e de esguelha.
     PESO    o trilho do agente fica mais grosso E no tom escuro da familia, em
             vez do lilas claro. E diferenca de espessura e de luminosidade, que
             e o que a escala de cinza preserva.
   ------------------------------------------------------------------------- */

/*
  O marcador herda `currentColor`, entao ele acompanha sozinho a cor que a folha
  do index.html ja da ao nome de cada autor. Se a paleta de la mudar, este bloco
  nao precisa saber.

  `vertical-align: middle` porque o cabecalho do comentario alinha os filhos pela
  BASELINE: sem isto o disco desce e fica pendurado abaixo do nome.
*/
#tarefa-detalhe .tarefa-comentario-autor::before {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 6px;
  vertical-align: middle;
  border: 2px solid currentColor;
  border-radius: 50%;
  /* Disco CHEIO: a borda e o fundo sao a mesma cor, entao o que se ve e um
     ponto solido. E o padrao, e nao o caso especial — qualquer valor novo do
     enum kanban.autoria cai aqui, do mesmo jeito que a folha do index.html ja
     resolveu para a cor. */
  background: currentColor;
}

/* Quadrado VAZADO: so o contorno, e com canto. Duas diferencas de forma de uma
   vez (preenchimento e cantos), porque uma so num quadrado de 8px e pouco. */
#tarefa-detalhe .tarefa-comentario[data-autor="agente"] .tarefa-comentario-autor::before {
  border-radius: 2px;
  background: transparent;
}

/*
  O canal de PESO.

  `--autor-agente-ink` e declarado no `#tarefa-detalhe` da folha do index.html e
  desce por heranca ate aqui. Usa-lo em vez de repetir o hexadecimal mantem uma
  fonte da verdade so para a paleta do autor; o fallback existe para o caso de
  aquele bloco sair de cena, e nao para o dia a dia — sem ele, a variavel
  indefinida deixaria a borda esquerda sem cor declarada.

  O `padding-left` desconta os 2px que o trilho engordou, para o texto do
  comentario de agente comecar na mesma coluna do texto do comentario de pessoa.
  Sem isso a conversa fica com o paragrafo do agente deslocado, e o olho le isso
  como desalinho, nao como sinal.
*/
#tarefa-detalhe .tarefa-comentario[data-autor="agente"] {
  border-left-width: 5px;
  border-left-color: var(--autor-agente-ink, #6d28d9);
  padding-left: 10px;
}

/*
  ONDE NAO HA MOUSE, O BOTAO DE APAGAR NAO PODE FICAR INVISIVEL.

  A folha do index.html esconde o "Apagar" com `opacity: 0` e o traz de volta no
  `:hover` do comentario ou no `:focus-visible` do proprio botao. Num aparelho de
  toque nao existe hover, e `:focus-visible` so acende depois do toque — ou seja,
  o botao fica permanentemente transparente E permanentemente clicavel. Um alvo
  invisivel que apaga comentario e pior do que um botao visivel demais.

  `(hover: none)` pergunta pelo APARELHO, e nao pela largura da janela: uma
  janela estreita num laptop continua tendo mouse e continua escondendo o botao,
  que e o que a folha de la quis.

  A regra de la que desliga o botao enquanto uma escrita esta no ar
  (`#tarefa-detalhe[data-ocupado="sim"] .tarefa-comentario-apagar`) tem
  especificidade maior que esta e continua ganhando — de proposito: durante a
  escrita o botao deve sumir em qualquer aparelho.
*/
@media (hover: none) {
  #tarefa-detalhe .tarefa-comentario-apagar {
    opacity: 1;
  }
}

/* Quem pediu menos movimento no sistema nao deve ganhar botao surgindo a cada
   passagem do mouse. Bloco proprio, e nao um acrescimo ao
   `prefers-reduced-motion` que ja existe mais acima: media queries se somam, e
   mexer no bloco de la seria editar regra que ja estava no ar. */
@media (prefers-reduced-motion: reduce) {
  #tarefa-detalhe .tarefa-comentario-apagar {
    transition: none;
  }
}

/* ---------------------------------------------------------------------------
   KANBITO: A TAREFA QUE ABRE O DETALHE, E A COLUNA DE FEATURES (22/09/2026)
   ---------------------------------------------------------------------------

   O título da tarefa do kanbito virou um <button> que abre o detalhe da tarefa
   (o mesmo diálogo da tela de Tarefas). Ele se veste de texto — sem moldura,
   alinhado à esquerda — e só denuncia que é clicável no hover, como o corpo da
   linha na tela de Tarefas.
*/
#card-modal .task-item-corpo {
  flex: 1;
  min-width: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  overflow-wrap: anywhere;
  cursor: pointer;
}

#card-modal .task-item-corpo:hover,
#card-modal .task-item-corpo:focus-visible {
  color: var(--accent-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  outline: none;
}

/* O riscado de concluída valia para o <span> antigo; o título agora é botão. */
.task-item.completed .task-item-corpo {
  text-decoration: line-through;
  opacity: 0.6;
}

/* A lista de features. Cada item é um cartão como os de tarefa e nota, com o
   selo da esteira na frente do título e uma linha de progresso embaixo. */
#card-modal .features-list {
  list-style: none;
  margin: 0;
  padding: 0 4px 0 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

#card-modal .feature-item-corpo {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px 12px;
  border: 1px solid var(--glass-border);
  border-radius: var(--r-sm);
  background: var(--surface);
  box-shadow: var(--glass-highlight), var(--shadow-sm);
  font: inherit;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}

#card-modal .feature-item-corpo:hover,
#card-modal .feature-item-corpo:focus-visible {
  transform: translateY(-1px);
  border-color: var(--line-strong);
  box-shadow: var(--shadow-md);
  outline: none;
}

#card-modal .feature-item-topo {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

#card-modal .feature-item-titulo {
  flex: 1;
  min-width: 0;
  font-size: 0.88rem;
  font-weight: 600;
  line-height: 1.35;
  overflow-wrap: anywhere;
}

#card-modal .feature-item-meta {
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--muted);
}

#card-modal .feature-item[data-status="done"] .feature-item-titulo {
  color: var(--ink-2);
}

#card-modal .feature-lista-vazia {
  font-size: 0.78rem;
  line-height: 1.45;
  color: var(--muted);
}

/* O SELO DA ESTEIRA. Backlog neutro, Doing no acento, Done em verde: a mesma
   leitura de cor que o resto do app já dá a "em andamento" e a "feito". */
.feature-status {
  flex: 0 0 auto;
  padding: 2px 8px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-3);
  font-size: 0.64rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.feature-status[data-status="doing"] {
  border-color: var(--accent-border);
  background: var(--accent-bg);
  color: var(--accent-ink);
}

.feature-status[data-status="done"] {
  border-color: var(--success-border);
  background: var(--success-bg);
  color: var(--success-ink);
}

/* ---------------------------------------------------------------------------
   O DIÁLOGO DA FEATURE (#feature-detalhe)
   ---------------------------------------------------------------------------

   Mais largo que o detalhe da tarefa, e de propósito: a spec é um documento de
   onze seções, e a lateral (anexos, diário) precisa ficar à vista
   enquanto ele é escrito. As duas colunas rolam cada uma por si — rolar a spec
   não pode levar o diário embora.

   As variáveis de autor são as do #tarefa-detalhe: o comentário do agente de IA
   tem a mesma cor nas duas telas.
*/
#feature-detalhe {
  --autor-humano-bg: var(--surface-2);
  --autor-humano-borda: var(--line-strong);
  --autor-humano-ink: var(--ink-2);
  --autor-agente-bg: var(--violet-bg);
  --autor-agente-borda: var(--violet-border);
  --autor-agente-ink: var(--violet-ink);
  /* Quase a tela inteira (25/09/2026): a spec é documento longo, e a moldura
     de 16 px basta para dizer que é um diálogo por cima do board. */
  width: calc(100vw - 32px);
  max-width: none;
  height: calc(100vh - 32px);
  height: calc(100dvh - 32px);
  max-height: none;
  margin: auto;
  border-radius: var(--r-xl);
  overflow: hidden;
}

#feature-detalhe .modal-content {
  height: 100%;
  max-height: none;
}

/* O CABEÇALHO É A FICHA (25/09/2026): chave e card numa linha, o título em
   tamanho de título; no canto direito, o status ao lado do fechar. */
#feature-detalhe .feature-detalhe-cabecalho {
  align-items: flex-start;
  gap: 16px;
  padding: 20px 24px 16px;
}

.feature-detalhe-identidade {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.feature-detalhe-controles {
  flex: none;
  display: flex;
  align-items: center;
  gap: 12px;
}

.feature-detalhe-origem {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

/* A chave F-7: é por ela que se fala da feature com os agentes, então ela se
   lê de longe. É também o botão de copiar o link — o ícone diz isso. */
.feature-chave {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px 4px 11px;
  border: 1px solid var(--accent-border);
  border-radius: 999px;
  background: var(--accent-bg);
  color: var(--accent-ink);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.9rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: background 0.15s ease, box-shadow 0.15s ease;
}

.feature-chave:hover:not(:disabled) {
  box-shadow: var(--accent-ring);
}

.feature-chave:focus-visible {
  outline: none;
  box-shadow: var(--accent-ring);
}

.feature-chave:disabled {
  cursor: default;
  font-family: inherit;
}

.feature-chave:disabled .feature-chave-icone {
  display: none;
}

.feature-chave-icone {
  width: 14px;
  height: 14px;
  opacity: 0.75;
}

.feature-detalhe-card {
  margin: 0;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--muted);
}

/* O título é um campo, mas se veste de título: sem moldura até o mouse ou o
   foco chegarem. */
.feature-detalhe-titulo {
  width: 100%;
  margin-left: -8px;
  padding: 2px 8px;
  border: 1px solid transparent;
  border-radius: var(--r-xs);
  background: transparent;
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ink);
}

.feature-detalhe-titulo:hover {
  border-color: var(--line);
}

.feature-detalhe-titulo:focus {
  outline: none;
  border-color: var(--accent-border);
  background: var(--surface);
  box-shadow: var(--accent-ring);
}

/* A escolha de status: três pílulas num trilho, como um controle segmentado.
   O rádio de verdade fica por cima, transparente — teclado e leitor de tela
   continuam falando com um grupo de rádio. */
.feature-status-escolha {
  display: inline-grid;
  grid-template-columns: repeat(3, auto);
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-2);
}

.feature-status-escolha label {
  position: relative;
  margin: 0;
}

.feature-status-escolha input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.feature-status-escolha span {
  display: block;
  padding: 4px 14px;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 700;
  text-align: center;
  color: var(--muted);
  transition: background 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
}

.feature-status-escolha input:checked + span {
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--glass-highlight), var(--shadow-sm);
}

.feature-status-escolha input[value="doing"]:checked + span {
  background: var(--accent-bg);
  color: var(--accent-ink);
}

.feature-status-escolha input[value="done"]:checked + span {
  background: var(--success-bg);
  color: var(--success-ink);
}

.feature-status-escolha input:focus-visible + span {
  box-shadow: var(--accent-ring);
}

/* A barra da DoD, no título da seção. */
.feature-barra {
  width: 64px;
  height: 6px;
  border-radius: 999px;
  background: var(--line-strong);
  overflow: hidden;
}

.feature-barra > span {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--success);
  transition: width 0.2s ease;
}

.feature-detalhe-aviso {
  margin: 12px 24px 0;
  padding: 8px 12px;
  border-radius: var(--r-xs);
  background: var(--surface-3);
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--ink-2);
}

.feature-detalhe-aviso:empty {
  display: none;
}

.feature-detalhe-aviso[data-tipo="erro"] {
  background: var(--danger-bg);
  color: var(--danger-ink);
}

#feature-detalhe .feature-detalhe-corpo {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 380px;
  padding: 0;
  overflow: hidden;
}

/* O DOCUMENTO: quatro grupos com nome, e dentro deles as seções. */
.feature-detalhe-spec {
  min-height: 0;
  overflow-y: auto;
  padding: 8px 28px 32px;
  display: flex;
  flex-direction: column;
}

.feature-grupo {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 20px 0 24px;
}

/* COM LARGURA, CADA GRUPO EM DUAS COLUNAS (29/09/2026). O diálogo ocupa quase
   a tela, e uma coluna só de ~1100 px centrada deixava duas faixas vazias dos
   lados. Lado a lado, cada seção fica numa largura boa de ler e a spec cabe em
   menos rolagem: requisitos funcionais | não funcionais, critérios | DoD. No
   problema, o contexto ocupa a esquerda inteira e objetivo e usuários se
   empilham à direita. A ordem no documento (e no Tab) continua a de SECOES. */
.feature-detalhe-spec {
  container-type: inline-size;
}

@container (min-width: 860px) {
  .feature-grupo {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
    gap: 16px 28px;
  }

  .feature-grupo-titulo {
    grid-column: 1 / -1;
  }

  .feature-secao[data-chave="contexto"] {
    grid-row: span 2;
  }
}

.feature-grupo + .feature-grupo {
  border-top: 1px solid var(--line);
}

.feature-grupo-titulo {
  margin: 0;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
}

.feature-secao {
  display: flex;
  flex-direction: column;
  gap: 6px;
  scroll-margin-top: 12px;
}

.feature-secao-topo {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.feature-secao-rotulo {
  font-size: 0.92rem;
  font-weight: 650;
  color: var(--ink);
}

.feature-secao[data-vazia="sim"] .feature-secao-rotulo {
  color: var(--muted);
}

.feature-secao-contagem {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.76rem;
  font-weight: 600;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.feature-secao-contagem[data-completo="sim"] {
  color: var(--success-ink);
}

/* O texto escrito se lê como texto: fundo leve, sem moldura até o mouse ou o
   foco chegarem. A seção vazia fica tracejada e baixa — a lacuna à vista. */
.feature-secao textarea {
  width: 100%;
  min-height: 44px;
  padding: 10px 12px;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--ink);
  font-family: inherit;
  font-size: 0.9rem;
  line-height: 1.55;
  resize: vertical;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}

.feature-secao[data-vazia="sim"] textarea {
  border-style: dashed;
  border-color: var(--line-strong);
  background: transparent;
}

.feature-secao textarea:hover {
  border-color: var(--line-strong);
}

.feature-secao textarea:focus {
  outline: none;
  border-style: solid;
  border-color: var(--accent-border);
  background: var(--surface);
  box-shadow: var(--accent-ring);
}

.feature-secao textarea::placeholder {
  color: var(--faint);
}

/* AS SEÇÕES DE LISTA (25/09/2026) — admin/js/spec-itens.js. Os itens moram
   numa bandeja com linhas finas entre eles; lápis e lixo acendem no hover (e
   ficam sempre acesos em tela de toque). O <textarea> da seção continua ali,
   escondido, e volta no modo Markdown. */
.feature-secao[data-modo="itens"] > textarea,
.feature-secao[data-modo="markdown"] > .spec-itens {
  display: none;
}

.feature-secao-contagem {
  margin-left: auto;
}

.feature-secao-acoes {
  display: flex;
  gap: 2px;
}

.feature-secao-contagem + .feature-secao-acoes {
  margin-left: 0;
}

.feature-secao-topo > .feature-secao-acoes:only-of-type {
  margin-left: auto;
}

.spec-botao {
  flex: none;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, opacity 0.15s ease;
}

.spec-botao:hover:not(:disabled) {
  background: var(--surface-3);
  color: var(--ink);
}

.spec-botao:focus-visible {
  outline: none;
  box-shadow: var(--accent-ring);
}

.spec-botao[aria-pressed="true"] {
  background: var(--accent-bg);
  color: var(--accent-ink);
}

.spec-botao-perigo:hover:not(:disabled) {
  background: var(--danger-bg);
  color: var(--danger-ink);
}

.spec-botao-ok {
  color: var(--accent-ink);
}

.feature-secao-adicionar {
  color: var(--accent-ink);
}

.feature-secao-adicionar:hover:not(:disabled) {
  background: var(--accent-bg);
  color: var(--accent-ink);
}

.spec-icone {
  width: 16px;
  height: 16px;
}

.spec-itens {
  margin: 0;
  padding: 0;
  list-style: none;
  border-radius: var(--r-sm);
  background: var(--surface-2);
}

.spec-itens:has(> .spec-itens-vazio) {
  background: transparent;
}

.spec-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 9px 8px 9px 12px;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--ink);
}

.spec-item + .spec-item {
  border-top: 1px solid var(--line);
}

/* O subtítulo dentro da lista ("A fazer", "Premissas"): separa, não é item. */
.spec-item[data-tipo="texto"] + .spec-item,
.spec-item + .spec-item[data-tipo="texto"] {
  border-top-color: transparent;
}

.spec-item[data-tipo="texto"] {
  color: var(--ink-2);
}

.spec-item-conteudo {
  flex: 1;
  min-width: 0;
  overflow-wrap: anywhere;
}

.spec-item-conteudo p {
  margin: 0;
}

.spec-item-conteudo code {
  padding: 1px 5px;
  border-radius: 6px;
  background: var(--surface-3);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.82em;
}

.spec-item-conteudo pre {
  margin: 0;
  padding: 8px 10px;
  border-radius: var(--r-xs);
  background: var(--surface-3);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.78rem;
  line-height: 1.45;
  overflow-x: auto;
  white-space: pre;
}

.spec-item-titulo {
  padding-top: 4px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

.spec-item-titulo strong {
  font-weight: inherit;
}

.spec-item-linha {
  color: var(--ink-2);
}

.spec-item-palavra {
  color: var(--accent-ink);
}

.spec-item-sub {
  position: relative;
  padding-left: 14px;
  color: var(--ink-2);
}

.spec-item-sub::before {
  content: "";
  position: absolute;
  left: 3px;
  top: 0.62em;
  width: 4px;
  height: 4px;
  border-radius: 999px;
  background: var(--faint);
}

/* A marca de cada tipo: o selo da série (RF-01), a caixa do checklist, o ponto. */
.spec-item-selo {
  flex: none;
  margin-top: 1px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--accent-bg);
  color: var(--accent-ink);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.74rem;
  font-weight: 700;
  line-height: 1.6;
}

.spec-item-check {
  flex: none;
  width: 16px;
  height: 16px;
  margin: 3px 0 0;
  accent-color: var(--success);
  cursor: pointer;
}

.spec-item[data-feito="sim"] .spec-item-conteudo {
  color: var(--muted);
}

.spec-item-ponto {
  flex: none;
  width: 6px;
  height: 6px;
  margin: 0.55em 2px 0;
  border-radius: 999px;
  background: var(--faint);
}

.spec-item-acoes {
  flex: none;
  display: flex;
  gap: 0;
  margin-top: -3px;
  opacity: 0;
  transition: opacity 0.15s ease;
}

.spec-item:hover .spec-item-acoes,
.spec-item:focus-within .spec-item-acoes {
  opacity: 1;
}

@media (hover: none) {
  .spec-item-acoes {
    opacity: 1;
  }
}

.spec-item-editando {
  background: var(--surface);
  border-radius: var(--r-sm);
  box-shadow: 0 0 0 1px var(--accent-border), var(--accent-ring);
  position: relative;
}

.spec-item-editor {
  flex: 1;
  min-width: 0;
}

.spec-item-editor textarea {
  display: block;
  width: 100%;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--ink);
  font-family: inherit;
  font-size: 0.9rem;
  line-height: 1.5;
  resize: none;
  overflow: hidden;
}

.spec-item-editor textarea:focus {
  outline: none;
}

.spec-item-editor-acoes {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-top: 6px;
}

.spec-item-dica {
  margin-right: auto;
  font-size: 0.7rem;
  color: var(--faint);
}

.spec-itens-adicionar {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 10px 12px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-sm);
  background: transparent;
  font-family: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.spec-itens-adicionar:hover:not(:disabled) {
  border-color: var(--accent-border);
  background: var(--accent-bg);
  color: var(--accent-ink);
}

/* Spec carregando, ocupada ou apagada lá fora: a lista se lê, mas não age. */
.feature-detalhe-spec[data-travado="sim"] .spec-botao,
.feature-detalhe-spec[data-travado="sim"] .spec-item-check,
.feature-detalhe-spec[data-travado="sim"] .spec-itens-adicionar {
  pointer-events: none;
  opacity: 0.4;
}

/* A LATERAL: o que rola (anexos e diário) em cima, o campo de comentar preso
   no pé. */
.feature-detalhe-lateral {
  min-height: 0;
  display: flex;
  flex-direction: column;
  border-left: 1px solid var(--line);
  background: var(--glass-soft);
}

.feature-lateral-rolagem {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 20px 20px 16px;
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.feature-lateral-bloco {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.feature-lateral-topo {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.feature-lateral-titulo {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
}

.feature-contagem {
  min-width: 18px;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--surface-3);
  font-size: 0.68rem;
  letter-spacing: 0;
  text-align: center;
  color: var(--muted);
}

.feature-contagem:empty {
  display: none;
}

.feature-lateral-acao {
  padding: 3px 8px;
  border: none;
  border-radius: 999px;
  background: transparent;
  font-family: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--accent-ink);
  cursor: pointer;
}

.feature-lateral-acao:hover:not(:disabled) {
  background: var(--accent-bg);
}

.feature-lateral-acao:disabled {
  opacity: 0.5;
  cursor: default;
}

.feature-detalhe-anexos {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.feature-anexo {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
}

.feature-anexo-nome {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.84rem;
  font-weight: 600;
  color: var(--accent-ink);
  text-decoration: none;
}

.feature-anexo-nome:hover {
  text-decoration: underline;
}

.feature-anexo-tamanho {
  font-size: 0.72rem;
  color: var(--muted);
}

/* O "Remover" reaproveita o botão de apagar comentário, que some até o mouse
   passar; aqui ele acende no hover da linha do anexo. */
.feature-anexo .tarefa-comentario-apagar {
  margin-left: 0;
}

.feature-anexo:hover .tarefa-comentario-apagar {
  opacity: 1;
}

.feature-detalhe-diario {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 20px 16px;
  border-top: 1px solid var(--line);
}

.feature-detalhe-diario textarea {
  width: 100%;
  min-height: 60px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  font-family: inherit;
  font-size: 0.88rem;
  line-height: 1.45;
  resize: vertical;
}

.feature-detalhe-diario textarea:focus {
  outline: none;
  border-color: var(--accent-border);
  box-shadow: var(--accent-ring);
}

#feature-detalhe[data-ocupado="sim"] .tarefa-detalhe-comentarios,
#feature-detalhe[data-ocupado="sim"] .feature-detalhe-anexos {
  opacity: 0.6;
}

#feature-detalhe[data-ocupado="sim"] .tarefa-comentario-apagar {
  pointer-events: none;
}

.feature-detalhe-rodape {
  flex-wrap: wrap;
  padding: 12px 24px;
}

.feature-detalhe-exportar {
  display: flex;
  gap: 8px;
}

.feature-detalhe-rodape .btn {
  white-space: nowrap;
}

.btn-pequeno {
  padding: 5px 12px;
  font-size: 0.78rem;
}

/* Apagar é destrutivo, mas não é a ação principal do rodapé: contorno em vez
   de fundo cheio, para não disputar o olho com "Salvar". */
.btn-danger-ghost {
  background: transparent;
  border-color: var(--danger-border);
  color: var(--danger-ink);
}

.btn-danger-ghost:hover {
  background: var(--danger-bg);
}

@media (max-width: 860px) {
  #feature-detalhe {
    width: 100vw;
    height: 100vh;
    max-height: 100vh;
    border-radius: 0;
  }

  #feature-detalhe .feature-detalhe-corpo {
    grid-template-columns: 1fr;
    overflow-y: auto;
  }

  /* Numa coluna só, quem rola é o corpo inteiro. O `min-height: 0` que deixa
     cada coluna rolar por si no desktop, aqui, deixaria as linhas do grid
     encolherem abaixo do conteúdo — e a lateral subiria por cima da spec. */
  .feature-detalhe-spec,
  .feature-detalhe-lateral,
  .feature-lateral-rolagem {
    min-height: auto;
    overflow: visible;
  }

  .feature-lateral-rolagem {
    flex: none;
  }

  .feature-detalhe-spec {
    padding: 4px 16px 16px;
  }

  /* No estreito, status e fechar sobem para uma linha própria, em cima da
     ficha: ao lado do título, eles o espremeriam. */
  #feature-detalhe .feature-detalhe-cabecalho {
    flex-wrap: wrap;
    gap: 12px;
    padding: 16px 16px 12px;
  }

  .feature-detalhe-controles {
    order: -1;
    width: 100%;
    justify-content: space-between;
  }

  .feature-detalhe-titulo {
    font-size: 1.25rem;
  }

  .feature-detalhe-lateral {
    border-left: 0;
    border-top: 1px solid var(--line);
  }

  .feature-lateral-rolagem,
  .feature-detalhe-diario {
    padding-left: 16px;
    padding-right: 16px;
  }
}
