/*
 * Heimdall — tokens de SISTEMA (Fase 2).
 *
 * Fonte normativa: .claude/rules/design-system.md
 * Registro de decisão: design/system/001-fundacao.md
 * Marca (cor, tipografia, símbolo): design/tokens/brand.css — carregue ANTES deste.
 *
 * Um sistema só cobre produto e site. A diferença entre eles não é o token,
 * é a DENSIDADE e o REGISTRO — ambos ligados por atributo no elemento raiz.
 */

/* ---------------------------------------------------------------- *
 * Tipografia
 *
 * Escala pragmática, não modular pura: os passos de UI (11-16) precisam de
 * granularidade fina que uma razão constante não dá, e os de display (24-52)
 * precisam de salto grande. Forçar uma razão só produziria tamanhos que
 * ninguém usa entre 16 e 24.
 *
 * Line-height é generoso porque PT-BR corre mais longo que EN e quebra mais.
 * ---------------------------------------------------------------- */

:root {
  --text-2xs:  0.6875rem;  /* 11px — só Mono: rótulo de coluna, tag de estado */
  --text-xs:   0.75rem;    /* 12px */
  --text-sm:   0.8125rem;  /* 13px */
  --text-base: 0.875rem;   /* 14px — corpo do PRODUTO */
  --text-md:   1rem;       /* 16px — corpo do SITE */
  --text-lg:   1.125rem;   /* 18px */
  --text-xl:   1.3125rem;  /* 21px */
  --text-2xl:  1.625rem;   /* 26px */
  --text-3xl:  2rem;       /* 32px */
  --text-4xl:  2.5rem;     /* 40px */
  --text-5xl:  3.25rem;    /* 52px */

  --leading-tight:   1.08;  /* display 32+ */
  --leading-snug:    1.22;  /* títulos 20-30 */
  --leading-normal:  1.45;  /* UI, rótulo, célula */
  --leading-relaxed: 1.6;   /* corpo de leitura */

  --tracking-display: -0.032em;  /* 32px+ */
  --tracking-tight:   -0.018em;  /* 20-30px */
  --tracking-normal:  0;
  --tracking-mono:    0.09em;    /* Mono em caixa alta */
  --tracking-label:   0.16em;    /* rótulo de seção, caixa alta */

  /* Medida de leitura. Sempre em ch, nunca em px — é o que sobrevive ao PT-BR. */
  --measure-tight: 17ch;   /* headline de hero */
  --measure-body:  52ch;   /* parágrafo */
  --measure-wide:  68ch;   /* documentação */
}

/* ---------------------------------------------------------------- *
 * Espaçamento — base 4
 * ---------------------------------------------------------------- */

:root {
  --space-0:  0;
  --space-px: 1px;
  --space-1:  0.25rem;   /*  4 */
  --space-2:  0.5rem;    /*  8 */
  --space-3:  0.75rem;   /* 12 */
  --space-4:  1rem;      /* 16 */
  --space-5:  1.25rem;   /* 20 */
  --space-6:  1.5rem;    /* 24 */
  --space-8:  2rem;      /* 32 */
  --space-10: 2.5rem;    /* 40 */
  --space-12: 3rem;      /* 48 */
  --space-16: 4rem;      /* 64 */
  --space-20: 5rem;      /* 80 */
  --space-24: 6rem;      /* 96 */
  --space-32: 8rem;      /* 128 */
}

/* ---------------------------------------------------------------- *
 * Densidade
 *
 * CONFORTÁVEL é o padrão, e isso é deliberado. Controle de 44px é o mínimo
 * de alvo de toque; se a base fosse densa, toda peça de marketing teria que
 * corrigir por exceção e uma delas esqueceria. O produto liga COMPACTO uma
 * vez, no shell, e a exceção passa a ser explícita e única.
 *
 * Compacto é para ponteiro. Nunca aplique compacto numa superfície de toque.
 *
 * --icon-size é o ícone que acompanha texto de controle: botão, erro de
 * campo, item de lista. 16 no confortável e 14 no compacto
 * (002-componentes.md, Button). É densidade, e não escala de espaço, porque
 * encolhe junto com o controle que o contém; o ícone de estado (12–14, no
 * badge) não é este token.
 * ---------------------------------------------------------------- */

:root,
[data-density="comfortable"] {
  --control-h:   2.75rem;  /* 44 */
  --control-h-sm: 2.25rem; /* 36 */
  --field-h:     2.75rem;  /* 44 */
  --row-h:       3.5rem;   /* 56 */
  --cell-px:     var(--space-4);
  --cell-py:     var(--space-3);
  --stack-gap:   var(--space-4);
  --section-py:  var(--space-16);
  --icon-size:   1rem;     /* 16 */
}

/*
 * Compacto só vale onde o ponteiro principal NÃO é grosso. Num tablet ou num
 * celular, [data-density="compact"] não declara nada, e o elemento herda o
 * confortável do :root — o Console ligou compacto no shell, e mesmo assim o
 * controle fica em 44px debaixo do dedo. É a regra "densidade não é
 * preferência" imposta no token, onde prefers-reduced-motion já é imposto:
 * nenhum componente precisa lembrar de checar.
 *
 * `not all and (pointer: coarse)` em vez de repetir os valores de confortável
 * num bloco de toque: assim só existe UMA declaração de cada densidade, e
 * nenhuma cópia pode divergir. `not all and` é a forma de Media Queries 3; um
 * browser que não conheça `pointer` fica com o compacto, que é o que ele já
 * tinha.
 */
@media not all and (pointer: coarse) {
  [data-density="compact"] {
    --control-h:   2rem;     /* 32 */
    --control-h-sm: 1.75rem; /* 28 */
    --field-h:     2rem;     /* 32 */
    --row-h:       2.5rem;   /* 40 */
    --cell-px:     var(--space-2);
    --cell-py:     var(--space-1);
    --stack-gap:   var(--space-3);
    --section-py:  var(--space-8);
    --icon-size:   0.875rem; /* 14 */
  }
}

/* ---------------------------------------------------------------- *
 * Raio
 *
 * O canto reto é a decisão, não a ausência de uma. O símbolo é círculo e reta;
 * a marca é instrumento de precisão. Canto arredondado em cartão e botão é o
 * default da categoria e amolece exatamente o que a marca afirma.
 *
 * --radius-xs existe só onde o canto reto serrilha em tamanho pequeno.
 * ---------------------------------------------------------------- */

:root {
  --radius-none: 0;         /* botão, input, card, badge, tabela — o padrão */
  --radius-xs:   3px;       /* chip < 20px de altura, thumbnail */
  --radius-full: 9999px;    /* avatar, spinner, pill de contagem */
}

/* ---------------------------------------------------------------- *
 * Elevação
 *
 * A borda carrega a elevação; a sombra só entra quando algo flutua de verdade
 * sobre o conteúdo. Cartão NÃO tem sombra — tem borda.
 * ---------------------------------------------------------------- */

:root {
  --shadow-none:    none;
  --shadow-raised:  0 1px 2px oklch(0 0 0 / 0.06), 0 2px 6px oklch(0 0 0 / 0.05);
  --shadow-overlay: 0 4px 12px oklch(0 0 0 / 0.10), 0 12px 32px oklch(0 0 0 / 0.09);
}

[data-register="dark"] {
  --shadow-raised:  0 1px 2px oklch(0 0 0 / 0.34), 0 2px 6px oklch(0 0 0 / 0.28);
  --shadow-overlay: 0 4px 12px oklch(0 0 0 / 0.44), 0 12px 32px oklch(0 0 0 / 0.38);
}

/*
 * Véu: o fundo atrás de dialog e sheet. Declarado POR REGISTRO, nunca só no
 * :root — um valor único vazaria o do claro para o escuro sem ninguém ver.
 *
 * Claro: a tinta a 40%. Escuro: PRETO a 60%, da família das sombras acima, e
 * não a --ink do escuro — ela é clara (0.930), e a 60% clarearia o Console
 * inteiro para um cinza médio a cada dialog aberto.
 */
:root,
[data-register="light"] {
  --backdrop: oklch(0.229 0.006 100 / 0.40);
}

[data-register="dark"] {
  --backdrop: oklch(0 0 0 / 0.60);
}

/* ---------------------------------------------------------------- *
 * Traço
 *
 * Duas espessuras, e só duas. A fina é a borda: é ela que carrega a
 * elevação, separa linha de tabela e desenha o cartão. A forte é o que
 * MARCA: o anel de foco, a barra do item ativo da sidebar, o sublinhado da
 * aba ativa. Uma terceira espessura seria uma terceira hierarquia que
 * ninguém consegue ler.
 *
 * Em px, não em rem: um traço de 0.0625rem sob uma fonte base de 18px vira
 * 1.125px, e o browser o desenha borrado ou some com ele.
 * ---------------------------------------------------------------- */

:root {
  --stroke-hairline: 1px;   /* borda, separador, linha de tabela            */
  --stroke-strong:   2px;   /* anel de foco, item ativo, aba ativa          */
}

/* ---------------------------------------------------------------- *
 * Camadas
 *
 * O que fica por cima do quê, em cinco degraus:
 *
 *   conteúdo  a página
 *   sticky    o cabeçalho que gruda no topo (PageHeader)
 *   overlay   véu, dialog, sheet
 *   raised    dropdown, popover, tooltip, select
 *   toast     por cima de tudo
 *
 * O toast fica no topo porque confirma o que ACABOU de acontecer, e não pode
 * sumir atrás do dialog que o disparou.
 *
 * `raised` fica ACIMA de `overlay`, e não abaixo. Um select, um popover ou um
 * tooltip abertos DENTRO de um dialog ou de um sheet são portados para o fim
 * do <body>, fora do dialog; com `raised` abaixo de `overlay`, eles abririam
 * atrás do próprio dialog que os contém. O inverso não acontece: com um
 * dialog modal aberto, a página atrás é inerte, e nada nela abre um popover.
 *
 * `sticky` fica acima do conteúdo e abaixo de tudo que flutua (spec 32.7,
 * Task 6). Acima do conteúdo porque um descendente posicionado mais adiante
 * na página — um cartão `relative`, o alvo esticado de uma lista — pinta por
 * cima de um cabeçalho que está no mesmo degrau. Abaixo do overlay porque o
 * véu de um dialog cobre a página inteira, cabeçalho incluso.
 *
 * Os números têm folga de 10 para que uma peça futura caiba entre dois
 * degraus sem renumerar os outros. Nenhum componente escreve um número.
 * ---------------------------------------------------------------- */

:root {
  --layer-content: 0;
  --layer-sticky:  5;
  --layer-overlay: 10;
  --layer-raised:  20;
  --layer-toast:   30;
}

/* ---------------------------------------------------------------- *
 * Peças com medida própria
 *
 * Largura de peça que não é texto, e por isso não é medida em ch. Os
 * valores são os da vitrine (design/artifacts.md), README de cada peça.
 *
 * Sidebar: 240 fixos, colapsável para 56 — o ícone de navegação, o
 * marcador de 2px e o respiro dos dois lados.
 *
 * Sheet: entre 420 e 560, nunca a tela inteira no desktop — ver a lista
 * atrás é o ponto do sheet. Em toque vira folha de baixo para cima, até 90%
 * da altura visível (dvh, que desconta a barra do navegador móvel).
 *
 * Página: a largura máxima da coluna de conteúdo do site (nav, seções,
 * rodapé), 1200, a do canvas aprovado em 2026-10-10. Nasceu na spec 58
 * (docs/specs/institutional-site.md), para o site; o Console não a usa, a
 * largura dele é a da janela menos a sidebar. É o teto da coluna, não uma
 * largura de texto: o parágrafo continua limitado por --measure-body.
 * ---------------------------------------------------------------- */

:root {
  --sidebar-w:           15rem;     /* 240 */
  --sidebar-w-collapsed: 3.5rem;    /*  56 */
  --sheet-w-min:         26.25rem;  /* 420 */
  --sheet-w-max:         35rem;     /* 560 */
  --sheet-h-max-touch:   90dvh;
  --page-w-max:          75rem;     /* 1200 */
}

/* ---------------------------------------------------------------- *
 * Movimento
 *
 * Rápido e sem elástico. Um console lido por oito horas não pode ter animação
 * com personalidade — ela vira ruído na décima repetição.
 * ---------------------------------------------------------------- */

:root {
  --ease:        cubic-bezier(0.2, 0, 0, 1);
  --ease-out:    cubic-bezier(0, 0, 0, 1);
  --duration-instant: 90ms;   /* hover, foco */
  --duration-fast:    140ms;  /* troca de estado, expandir */
  --duration-base:    200ms;  /* entrada de popover, toast */
  --duration-slow:    280ms;  /* dialog, sheet */

  /*
   * Ciclo, não transição: uma volta inteira do ícone de estado em curso
   * (provisioning, updating, deprovisioning) e do spinner. Os keyframes e o
   * easing linear ficam no pacote que desenha o ícone; aqui fica só o tempo.
   *
   * 1s por volta: 6° por quadro a 60 Hz, que lê como giro contínuo e não como
   * passo. Mais rápido que isso, várias linhas em curso numa tabela viram
   * ruído na visão periférica de quem lê o Console por um turno inteiro.
   */
  --duration-spin:    1000ms;

  /*
   * Ciclo da pulsação do skeleton: a opacidade vai de 1 a --pulse-opacity e
   * volta, uma vez a cada 1.6s. Lenta de propósito — o skeleton só diz "está
   * vindo", e pulsação rápida lê como alarme. Ciclo e amplitude são os da
   * vitrine (Skeleton). Não é --duration-slow: 280ms por ciclo piscaria três
   * vezes e meia por segundo.
   */
  --duration-pulse:   1600ms;
  --pulse-opacity:    0.55;
}

/*
 * As transições vão a 1ms, não a 0: um evento transitionend continua
 * disparando, e há código que espera por ele.
 *
 * A rotação vai a 0s, e NÃO a 1ms. Uma animação infinita com período de 1ms
 * amostrada a 60 Hz cai num ângulo arbitrário a cada quadro: o ícone treme em
 * vez de parar, que é pior para quem pediu menos movimento do que a rotação
 * original. Com 0s a animação não tem duração ativa e o ícone fica parado na
 * posição de repouso. O estado continua legível, porque ícone e nome o
 * carregam; a rotação nunca foi o único sinal.
 *
 * A pulsação do skeleton vai a 0s pela mesma razão: alternar opacidade com
 * período de 1ms é um pisca-pisca. Parada, a barra fica em opacidade cheia.
 */
@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-instant: 1ms;
    --duration-fast:    1ms;
    --duration-base:    1ms;
    --duration-slow:    1ms;
    --duration-spin:    0s;
    --duration-pulse:   0s;
  }
}

/* ---------------------------------------------------------------- *
 * Estado
 *
 * Gerados a partir de oklch com o contraste resolvido numericamente. Pior par
 * do conjunto: 5.49:1, contra o mínimo de 4.5:1.
 *
 * A matiz 162 da marca NÃO aparece aqui, e isso é verificado por asserção.
 * Estado usa SUPERFÍCIE TINGIDA + texto + borda; nunca fill sólido — é o que
 * o separa da marca antes de qualquer diferença de matiz.
 *
 * Pares intencionalmente idênticos, porque ícone e nome já os separam:
 *   approved = provisioned                      (145)
 *   rejected = failed                           (27)
 *   provisioning = updating = deprovisioning    (235)
 * Não "conserte" isso dando matiz própria a cada um: catorze matizes numa
 * tabela é ruído, e a distinção que o usuário lê é o nome.
 * ---------------------------------------------------------------- */

:root,
[data-register="light"] {
  --state-draft-surface: #f1f0ec;
  --state-draft-ink:     #5f5e57;   /* 5.71:1 */
  --state-draft-border:  #dbd9d0;
  --state-pending-approval-surface: #fceedb;
  --state-pending-approval-ink:     #805300;   /* 5.83:1 */
  --state-pending-approval-border:  #f3d4a9;
  --state-approved-surface: #e5f6e5;
  --state-approved-ink:     #356c38;   /* 5.56:1 */
  --state-approved-border:  #c1e5c1;
  --state-rejected-surface: #ffe9e5;
  --state-rejected-ink:     #9b3731;   /* 6.04:1 */
  --state-rejected-border:  #ffc9c2;
  --state-provisioning-surface: #dff4ff;
  --state-provisioning-ink:     #13658b;   /* 5.68:1 */
  --state-provisioning-border:  #b2e0fc;
  --state-provisioned-surface: #e5f6e5;
  --state-provisioned-ink:     #356c38;   /* 5.56:1 */
  --state-provisioned-border:  #c1e5c1;
  --state-failed-surface: #ffe9e5;
  --state-failed-ink:     #9b3731;   /* 6.04:1 */
  --state-failed-border:  #ffc9c2;
  --state-updating-surface: #dff4ff;
  --state-updating-ink:     #13658b;   /* 5.68:1 */
  --state-updating-border:  #b2e0fc;
  --state-deprovisioning-surface: #dff4ff;
  --state-deprovisioning-ink:     #13658b;   /* 5.68:1 */
  --state-deprovisioning-border:  #b2e0fc;
  --state-deprovisioned-surface: #f1f0ec;
  --state-deprovisioned-ink:     #5f5e57;   /* 5.71:1 */
  --state-deprovisioned-border:  #dbd9d0;
  --state-sensitivity-low-surface: #f1f0ec;
  --state-sensitivity-low-ink:     #5f5e57;   /* 5.71:1 */
  --state-sensitivity-low-border:  #dbd9d0;
  --state-sensitivity-medium-surface: #fceedb;
  --state-sensitivity-medium-ink:     #805300;   /* 5.83:1 */
  --state-sensitivity-medium-border:  #f3d4a9;
  --state-sensitivity-high-surface: #ffeae0;
  --state-sensitivity-high-ink:     #954114;   /* 5.95:1 */
  --state-sensitivity-high-border:  #ffccb6;
  --state-sensitivity-critical-surface: #ffe8e9;
  --state-sensitivity-critical-ink:     #9d3343;   /* 6.01:1 */
  --state-sensitivity-critical-border:  #ffc7ca;
}

[data-register="dark"] {
  --state-draft-surface: #262520;
  --state-draft-ink:     #a09f98;   /* 5.78:1 */
  --state-draft-border:  #3f3d33;
  --state-pending-approval-surface: #332106;
  --state-pending-approval-ink:     #c5954f;   /* 5.72:1 */
  --state-pending-approval-border:  #583400;
  --state-approved-surface: #162b17;
  --state-approved-ink:     #76af77;   /* 5.87:1 */
  --state-approved-border:  #1c481f;
  --state-rejected-surface: #391b18;
  --state-rejected-ink:     #e67b70;   /* 5.53:1 */
  --state-rejected-border:  #642722;
  --state-provisioning-surface: #0b2838;
  --state-provisioning-ink:     #5fa8d1;   /* 5.82:1 */
  --state-provisioning-border:  #004362;
  --state-provisioned-surface: #162b17;
  --state-provisioned-ink:     #76af77;   /* 5.87:1 */
  --state-provisioned-border:  #1c481f;
  --state-failed-surface: #391b18;
  --state-failed-ink:     #e67b70;   /* 5.53:1 */
  --state-failed-border:  #642722;
  --state-updating-surface: #0b2838;
  --state-updating-ink:     #5fa8d1;   /* 5.82:1 */
  --state-updating-border:  #004362;
  --state-deprovisioning-surface: #0b2838;
  --state-deprovisioning-ink:     #5fa8d1;   /* 5.82:1 */
  --state-deprovisioning-border:  #004362;
  --state-deprovisioned-surface: #262520;
  --state-deprovisioned-ink:     #a09f98;   /* 5.78:1 */
  --state-deprovisioned-border:  #3f3d33;
  --state-sensitivity-low-surface: #262520;
  --state-sensitivity-low-ink:     #a09f98;   /* 5.78:1 */
  --state-sensitivity-low-border:  #3f3d33;
  --state-sensitivity-medium-surface: #332106;
  --state-sensitivity-medium-ink:     #c5954f;   /* 5.72:1 */
  --state-sensitivity-medium-border:  #583400;
  --state-sensitivity-high-surface: #381d10;
  --state-sensitivity-high-ink:     #de845a;   /* 5.59:1 */
  --state-sensitivity-high-border:  #622b0d;
  --state-sensitivity-critical-surface: #3a1a1d;
  --state-sensitivity-critical-ink:     #e87782;   /* 5.49:1 */
  --state-sensitivity-critical-border:  #66232c;
}

/* ---------------------------------------------------------------- *
 * Gráfico
 *
 * A TERCEIRA classe de cor, e a separação entre as três é estrutural antes
 * de ser cromática:
 *
 *   marca    → fill sólido                          matiz 162, reservada
 *   estado   → superfície tingida + texto + ícone    145 · 75 · 27 · 235 · 100
 *   gráfico  → marca de dado sólida, com legenda     250 · 35 · 300 · 195 · 80
 *
 * design/system/002-componentes.md deixou gráfico explicitamente em aberto,
 * e registrou o motivo: as matizes de estado NÃO servem como paleta
 * categórica de série. Esta seção fecha a lacuna. O raciocínio está em
 * design/system/003-graficos.md.
 *
 * CINCO séries, em ORDEM FIXA, nunca ciclada. Não é escolha estética: cinco
 * é o maior conjunto que passa em TODOS os pares — não só nos adjacentes —
 * sob protanopia, deuteranopia e tritanopia, nos dois registros. Com seis, o
 * par ocre/terracota cai para ΔE 3.3 sob deuteranopia, e são duas séries que
 * o leitor não separa. A sexta série vira `Outros`, small multiples ou
 * encoding composto — nunca uma matiz gerada na hora.
 *
 * Nenhuma matiz de série encosta na marca: todas a ≥25° de 162. Não há verde
 * na paleta, e isso é deliberado — verde é da marca.
 *
 * A cor segue a ENTIDADE, nunca o rank. Um filtro que muda a contagem de
 * séries não pode repintar as sobreviventes.
 *
 * Gerados de oklch e medidos por design/tokens/verify-contrast.mjs, que
 * roda a simulação de Machado-Oliveira-Fernandes sobre TODO par.
 * ---------------------------------------------------------------- */

:root,
[data-register="light"] {
  /* categórica — identidade. Ordem fixa. */
  --chart-1: #1d5b92;   /* azul aço   L .46 C .11 H 250 */
  --chart-2: #914330;   /* terracota  L .48 C .11 H  35 */
  --chart-3: #8962c5;   /* violeta    L .58 C .15 H 300 */
  --chart-4: #02a0a1;   /* teal       L .64 C .15 H 195 */
  --chart-5: #a77601;   /* ocre       L .60 C .13 H  80 */

  /* sequencial — magnitude. Matiz única, L monotônico. */
  --chart-seq-1: #8db5e0;
  --chart-seq-2: #689ed5;
  --chart-seq-3: #4887c5;
  --chart-seq-4: #2d70b0;
  --chart-seq-5: #1d5b92;

  /* divergente — polaridade. O meio é CINZA, nunca uma matiz. */
  --chart-diverging-neg-2: #1d5b92;
  --chart-diverging-neg-1: #668aaf;
  --chart-diverging-mid:   #d2d1cb;
  --chart-diverging-pos-1: #ac776a;
  --chart-diverging-pos-2: #914330;

  /* recessivos: nunca mais fortes que a marca de dado */
  --chart-grid: #e3dfd7;
  --chart-axis: #bbb7ae;
}

[data-register="dark"] {
  --chart-1: #316ca5;
  --chart-2: #a45541;
  --chart-3: #9b74d9;
  --chart-4: #05a7a7;
  --chart-5: #bb881a;

  --chart-seq-1: #385b7e;
  --chart-seq-2: #4172a4;
  --chart-seq-3: #4b8ac9;
  --chart-seq-4: #61a3e6;
  --chart-seq-5: #85bcf5;

  --chart-diverging-neg-2: #85bcf5;
  --chart-diverging-neg-1: #6b90b6;
  --chart-diverging-mid:   #494843;
  --chart-diverging-pos-1: #b27d6f;
  --chart-diverging-pos-2: #f0a08c;

  --chart-grid: #272722;
  --chart-axis: #43433d;
}
