/* ==========================================================================
   NEXUS theme-final / 07-studio.css
   Layout do gatilho e do painel do Estúdio de Tema.
   Só consome tokens de 01-tokens.css: nenhum hex, nenhum raio em px,
   nenhuma família de fonte literal. Paleta preto e branco enterprise:
   toda decoração é luz branca de baixa opacidade ou --signal.

   Decisão de superfície (medida, não opinada):
   sobre --card, --surface-2 e --surface-3 o token --muted-foreground fica
   mais apertado do que sobre --background em paletas derivadas. Por isso o
   corpo do painel, onde vivem texto secundário e borda de controle, fica
   sobre --background. Cabeçalho, barra de navegação e rodapé usam
   --surface-2 e só carregam texto em --foreground.

   Índice:
    1. Gatilho fixo
    2. Não existe mais backdrop (e o que caiu junto com ele)
    3. Painel e chassi de rolagem
    4. Índice lateral vertical e as abas
    5. Subgrupo colapsável
    6. Campos
    7. Segmented
    8. Swatches de preset
    9. Indicador de contraste
   10. Campo de cor
   11. Botões
   12. Famílias tipográficas
   13. Slider
   14. Chips: o painel consome .chip de 03-ui.css
   15. Switch
   16. Exportar, importar e status
   16.1 Controles novos: select, parâmetros, selos, presets, amostra
   17. Mobile, alvo de toque e impressão
   18. Ponto de consumo dos eixos variáveis de peso
   19. O que o estúdio passa a governar NA PÁGINA (atrás de portão)
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Gatilho fixo no canto inferior direito
   -------------------------------------------------------------------------- */

.nx-studio-trigger {
  position: fixed;
  inset-block-end: var(--space-6);
  inset-inline-end: var(--space-6);
  z-index: 980;

  display: inline-flex;
  align-items: center;
  justify-content: center;

  inline-size: 3.25rem;
  block-size: 3.25rem;
  min-inline-size: var(--tap-min);
  min-block-size: var(--tap-min);

  color: hsl(var(--primary-foreground));
  background-color: hsl(var(--primary));
  border: var(--hairline) solid hsl(var(--primary));
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-md);

  transition:
    transform calc(var(--dur-fast) * var(--motion)) var(--ease-out),
    opacity calc(var(--dur-fast) * var(--motion)) var(--ease-out),
    background-color calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.nx-studio-trigger:hover {
  transform: translateY(-2px);
}

.nx-studio-trigger:active {
  transform: translateY(0);
}

/* Recuado: em tela estreita, enquanto a dobra ainda está em vista, o gatilho
   sai de cena para não cobrir o quadro de mídia do hero. studio.js escreve
   data-recuado; só transform e opacity animam (§6) e o botão sai do fluxo
   de foco enquanto está fora da tela. */
.nx-studio-trigger[data-recuado="true"] {
  transform: translateY(calc(100% + var(--space-6)));
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   2. NÃO EXISTE MAIS BACKDROP

   Decisão do dono, agosto de 2026: "ao clicar no widget não deve esmaecer o
   fundo, eu quero ver na hora já mudando e não ficar esmaecido,
   desnecessário".

   O véu tinha uma razão de ser quando o painel era um DIÁLOGO: ele recuava a
   página, prendia o olho e justificava `aria-modal`. Só que este painel não
   pede atenção exclusiva, ele EDITA o que está atrás: escurecer a página com
   42% de tinta enquanto o dono mexe no raio dos cartões esconde exatamente a
   coisa que ele está tentando ver, e ainda por cima falseia o contraste do
   que ele está julgando a olho.

   O que cai junto, e é por isso que a remoção não é cosmética:
   `role="dialog"`, `aria-modal="true"` e o foco preso. Painel que convive
   com a página não pode capturar o Tab, senão o teclado deixa de alcançar
   justamente o botão que está sendo editado. O que FICA: `Esc` fecha e
   devolve o foco ao gatilho, o painel tem rótulo próprio, e ele é
   `inert` enquanto fechado. Ver o cabeçalho de studio.js.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   3. Painel
   Quatro faixas: cabeçalho, índice lateral mais conteúdo, e rodapé.
   Só o conteúdo da aba ativa rola, e a rolagem é confinada
   (overscroll-behavior: contain), senão o scroll vaza para a página atrás em
   telas curtas.

   NADA ROLA NA HORIZONTAL, em lugar nenhum do painel. Era o segundo defeito
   de uso relatado: "ele está com barra de rolamento lateral etc, faz algo
   mais utilizável". A barra de grupos era `overflow-x: auto` com sete botões
   em fila; virou um índice VERTICAL de ícones, e os grupos deixaram de ser
   sete acordeões empilhados para virar abas: só o conteúdo da aba escolhida
   existe na tela, e ele rola em um eixo só.
   -------------------------------------------------------------------------- */

.nx-studio {
  position: fixed;
  inset-block: 0;
  inset-inline-end: 0;
  z-index: 1000;

  display: flex;
  flex-direction: column;

  /* Cresce com a tela: 380px no notebook, até 600px em 4K. Mais largo que a
     versão anterior porque agora perde uma coluna para o índice lateral, e a
     conta é essa: em 1440 o painel mede 446px, o índice sem rótulo mede 56px
     e sobram 390px para o controle, que é mais do que os 340px da versão de
     um acordeão só. */
  inline-size: clamp(380px, 31vw, 600px);
  max-inline-size: 100vw;
  block-size: 100svh;

  color: hsl(var(--foreground));
  background-color: hsl(var(--background));
  border-inline-start: var(--hairline) solid hsl(var(--border));
  box-shadow: var(--shadow-lg);

  visibility: hidden;
  transform: translateX(101%);
  transition:
    transform calc(var(--dur-base) * var(--motion)) var(--ease-out),
    visibility 0s linear calc(var(--dur-base) * var(--motion));
}

.nx-studio[data-open="true"] {
  visibility: visible;
  transform: translateX(0);
  transition:
    transform calc(var(--dur-base) * var(--motion)) var(--ease-out),
    visibility 0s linear 0s;
}

.nx-studio__head,
.nx-studio__foot {
  flex: none;
  background-color: hsl(var(--surface-2));
}

/* Corpo do painel: índice à esquerda, aba à direita. */
.nx-studio__shell {
  flex: 1 1 auto;
  min-block-size: 0;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
}

/* CABEÇALHO EM DUAS LINHAS, EM TODA LARGURA (revisão de 6 de agosto de 2026).

   O que havia era `display: flex` com quatro filhos numa linha só, e a meta
   entre o título e os dois botões de ícone. Medido no browserless, em 1440
   com o painel aberto: `.nx-studio__meta` fechava em **clientWidth 0** contra
   scrollWidth 180, ou seja, o texto "Padrão · claro · sistema" não existia na
   tela em NENHUMA largura. A conta explica: o painel mede 446px em 1440, sobram
   414px de conteúdo, o título come 255, os dois botões 88 e os vãos 36 — não
   restava pixel para a meta, e `.nx-studio__id { flex: none }` garantia que
   quem cedesse fosse ela.

   Isso contraria o §11 do contrato, que pede a meta "sempre visível: o dono
   precisa saber o que está editando sem rolar até o topo do grupo", e era o
   mesmo defeito que o dono viu no mobile, só que ali com o título espremido
   por cima. Uma linha para cada coisa resolve os dois de uma vez, com o mesmo
   desenho nas duas pontas da matriz: linha 1 com a identidade e os botões,
   linha 2 com a meta inteira, alinhada ao início. */
.nx-studio__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  grid-template-rows: auto auto;
  align-items: center;
  column-gap: var(--space-3);
  row-gap: var(--space-1);
  padding: var(--space-3) var(--space-5);
  border-block-end: var(--hairline) solid hsl(var(--border));
}

.nx-studio__id {
  grid-column: 1;
  grid-row: 1;
  min-inline-size: 0;
}

.nx-studio__eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  font-weight: 500;
  line-height: 1;
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  /* --faint-foreground, nao alfa sobre --foreground (§2.5). Passava com folga
     (7,63:1), mas e a mesma regra dos dois defeitos desta rodada, com um
     terceiro token. O painel roda sobre as tres peles e sobre qualquer padrao
     de fundo que o proprio painel liga: alfa aqui e aposta sobre um fundo que
     o usuario controla. */
  color: hsl(var(--faint-foreground));
}

.nx-studio__title {
  font-size: var(--fs-h3);
  line-height: var(--lh-tight);
  margin-block-start: var(--space-1);
}

/* Pele e modo em vigor, sempre visíveis: o painel é grande e o dono precisa
   saber o que está editando sem rolar até o topo do grupo. */
.nx-studio__meta {
  grid-column: 1 / -1;
  grid-row: 2;
  min-inline-size: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--tracking-mono);
  color: hsl(var(--muted-foreground));
}

/* --------------------------------------------------------------------------
   3.1 Faixa de rascunho guardado

   Acrescentada em 6 de agosto de 2026, junto da regra "o painel abre no
   publicado, sempre" (§15.4.4 do contrato). O painel deixou de reaplicar
   rascunho não publicado numa recarga, e esta faixa é a rede de segurança: o
   rascunho não foi jogado fora, e aqui o dono escolhe recuperar ou descartar.

   Ela é irmã do cabeçalho, e não filha do corpo, porque a decisão vale para o
   painel inteiro: dentro do corpo ela rolaria para fora da tela e ficaria
   invisível justamente na aba em que o dono estava mexendo.

   O peso visual é o de uma OFERTA, não o de um erro: fundo `--surface-2`, o
   mesmo do cabeçalho, e uma barra fina de `--signal` na borda de início, que é
   como o painel marca "isto merece um olhar" desde a §16.1a. Sem caixa, sem
   ícone grande e sem cor de fundo cromática — o estado do painel já está
   correto com ou sem esta faixa, e gritar aqui seria mentir sobre a urgência.
   -------------------------------------------------------------------------- */
/* Frase em cima, ações embaixo. Não é preferência: é a MESMA forma do `.nx-volta`
   da §16.1a, que já resolve "um texto que explica mais um botão que age" dentro
   deste painel, e usar outra aqui seria uma segunda política visual para o mesmo
   problema. Medido antes de fixar: com o texto ao lado dos dois botões, a coluna
   de frase fechava em cerca de 200px dentro do painel de 446px e a mesma frase
   ocupava QUATRO linhas; empilhada ela cabe em duas, com a mesma altura total e
   sem a aparência de aperto. */
.nx-aviso {
  flex: none;
  display: grid;
  gap: var(--space-2);
  justify-items: start;
  padding: var(--space-3) var(--space-5);
  background-color: hsl(var(--surface-2));
  border-block-end: var(--hairline) solid hsl(var(--border));
  border-inline-start: 0.1875rem solid hsl(var(--signal));
}

.nx-aviso__txt {
  max-inline-size: 60ch;
  font-size: var(--fs-xs);
  line-height: var(--lh-body);
  color: hsl(var(--foreground));
}

.nx-aviso__acoes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.nx-studio__body {
  min-inline-size: 0;
  overflow-y: auto;
  overflow-x: hidden;            /* invariante: nada rola na horizontal */
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  scroll-behavior: smooth;
  padding: var(--space-4) var(--space-5) var(--space-8);
  scrollbar-width: thin;         /* mesma barra discreta do índice (§4) */
}

/* Barra fina em Firefox já vem de `scrollbar-width: thin`. WebKit/Blink
   precisam do pseudo-elemento; tokens do tema, nunca cor fixa, e o polegar
   só aparece com tinta no hover — discreto em repouso, achável ao passar o
   mouse (§7, micro do pedido do dono). */
.nx-studio__body::-webkit-scrollbar,
.nx-studio__rail::-webkit-scrollbar {
  inline-size: 0.5rem;
}

.nx-studio__body::-webkit-scrollbar-track,
.nx-studio__rail::-webkit-scrollbar-track {
  background-color: transparent;
}

.nx-studio__body::-webkit-scrollbar-thumb,
.nx-studio__rail::-webkit-scrollbar-thumb {
  background-color: hsl(var(--border));
  border-radius: var(--radius-full);
}

.nx-studio__body::-webkit-scrollbar-thumb:hover,
.nx-studio__rail::-webkit-scrollbar-thumb:hover {
  background-color: hsl(var(--input));
}

.nx-studio__foot {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-5) var(--space-4);
  border-block-start: var(--hairline) solid hsl(var(--border));
}

/* --------------------------------------------------------------------------
   4. Índice lateral, vertical, e as abas

   Quatorze grupos não cabem em fila. O índice é uma coluna de ícones à
   esquerda do conteúdo, com `overflow-y: auto` e ZERO rolagem horizontal; o
   rótulo aparece no `title` e no `aria-label`, e volta como texto quando o
   painel é largo o bastante para caber.

   `role="tablist"` de verdade: setas navegam, Home e End vão às pontas, e só
   o painel ativo existe no DOM visível, então a lista de foco nunca contém
   um controle que o dono não está vendo.
   -------------------------------------------------------------------------- */

.nx-studio__rail {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-2);
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  background-color: hsl(var(--surface-2));
  border-inline-end: var(--hairline) solid hsl(var(--border));
}

.nx-rail__btn {
  display: flex;
  flex: none;
  align-items: center;
  /* Ícone sozinho (abaixo de 1700px, ver §4 embaixo) fica centralizado na
     coluna; com rótulo, os dois passam a colar à esquerda (ver media query
     abaixo), que é o alinhamento de leitura correto para texto. */
  justify-content: center;
  gap: var(--space-2);

  padding: var(--space-2);
  min-block-size: 2.5rem;
  min-inline-size: 2.5rem;

  font-size: var(--fs-xs);
  font-weight: 550;
  white-space: nowrap;
  text-align: start;
  cursor: pointer;

  color: hsl(var(--muted-foreground));
  background-color: transparent;
  border: var(--hairline) solid transparent;
  border-radius: var(--radius-sm);

  transition:
    background-color calc(var(--dur-fast) * var(--motion)) var(--ease-out),
    border-color calc(var(--dur-fast) * var(--motion)) var(--ease-out),
    color calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.nx-rail__icon {
  display: inline-flex;
  flex: none;
  font-size: 1.125rem;
}

/* O rótulo só entra quando o painel tem largura sobrando. Abaixo disso fica
   o ícone, com o nome no title e no aria-label: nunca uma barra que rola. */
.nx-rail__txt {
  display: none;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 1700px de viewport é onde o painel passa de 520px: abaixo disso o rótulo
   custa 84px de coluna que o controle precisa mais do que o índice. Medido:
   com rótulo em 1440 o conteúdo caía para 232px e a lista de famílias
   tipográficas estourava a caixa. */
@media (min-width: 1700px) {
  .nx-rail__txt { display: inline; }
  .nx-rail__btn { min-inline-size: 7.5rem; justify-content: flex-start; }
}

.nx-rail__btn:hover {
  color: hsl(var(--foreground));
  background-color: hsl(var(--accent));
  border-color: hsl(var(--border));
}

.nx-rail__btn[aria-selected="true"] {
  color: hsl(var(--primary-foreground));
  background-color: hsl(var(--primary));
  border-color: hsl(var(--primary));
}

/* Ponto de mudança: o grupo saiu do padrão de fábrica. Fundo, nunca tinta de
   glifo (§2.5): é uma marca, não um texto. */
.nx-rail__btn[data-sujo="true"]::after {
  content: "";
  flex: none;
  margin-inline-start: auto;
  inline-size: 0.375rem;
  block-size: 0.375rem;
  border-radius: var(--radius-full);
  background-color: hsl(var(--signal));
}

.nx-rail__btn[aria-selected="true"][data-sujo="true"]::after {
  background-color: hsl(var(--primary-foreground));
}

/* Micro-separadores por natureza, direto nos valores de data-goto que
   railHTML() (studio.js) já escreve — nenhuma mudança de JS: aparência
   (pele, cor, tipografia, forma, fundo) | composição (menu, botões, ícones,
   seções, títulos) | movimento (motion, efeitos) | dados (presets, ações).
   Regra passada em 5 de agosto de 2026, junto do resto desta rodada de
   design do estúdio. */
/* Revisão de 6 de agosto de 2026, pedido do dono: a borda superior no
   PRÓPRIO botão lia como "uns botões com borda e outros sem". O grupo passa
   a se expressar só por respiro maior entre blocos, e cada item do rail tem
   cara de botão consistente (o pill de hover/ativo já existe na regra base).
   Nenhuma linha órfã. */
.nx-rail__btn[data-goto="menu"],
.nx-rail__btn[data-goto="motion"],
.nx-rail__btn[data-goto="presets"] {
  margin-block-start: calc(var(--space-3) + var(--space-1));
}

/* --------------------------------------------------------------------------
   4a. Índice do mobile: um menu com os NOMES dos grupos

   Pedido do dono, 6 de agosto de 2026: "poderia mudar o menu que está no topo,
   poderia virar um outro ícone que abre todas as opções, mas o menu em si
   dentro dele poderia ser as opções tipo pele, cor, fonte etc, para não ficar
   aquela barra enorme à toa, mas só no modo mobile; no desktop pode manter
   daquele jeito".

   NO DESKTOP ESTE BLOCO NÃO EXISTE NA TELA. `display: none` aqui não é um
   painel escondido (aquilo é proibido pelo §15.3 e vale para o estúdio inteiro
   fora do /admin-cli): é um SEGUNDO índice para a mesma coisa, e ter os dois
   ao mesmo tempo daria dois caminhos de teclado e dois pontos de foco para uma
   navegação só. Quem some no mobile é a coluna de ícones; quem some no desktop
   é este menu. Nunca os dois, nunca nenhum.
   -------------------------------------------------------------------------- */

.nx-abas {
  display: none;
  position: relative;
}

.nx-abas__btn {
  display: flex;
  inline-size: 100%;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  min-block-size: var(--tap-min);

  font-size: var(--fs-sm);
  font-weight: 550;
  text-align: start;
  cursor: pointer;

  color: hsl(var(--foreground));
  background-color: hsl(var(--background));
  border: var(--hairline) solid hsl(var(--border));
  border-radius: var(--radius-sm);

  transition:
    background-color calc(var(--dur-fast) * var(--motion)) var(--ease-out),
    border-color calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.nx-abas__btn:hover {
  background-color: hsl(var(--accent));
  border-color: hsl(var(--input));
}

.nx-abas__ico {
  display: inline-flex;
  flex: none;
  font-size: 1.125rem;
  color: hsl(var(--muted-foreground));
}

.nx-abas__atual {
  flex: 1 1 auto;
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nx-abas__seta {
  display: inline-flex;
  flex: none;
  color: hsl(var(--muted-foreground));
  transition: transform calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.nx-abas__btn[aria-expanded="true"] .nx-abas__seta {
  transform: rotate(180deg);
}

/* A lista flutua sobre o conteúdo em vez de empurrá-lo: numa folha de 88svh,
   catorze linhas empurrando o corpo tirariam da tela o controle que o dono
   acabou de abrir o menu para alcançar. Rolagem própria, com teto, e o
   `data-lenis-prevent` do JS impede a rolagem global de sequestrar a roda. */
.nx-abas__lista {
  position: absolute;
  inset-block-start: calc(100% + var(--space-1));
  inset-inline: 0;
  /* Acima do corpo E do rodapé do painel, que vêm depois no DOM e têm fundo
     próprio: um menu com o fim escondido atrás do rodapé é um menu com abas
     inalcançáveis. */
  z-index: 5;

  display: grid;
  gap: 0.125rem;
  /* Cabe DENTRO do corpo do painel, e não em cima do rodapé. Medido em 390x844:
     a folha tem 88svh, o menu começa a cerca de 275px e o rodapé fixo mora nos
     últimos 80px; com 60svh (506px) a lista terminava embaixo do rodapé e as
     duas últimas abas ficavam inalcançáveis sem rolar às cegas. 44svh cabe na
     área do corpo em retrato e continua rolando por conta própria quando não
     cabe. */
  max-block-size: 44svh;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-2);

  background-color: hsl(var(--surface-2));
  border: var(--hairline) solid hsl(var(--border));
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
}

.nx-abas__lista[hidden] { display: none; }

.nx-abas__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  min-block-size: var(--tap-min);

  font-size: var(--fs-sm);
  font-weight: 500;
  text-align: start;
  white-space: nowrap;
  cursor: pointer;

  color: hsl(var(--muted-foreground));
  background-color: transparent;
  border: var(--hairline) solid transparent;
  border-radius: var(--radius-sm);
}

.nx-abas__item:hover {
  color: hsl(var(--foreground));
  background-color: hsl(var(--accent));
  border-color: hsl(var(--border));
}

/* O grupo aberto se marca como o rail marca a aba ativa, com o mesmo par de
   tokens: dois índices para a mesma navegação não podem ter dois vocabulários
   de "você está aqui". */
.nx-abas__item[aria-current="true"] {
  color: hsl(var(--primary-foreground));
  background-color: hsl(var(--primary));
  border-color: hsl(var(--primary));
}

.nx-abas__item[aria-current="true"] .nx-abas__ico {
  color: inherit;
}

/* Aba: só a ativa existe na tela. */
.nx-tab[hidden] { display: none; }

.nx-tab {
  display: grid;
  gap: var(--space-6);
}

/* A REGRA QUE IMPEDE O PAINEL DE ESTOURAR, e ela vale para todo grid do
   painel, não só para a aba.

   Um item de grid nasce com `min-width: auto`, que resolve para o
   min-content dele: um nome de família tipográfica, um valor de token ou uma
   legenda comprida empurra o item para além da trilha, e a trilha implícita
   `auto` acompanha. Foi assim que a aba de ícones mediu 269px de conteúdo
   dentro de uma coluna de 232px, com o texto cortado na borda do painel.
   Fixar a trilha em `minmax(0, 1fr)` e zerar o mínimo dos filhos resolve os
   dois lados de uma vez, e é a única forma de garantir a invariante deste
   arquivo: o painel não rola na horizontal em viewport nenhuma. */
.nx-studio :is(.nx-tab, .nx-field, .nx-params, .nx-import, .nx-export,
  .nx-presets, .nx-fxgrupo, .nx-fxitem, .nx-ct, .nx-glass, .nx-sub__body,
  .nx-preset__txt) {
  grid-template-columns: minmax(0, 1fr);
}

.nx-studio :is(.nx-tab, .nx-field, .nx-params, .nx-import, .nx-export,
  .nx-presets, .nx-fxgrupo, .nx-fxitem, .nx-ct, .nx-glass, .nx-sub__body,
  .nx-preset__txt, .nx-color) > * {
  min-inline-size: 0;
}

.nx-tab__head {
  display: grid;
  gap: var(--space-2);
  padding-block-end: var(--space-4);
  border-block-end: var(--hairline) solid hsl(var(--border));
}

/* Hierarquia mais forte que os campos abaixo (rodada de design de 5 de
   agosto de 2026): o título da aba é o único texto do painel maior que
   --fs-sm, para o dono nunca confundir "onde estou" com o rótulo de um
   controle. */
.nx-tab__title {
  font-size: var(--fs-base);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: var(--lh-tight);
  color: hsl(var(--foreground));
}

.nx-tab__sub {
  max-inline-size: 42rem;
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: hsl(var(--muted-foreground));
}

/* --------------------------------------------------------------------------
   5. Subgrupo colapsável (details/summary nativo: teclado de graça)

   Sobrou UM: o "Avançado, token a token" dentro da aba de Cor. Os sete
   acordeões de grupo viraram abas nesta rodada e as regras deles saíram
   daqui junto; o que continua valendo é o desenho do summary, porque o
   subgrupo ainda é um <details>.
   -------------------------------------------------------------------------- */

.nx-sub__sum {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding-block: var(--space-4);
  cursor: pointer;
  list-style: none;
  font-weight: 600;
  font-size: var(--fs-sm);
  min-block-size: var(--tap-min);
}

.nx-sub__sum::-webkit-details-marker {
  display: none;
}

.nx-sub__label {
  flex: none;
}

/* Valor legível ao lado do rótulo do subgrupo */
.nx-sub__value {
  flex: 1 1 auto;
  min-inline-size: 0;
  text-align: end;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  font-weight: 400;
  letter-spacing: var(--tracking-mono);
  color: hsl(var(--muted-foreground));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nx-group__chev {
  display: inline-flex;
  flex: none;
  color: hsl(var(--muted-foreground));
  transition: transform calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.nx-sub[open] > .nx-sub__sum .nx-group__chev {
  transform: rotate(180deg);
}

.nx-sub {
  border: var(--hairline) solid hsl(var(--border));
  border-radius: var(--radius-md);
  padding-inline: var(--space-4);
  transition: border-color calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

/* Mesmo cromo do agrupador de Seções (§20): aberto pesa mais que fechado. */
.nx-sub[open] {
  border-color: hsl(var(--input));
}

.nx-sub__sum {
  font-size: var(--fs-xs);
  margin-inline: calc(var(--space-2) * -1);
  padding-inline: var(--space-2);
  border-radius: var(--radius-sm);
  transition: background-color calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.nx-sub__sum:hover {
  background-color: hsl(var(--accent));
}

.nx-sub__body {
  display: grid;
  gap: var(--space-3);
  padding-block-end: var(--space-4);
}

/* Botão de restauro por grupo: ação secundária, sempre no mesmo peso visual
   em toda aba — tracejado em repouso (nunca se confunde com ação primária),
   preenchimento de --accent só no hover/foco, como o resto dos botões
   fantasmas do painel (.nx-btn--ghost). */
.nx-reset {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  justify-self: start;
  margin-block-start: var(--space-1);

  padding: var(--space-2) var(--space-4);
  min-block-size: var(--tap-min);

  font-size: var(--fs-xs);
  font-weight: 600;
  cursor: pointer;

  color: hsl(var(--muted-foreground));
  background-color: transparent;
  border: var(--hairline) dashed hsl(var(--border));
  border-radius: var(--radius-sm);

  transition:
    color calc(var(--dur-fast) * var(--motion)) var(--ease-out),
    background-color calc(var(--dur-fast) * var(--motion)) var(--ease-out),
    border-color calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.nx-reset:hover {
  color: hsl(var(--accent-foreground));
  background-color: hsl(var(--accent));
  border-color: hsl(var(--input));
  border-style: solid;
}

/* --------------------------------------------------------------------------
   5.1 Foco visível, em um lugar só

   O estúdio NÃO empresta as classes de componente da página (.btn, .chip,
   .slider, .switch, .segmented, .color-field). Emprestá-las acoplava o painel
   às peles: [data-skin="glass"] .btn troca padding-inline e raio, e
   [data-skin="surface"] .btn troca altura mínima, ambos com especificidade
   maior que .nx-icon-btn. Com as três peles agora carregando nas três
   páginas, qualquer troca ao vivo deformava o próprio painel que fez a
   troca. O estúdio passa a ser autossuficiente: todo o desenho dos seus
   controles vive neste arquivo, inclusive o anel de foco que antes vinha
   de .btn:focus-visible.
   -------------------------------------------------------------------------- */

/* O radio e o checkbox reais estão escondidos: o anel deles já é
   transferido para o rótulo mais abaixo, por isso ficam de fora daqui. */
.nx-studio :is(button, input, textarea, summary, [tabindex]):not(.nx-pick__input, .nx-switch__input):focus-visible {
  outline: 2px solid hsl(var(--ring));
  outline-offset: 2px;
}

.nx-studio-trigger:focus-visible {
  outline: 2px solid hsl(var(--ring));
  outline-offset: 2px;
}

.nx-color__hex:focus-visible,
.nx-import__ta:focus-visible {
  border-color: hsl(var(--ring));
}

/* --------------------------------------------------------------------------
   6. Campos
   -------------------------------------------------------------------------- */

.nx-field {
  display: grid;
  gap: var(--space-2);
  border: 0;
  padding: 0;
  margin: 0;
  min-inline-size: 0;
}

.nx-field__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}

.nx-field__label {
  padding: 0;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: hsl(var(--foreground));
}

/* Valor legível: pílula discreta, não só texto solto, para o dono achar o
   número em qualquer aba sem procurar (§3 da passada de design, o slider
   precisa mostrar o valor atual com clareza). Mesmo elemento cobre o valor
   de slider e o rótulo de biblioteca exigida ao lado de um interruptor
   (aba Efeitos): as duas são a mesma natureza, "meta mono pequena". */
.nx-field__out {
  flex: none;
  padding: 0.15em var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--tracking-mono);
  color: hsl(var(--muted-foreground));
  background-color: hsl(var(--secondary));
  border-radius: var(--radius-sm);
  white-space: nowrap;
}

.nx-hint {
  font-size: var(--fs-xs);
  line-height: 1.45;
  color: hsl(var(--muted-foreground));
}

/* Linha com um controle largo e um botão ao lado */
.nx-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.nx-row > .nx-slider {
  flex: 1 1 auto;
  min-inline-size: 0;
}

/* Bloco do vidro: só aparece quando a pele de vidro está ativa */
.nx-glass {
  display: grid;
  gap: var(--space-5);
}

.nx-glass[hidden] {
  display: none;
}

/* Input escondido de radio e checkbox: o rótulo é o alvo visível.
   O anel de foco é transferido para o rótulo. */
.nx-pick__input,
.nx-switch__input {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  opacity: 0;
  pointer-events: none;
  margin: 0;
}

.nx-pick__input:focus-visible + label,
.nx-switch__input:focus-visible + label {
  outline: 2px solid hsl(var(--ring));
  outline-offset: 2px;
}

.nx-pick__icon {
  display: inline-flex;
  font-size: 1rem;
}

/* --------------------------------------------------------------------------
   7. Segmented (pele e modo)
   -------------------------------------------------------------------------- */

.nx-seg {
  position: relative;
  display: grid;
  gap: var(--space-1);
  padding: var(--space-1);
  background-color: hsl(var(--secondary));
  border: var(--hairline) solid hsl(var(--border));
  border-radius: var(--radius-md);
}

.nx-seg--3 {
  grid-template-columns: repeat(3, 1fr);
}

/* Cinco peles reais (Padrão/Vidro/Superfície/Metal/Suave), pedido do dono de
   agosto de 2026: a cápsula de "Pele" precisa das cinco em UMA linha, sem
   quebrar 3+2 torto. `minmax(0, 1fr)` (em vez do `1fr` nu de --3) é o que
   permite a coluna encolher abaixo do min-content do rótulo mais comprido
   ("Superfície"); sem isso a grade estoura a largura do painel em vez de
   quebrar o texto, porque o mínimo automático de item de grid é o min-content,
   não zero. O par funcional é .nx-seg--5 .nx-pick__txt logo abaixo: sem
   overflow-wrap ali, o próprio rótulo continuaria travando a coluna no
   min-content da palavra inteira. */
/* Revisão de 6 de agosto de 2026, camada de publicação: as colunas passaram de
   `repeat(5, …)` para trilhas implícitas em fluxo de coluna. O resultado com as
   cinco peles visíveis é idêntico (cinco colunas iguais, mesmo `minmax(0, 1fr)`
   e mesmo gap), mas uma pele DESABILITADA na publicação some do seletor, e uma
   contagem fixa de cinco deixaria uma trilha vazia no lugar dela. Trilha
   implícita nasce por item visível: o rótulo escondido não cria coluna, e o
   input, que é `position: absolute`, nunca criou. */
.nx-seg--5 {
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: calc(var(--space-1) / 2);
}

.nx-seg--5 .nx-seg__opt {
  min-inline-size: 0;
  padding-inline: calc(var(--space-1) / 4);
  gap: calc(var(--space-1) / 2);
}

.nx-seg--5 .nx-pick__icon {
  font-size: 0.85rem;
}

/* fs-xs * 0,8 e não 0,92: no rótulo mais comprido ("Superfície") o peso
   650 do estado marcado (.nx-pick__input:checked + .nx-seg__opt, herdado
   de §7 acima) é mais largo que o peso 500 de repouso — em 0,92 a cápsula
   fechava numa linha só enquanto "Vidro" estava marcado e quebrava
   "Superfíci" + "e" no instante em que o dono marcava "Superfície", um
   salto de altura só por causa de QUAL item está ativo. 0,8 cabe em uma
   linha nos dois pesos, testado no container de prova (5 peles, painel em
   380-600px, clamp de §6.2). */
.nx-seg--5 .nx-pick__txt {
  overflow-wrap: anywhere;
  font-size: calc(var(--fs-xs) * 0.8);
  line-height: 1.15;
  letter-spacing: -0.01em;
}

.nx-seg__opt {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);

  padding-block: var(--space-2);
  padding-inline: var(--space-1);
  min-block-size: var(--tap-min);

  font-size: var(--fs-xs);
  font-weight: 500;
  text-align: center;
  line-height: 1.2;
  cursor: pointer;
  border-radius: var(--radius-sm);
  color: hsl(var(--foreground));

  transition: background-color calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.nx-seg__opt:hover {
  background-color: hsl(var(--accent));
  color: hsl(var(--accent-foreground));
}

.nx-pick__input:checked + .nx-seg__opt {
  background-color: hsl(var(--primary));
  color: hsl(var(--primary-foreground));
  font-weight: 650;
  box-shadow: var(--shadow-sm);
}

/* --------------------------------------------------------------------------
   8. Swatches de preset
   -------------------------------------------------------------------------- */

.nx-swatches {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.nx-swatch {
  display: inline-flex;
  align-items: center;
  justify-content: center;

  inline-size: 2.25rem;
  block-size: 2.25rem;
  padding: var(--space-1);

  cursor: pointer;
  border: 2px solid transparent;
  border-radius: var(--radius-full);

  transition: transform calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.nx-swatch:hover {
  transform: translateY(-2px);
}

.nx-swatch__dot {
  inline-size: 100%;
  block-size: 100%;
  border-radius: var(--radius-full);
  /* --nx-sw é escrito pelo studio.js com a primária realmente derivada */
  background-color: hsl(var(--nx-sw, var(--primary)));
  box-shadow: inset 0 0 0 var(--hairline) hsl(var(--foreground) / 0.18);
}

.nx-pick__input:checked + .nx-swatch {
  border-color: hsl(var(--ring));
}

/* --------------------------------------------------------------------------
   9. Indicador de contraste
   A razão é medida em JS por luminância relativa WCAG. Aqui só o desenho:
   nada de cor semântica cromática, o estado é dito por texto e por peso.
   -------------------------------------------------------------------------- */

.nx-ct {
  display: grid;
  gap: var(--space-1);
  padding: var(--space-3);
  border: var(--hairline) solid hsl(var(--border));
  border-radius: var(--radius-md);
}

.nx-ct__row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.nx-ct__label {
  flex: 1 1 auto;
  min-inline-size: 0;
  font-size: var(--fs-xs);
}

.nx-ct__ratio {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--tracking-mono);
  color: hsl(var(--muted-foreground));
}

.nx-ct__badge {
  flex: none;
  min-inline-size: 3.5em;
  padding: 0.15em var(--space-2);
  text-align: center;

  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  font-weight: 600;
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;

  border: var(--hairline) solid hsl(var(--border));
  border-radius: var(--radius-full);
  color: hsl(var(--muted-foreground));
}

.nx-ct__badge[data-ok="true"] {
  color: hsl(var(--signal));
  border-color: hsl(var(--signal) / 0.55);
}

.nx-ct__badge[data-ok="false"] {
  color: hsl(var(--destructive-foreground));
  background-color: hsl(var(--destructive));
  border-color: hsl(var(--destructive));
}

/* --------------------------------------------------------------------------
   10. Campo de cor: <input type="color"> nativo mais campo hexadecimal
   -------------------------------------------------------------------------- */

.nx-color {
  display: grid;
  gap: var(--space-2);
}

.nx-color__label {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  font-size: var(--fs-xs);
  font-weight: 600;
}

.nx-color__tk {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  font-weight: 400;
  letter-spacing: normal;
  color: hsl(var(--muted-foreground));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Na lista token a token o rótulo fica na mesma linha do controle:
   treze campos empilhados em duas linhas cada não caberiam. */
.nx-color[data-compact="true"] {
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-2);
}

.nx-color[data-compact="true"] > .nx-color__label {
  flex-direction: column;
  align-items: start;
  gap: 0;
}

.nx-color[data-compact="true"] > .nx-color__row {
  inline-size: 10.5rem;
}

/* A paleta de atalho ocupa a largura inteira do campo compacto: ela é uma
   fileira própria abaixo do rótulo e do seletor, não uma terceira coluna. */
.nx-color[data-compact="true"] > .nx-swatches {
  grid-column: 1 / -1;
}

.nx-color__row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.nx-color__pick {
  flex: none;
  inline-size: 2.25rem;
  block-size: 2.25rem;
  min-inline-size: 2.25rem;
  padding: 0;
  cursor: pointer;
  background-color: transparent;
  border: var(--hairline) solid hsl(var(--input));
  border-radius: var(--radius-sm);
}

/* O quadrado interno do color picker acompanha o raio do tema */
.nx-color__pick::-webkit-color-swatch-wrapper {
  padding: 2px;
}

.nx-color__pick::-webkit-color-swatch {
  border: 0;
  border-radius: calc(var(--radius-sm) * 0.7);
}

.nx-color__pick::-moz-color-swatch {
  border: 0;
  border-radius: calc(var(--radius-sm) * 0.7);
}

.nx-color__hex {
  flex: 1 1 auto;
  min-inline-size: 0;
  padding: var(--space-2) var(--space-2);

  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;

  color: hsl(var(--foreground));
  background-color: hsl(var(--background));
  border: var(--hairline) solid hsl(var(--input));
  border-radius: var(--radius-sm);
}

/* --------------------------------------------------------------------------
   11. Botões
   -------------------------------------------------------------------------- */

.nx-btn,
.nx-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);

  color: hsl(var(--foreground));
  background-color: hsl(var(--background));
  border: var(--hairline) solid hsl(var(--input));
  border-radius: var(--radius-sm);
  cursor: pointer;

  transition:
    transform calc(var(--dur-fast) * var(--motion)) var(--ease-out),
    background-color calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.nx-btn {
  flex: 1 1 auto;
  padding: var(--space-3) var(--space-3);
  font-size: var(--fs-xs);
  font-weight: 600;
  min-block-size: var(--tap-min);
  text-align: center;
}

.nx-btn--sm {
  flex: none;
  padding: var(--space-2) var(--space-3);
}

.nx-btn:hover,
.nx-icon-btn:hover {
  background-color: hsl(var(--accent));
  color: hsl(var(--accent-foreground));
}

.nx-btn--ghost {
  background-color: transparent;
}

.nx-icon-btn {
  flex: none;
  inline-size: 2.25rem;
  block-size: 2.25rem;
  min-inline-size: 2.25rem;
  padding: 0;
  font-size: 1.05rem;
}

.nx-btn[disabled],
.nx-icon-btn[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}

.nx-btn[disabled]:hover,
.nx-icon-btn[disabled]:hover {
  background-color: transparent;
  color: hsl(var(--foreground));
}

.nx-studio__close {
  flex: none;
  background-color: hsl(var(--surface-2));
}

.nx-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* --------------------------------------------------------------------------
   12. Famílias tipográficas: cada eixo escolhe a sua, e cada opção é
   renderizada na própria fonte (studio.js escreve o font-family inline,
   lendo de theme.FAMILIES; nenhuma família literal entra neste arquivo).
   -------------------------------------------------------------------------- */

.nx-fams {
  position: relative;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 8.5rem), 1fr));
  gap: var(--space-2);
}

.nx-fam {
  display: flex;
  align-items: center;
  gap: var(--space-2);

  padding: var(--space-2);
  min-block-size: var(--tap-min);
  min-inline-size: 0;

  cursor: pointer;
  background-color: hsl(var(--background));
  border: var(--hairline) solid hsl(var(--input));
  border-radius: var(--radius-sm);

  transition: background-color calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.nx-fam:hover {
  background-color: hsl(var(--accent));
  color: hsl(var(--accent-foreground));
}

.nx-fam__demo {
  flex: none;
  inline-size: 1.6rem;
  font-size: var(--fs-base);
  font-weight: 700;
  line-height: 1;
  text-align: center;
  color: hsl(var(--primary));
}

.nx-fam__name {
  flex: 1 1 auto;
  min-inline-size: 0;
  font-size: var(--fs-xs);
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
}

.nx-pick__input:checked + .nx-fam {
  border-color: hsl(var(--ring));
  background-color: hsl(var(--secondary));
  color: hsl(var(--secondary-foreground));
}

/* --------------------------------------------------------------------------
   13. Slider
   -------------------------------------------------------------------------- */

.nx-slider {
  inline-size: 100%;
  margin: 0;
  padding: var(--space-2) 0;
  background: transparent;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.nx-slider::-webkit-slider-runnable-track {
  block-size: 0.375rem;
  background-color: hsl(var(--secondary));
  border: var(--hairline) solid hsl(var(--input));
  border-radius: var(--radius-full);
}

.nx-slider::-moz-range-track {
  block-size: 0.375rem;
  background-color: hsl(var(--secondary));
  border: var(--hairline) solid hsl(var(--input));
  border-radius: var(--radius-full);
}

.nx-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  inline-size: 1.125rem;
  block-size: 1.125rem;
  margin-block-start: -0.4375rem;
  background-color: hsl(var(--primary));
  border: 2px solid hsl(var(--background));
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-sm);
}

.nx-slider::-moz-range-thumb {
  inline-size: 1.125rem;
  block-size: 1.125rem;
  background-color: hsl(var(--primary));
  border: 2px solid hsl(var(--background));
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-sm);
}

/* Marcas do slider de raio: traços na posição real de cada valor.
   A margem lateral é metade do polegar, para o traço cair no centro dele. */
.nx-ticks {
  position: relative;
  block-size: 0.375rem;
  margin-inline: 0.5625rem;
  margin-block-start: calc(var(--space-1) * -1);
}

.nx-ticks__t {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: calc(var(--nx-at) * 100%);
  transform: translateX(-50%);
  inline-size: var(--hairline);
  block-size: 100%;
  background-color: hsl(var(--input));
}

/* Legenda das pontas da faixa */
.nx-legend {
  display: flex;
  justify-content: space-between;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--tracking-mono);
  color: hsl(var(--muted-foreground));
}

.nx-legend--3 > :nth-child(2) {
  text-align: center;
}

/* --------------------------------------------------------------------------
   14. Chips: o painel consome .chip de 03-ui.css, não uma cópia

   MUDANÇA DESTA RODADA, e ela corrige um defeito que o dono viu no próprio
   painel: os chips tinham geometria inconsistente, o selecionado retangular e
   o não selecionado redondo. O motivo era estrutural, não um erro de valor:
   o painel mantinha um `.nx-chip` PRÓPRIO, com `--radius-full`, enquanto
   03-ui.css padronizava `.chip` em `calc(var(--radius-sm) * 0.5)` e fixava a
   invariante de que ligado e desligado compartilham forma, altura, raio,
   padding, tipo e peso. Duas cópias do mesmo componente divergem por
   construção: uma delas sempre fica para trás.

   Agora o painel usa a MESMA classe. Este bloco não redeclara nem
   `border-radius`, nem `padding`, nem `min-block-size`, nem `font-*`: a
   geometria inteira vem de 03-ui.css, e a única coisa escrita aqui é o
   estado marcado, que é exatamente o que a invariante de lá permite
   (preenchimento e borda).

   Por que `html:root` no seletor do estado marcado. As peles ajustam o chip
   inativo com `[data-skin="glass"] .chip:not([aria-pressed="true"])`, que é
   (0,3,0) e carrega DEPOIS desta folha. Os chips do painel são `<label>` sem
   `aria-pressed`, então caem naquele `:not()`: sem o prefixo, a pele venceria
   o estado marcado e o chip escolhido perderia o preenchimento justamente na
   pele de vidro. `html:root` leva o seletor a (0,4,1) e resolve o empate de
   ordem, sem `!important` e sem tocar em 03-ui.css.
   -------------------------------------------------------------------------- */

.nx-chips {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* `background`, não `background-color`, e a diferença não é estilo: é o que
   apaga o `--glass-sheen` que a pele pinta como background-IMAGE no chip.
   A regra da pele é `[data-skin="glass"] .chip:not([aria-pressed="true"])`, e
   os chips do painel são <label> sem `aria-pressed`, então caem nela. Este
   bloco vence em especificidade e trocava a cor de fundo, mas `background-color`
   não zera a imagem: o degradê continuava por cima, e o primeiro ponto dele é
   branco a 92% de alfa. Resultado medido em `index2.html` claro, 1920x1080:
   `--primary-foreground` (quase branco) sobre um chip que o degradê deixava
   quase branco no topo, `span.nx-pick__txt` a 1,04:1. Valia para os treze
   chips ESCOLHIDOS do painel, um por grupo de radio, e é o rótulo da opção
   ativa, ou seja, exatamente o que o dono precisa ler.
   O irmão logo abaixo (estado não escolhido) já usava a forma correta. */
html:root .nx-studio .nx-pick__input:checked + .chip {
  background: hsl(var(--primary));
  color: hsl(var(--primary-foreground));
  border-color: hsl(var(--primary));
}

/* O chip do painel é um rótulo, não um botão: o `transform` de hover de
   03-ui.css desloca a fileira inteira dentro de um painel estreito. Fica o
   resto da transição, some só o deslocamento. */
html:root .nx-studio .chip:hover,
html:root .nx-studio .chip:active {
  transform: none;
}

/* O QUE O PAINEL NÃO HERDA DA PELE, e por quê.

   `[data-skin="glass"] .chip:not([aria-pressed="true"])` dá ao chip inativo
   um preenchimento translúcido MAIS `backdrop-filter`. Sobre a página isso é
   a assinatura da pele e está certo. Dentro do painel é errado por dois
   motivos, e o segundo foi medido:

   1. O painel é a superfície de controle: ele é opaco de propósito (§0 deste
      arquivo), e vidro dentro de vidro é a terceira camada que o §12.1 do
      contrato proíbe.
   2. PREENCHIMENTO TRANSLÚCIDO DENTRO DE UM PAINEL `position: fixed` NÃO É
      MENSURÁVEL. Esta é a que foi medida, e ela custou duas execuções da
      sonda. `contraste.mjs --estudio` remede em pixel sobre uma captura
      `fullPage`; num painel fixo, o que o Chrome pinta atrás de um elemento
      translúcido nessa captura não é o painel, é o trecho do documento que
      calhou de estar ali. Com o chip herdando o vidro da pele, a sonda leu
      `span.nx-pick__txt` a 1,02:1 e depois a 1,54:1 em index2, tema escuro,
      1920x1080, para um texto que na tela mede acima de 8:1. E não é só
      ruído de sonda: o §7.1.1 do contrato diz, literalmente, que a cadeia de
      ancestrais só é a medida certa para o cromo do estúdio PORQUE o
      preenchimento dele é opaco. Chip translúcido quebra essa premissa.

      A pele já tinha tomado exatamente esta decisão para o painel inteiro:
      `[data-skin="glass"] .nx-studio` é opaco e desliga o próprio
      `backdrop-filter`, com a justificativa escrita ali. O chip do painel
      passa a seguir a mesma regra.

   ISTO NÃO É REDEFINIR O CHIP. A invariante de 03-ui.css §4 é sobre
   GEOMETRIA (forma, altura, raio, padding, tipo, peso), e nada disso é
   tocado aqui. O preenchimento declarado abaixo é o MESMO `--surface-2` que
   03-ui.css dá ao chip de base: o que sai é a camada de ambiente da pele,
   que só faz sentido sobre o campo dela. */
html:root .nx-studio .chip {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* O preenchimento opaco vale só no estado NÃO escolhido, e os dois seletores
   existem porque o painel tem duas famílias de chip: rótulo de radio (estado
   em `input:checked`) e botão (estado em `aria-pressed`). Escrever um só
   `.chip` aqui apagaria o preenchimento do escolhido, que é o único lugar
   onde a invariante de 03-ui.css §4 permite diferença. Medido: com a regra
   larga, "Fade" e "Da pele" escolhidos mediram 1,07:1, texto de
   `--primary-foreground` sobre `--surface-2`. */
html:root .nx-studio .nx-pick__input:not(:checked) + .chip:not([aria-pressed="true"]),
html:root .nx-studio button.chip:not([aria-pressed="true"]) {
  background: hsl(var(--surface-2));
}

/* --------------------------------------------------------------------------
   15. Switch (motion)
   -------------------------------------------------------------------------- */

.nx-switch {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.nx-switch__label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  min-block-size: var(--tap-min);
  cursor: pointer;
  font-size: var(--fs-xs);
  font-weight: 600;
}

.nx-switch__track {
  position: relative;
  display: inline-flex;
  align-items: center;
  flex: none;

  inline-size: 2.75rem;
  block-size: 1.5rem;
  padding: 2px;

  background-color: hsl(var(--secondary));
  border: var(--hairline) solid hsl(var(--input));
  border-radius: var(--radius-full);

  transition: background-color calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.nx-switch__knob {
  inline-size: 1.125rem;
  block-size: 1.125rem;
  background-color: hsl(var(--muted-foreground));
  border-radius: var(--radius-full);
  transition: transform calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.nx-switch__input:checked + .nx-switch__label .nx-switch__track {
  background-color: hsl(var(--primary));
  border-color: hsl(var(--primary));
}

.nx-switch__input:checked + .nx-switch__label .nx-switch__knob {
  background-color: hsl(var(--primary-foreground));
  transform: translateX(1.25rem);
}

/* --------------------------------------------------------------------------
   16. Exportar, importar e status
   -------------------------------------------------------------------------- */

.nx-export {
  display: grid;
  gap: var(--space-2);
}

/* display:grid acima venceria o atributo hidden, que só define display:none
   na folha do agente. Sem esta linha o bloco nasceria aberto. */
.nx-export[hidden] {
  display: none;
}

.nx-export__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

.nx-export__hint {
  font-size: var(--fs-xs);
  color: hsl(var(--muted-foreground));
}

.nx-export__pre {
  max-block-size: 14rem;
  overflow: auto;
  overscroll-behavior: contain;
  padding: var(--space-3);

  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  line-height: 1.55;
  letter-spacing: normal;
  white-space: pre;

  color: hsl(var(--foreground));
  background-color: hsl(var(--background));
  border: var(--hairline) solid hsl(var(--border));
  border-radius: var(--radius-sm);
}

.nx-import {
  display: grid;
  gap: var(--space-2);
  justify-items: start;
}

.nx-import__ta {
  inline-size: 100%;
  min-block-size: 5.5rem;
  resize: vertical;
  padding: var(--space-3);

  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  line-height: 1.5;
  letter-spacing: normal;

  color: hsl(var(--foreground));
  background-color: hsl(var(--background));
  border: var(--hairline) solid hsl(var(--input));
  border-radius: var(--radius-sm);
}

.nx-studio__status {
  font-size: var(--fs-xs);
  line-height: 1.4;
  color: hsl(var(--muted-foreground));
  min-block-size: 1.4em;
}

/* Textarea temporário do fallback de cópia: precisa ser selecionável,
   então não pode ser display:none nem visibility:hidden. */
.nx-copy-sink {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  inline-size: 1px;
  block-size: 1px;
  opacity: 0;
  border: 0;
  padding: 0;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   16.1 Controles novos desta rodada

   Select nativo, blocos de parâmetro de efeito, selo de biblioteca, cartão de
   preset e amostra de ícone. Todos consomem os mesmos tokens do resto do
   painel, e nenhum deles reintroduz cópia de componente da página: o único
   componente emprestado é `.chip`, e é de propósito (ver §14).
   -------------------------------------------------------------------------- */

.nx-select {
  inline-size: 100%;
  min-block-size: var(--tap-min);
  padding: var(--space-2) var(--space-3);

  font-family: var(--font-body);
  font-size: var(--fs-sm);
  font-weight: 550;

  color: hsl(var(--foreground));
  background-color: hsl(var(--background));
  border: var(--hairline) solid hsl(var(--input));
  border-radius: var(--radius-sm);
  cursor: pointer;
}

/* Parâmetros de um efeito: recuados, com um filete que os prende ao efeito
   a que pertencem. */
.nx-params {
  display: grid;
  gap: var(--space-4);
}

.nx-params:empty { display: none; }

.nx-params[hidden] { display: none; }

.nx-fxitem > .nx-params {
  margin-block-start: var(--space-3);
  padding-inline-start: var(--space-4);
  border-inline-start: var(--hairline) solid hsl(var(--border));
}

/* Respiro maior ENTRE grupos que dentro de um grupo (rodada de design de 5
   de agosto de 2026): a lista de efeitos é a aba mais cheia do painel
   (§4 do pedido do dono), e o único jeito de dar estrutura a 8 grupos sem
   inventar cromo novo é fazer o espaço em si carregar a hierarquia. */
.nx-fxgrupo {
  display: grid;
  gap: var(--space-3);
  padding-block: var(--space-5);
  border-block-start: var(--hairline) solid hsl(var(--border));
}

.nx-fxgrupo:first-child {
  padding-block-start: 0;
  border-block-start: 0;
}

.nx-fxgrupo__t {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  font-weight: 600;
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  color: hsl(var(--faint-foreground));
}

/* Contagem de ligados no grupo: mesma pílula de "valor legível" do resto do
   painel (§6, .nx-field__out), sem inventar uma terceira receita de texto
   subordinado. Nunca maiúscula (não é rótulo, é dado). */
.nx-fxgrupo__count {
  flex: none;
  padding: 0.15em var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  font-weight: 500;
  letter-spacing: var(--tracking-mono);
  text-transform: none;
  color: hsl(var(--muted-foreground));
  background-color: hsl(var(--secondary));
  border-radius: var(--radius-sm);
}

.nx-fxitem {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-2);
  /* SEM margin-inline negativo aqui: ao contrário de `.nx-secgroup__sum` e
     `.nx-sub__sum` (que sangram para dentro do padding-inline que o próprio
     pai já reserva, §5 e §20), `.nx-fxgrupo` não tem padding-inline nenhum
     — o "sangue" estourava o painel em 8px, medido nas cinco peles.
     Correção registrada na rodada de design de 5 de agosto de 2026. */
  border-radius: var(--radius-sm);
  transition: background-color calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

/* Faixa sutil no efeito ligado: sinaliza estado sem depender só da cor do
   trilho do switch, que em telas pequenas é o menor elemento da linha. */
.nx-fxitem:has(.nx-switch__input:checked) {
  background-color: hsl(var(--secondary) / 0.5);
}

/* Selo de biblioteca: presente ou ausente, dito por texto e por preenchimento,
   nunca só por cor. */
.nx-libs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.nx-lib {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);

  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--tracking-mono);

  color: hsl(var(--muted-foreground));
  border: var(--hairline) solid hsl(var(--border));
  border-radius: var(--radius-sm);
}

.nx-lib[data-ok="true"] {
  color: hsl(var(--foreground));
  border-color: hsl(var(--input));
  background-color: hsl(var(--secondary));
}

.nx-lib__st {
  font-size: var(--fs-mono);
  color: hsl(var(--faint-foreground));
}

/* Cartão de preset de marca: miniatura de cinco cores, nome e descrição.
   Redesenhado em grade na rodada de design de 5 de agosto de 2026 (§6 do
   pedido do dono): a lista empilhada de 18 cartões de largura cheia virou
   uma grade responsiva de 1 ou 2 colunas, a mesma receita de
   `repeat(auto-fit, minmax(min(100%, X), 1fr))` que `.nx-fams` já usa
   nesta folha — nunca estoura porque o mínimo cede para 100% do
   container antes de forçar rolagem horizontal (garantia do §4).

   `.nx-studio` no seletor não é estilo, é especificidade: a regra
   anti-estouro do §4 (`.nx-studio :is(..., .nx-presets, ...)`) mede
   (0,2,0), e uma coluna só (`.nx-presets`) mediria (0,1,0) e perderia mesmo
   vindo depois no arquivo. Com o prefixo as duas empatam em especificidade
   e esta vence por ordem — sem !important. */
.nx-studio .nx-presets {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
  gap: var(--space-3);
}

.nx-preset {
  position: relative;
  display: grid;
  gap: var(--space-3);
  padding: var(--space-3);
  text-align: start;
  cursor: pointer;

  color: hsl(var(--foreground));
  background-color: hsl(var(--background));
  border: var(--hairline) solid hsl(var(--input));
  border-radius: var(--radius-md);

  transition:
    background-color calc(var(--dur-fast) * var(--motion)) var(--ease-out),
    border-color calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.nx-preset:hover {
  background-color: hsl(var(--accent));
  color: hsl(var(--accent-foreground));
}

.nx-preset[aria-pressed="true"] {
  border-color: hsl(var(--ring));
  background-color: hsl(var(--secondary));
  color: hsl(var(--secondary-foreground));
}

/* Selo do preset ativo: reforço visual do mesmo estado que `aria-pressed`
   já dá ao leitor de tela — nunca a única pista (§0.2 do contrato: nada
   que exista só em decoração). Glifo, não ícone de fonte, para não
   depender de nenhuma família custom aqui dentro. */
.nx-preset[aria-pressed="true"]::after {
  content: "\2713";
  position: absolute;
  inset-block-start: var(--space-2);
  inset-inline-end: var(--space-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 1.25rem;
  block-size: 1.25rem;
  font-size: 0.7rem;
  font-weight: 700;
  line-height: 1;
  color: hsl(var(--primary-foreground));
  background-color: hsl(var(--primary));
  border-radius: var(--radius-full);
}

/* A miniatura vira uma barra cheia no topo do cartão: mais fácil de julgar
   a paleta inteira de relance, e é o que sobra de espaço horizontal numa
   coluna estreita de grade. */
.nx-mini {
  display: flex;
  overflow: hidden;
  inline-size: 100%;
  block-size: 2.25rem;
  border-radius: var(--radius-sm);
  /* O filete interno existe porque a primeira cor da miniatura é o FUNDO do
     preset, quase branco no claro: sem ele a amostra não tem limite contra a
     superfície do cartão e parece ter quatro cores em vez de cinco. */
  box-shadow: inset 0 0 0 var(--hairline) hsl(var(--foreground) / 0.18);
}

.nx-mini__c {
  flex: 1 1 auto;
}

.nx-preset__txt {
  display: grid;
  gap: var(--space-1);
  min-inline-size: 0;
  /* Espaço para o selo de "ativo" nunca cair em cima do nome numa coluna
     estreita: o selo tem 1.25rem + --space-2 de recuo. */
  padding-inline-end: var(--space-5);
}

.nx-preset__nome {
  font-size: var(--fs-sm);
  font-weight: 700;
  line-height: 1.2;
}

/* Três linhas, sempre: numa grade de 18 cartões (contra a lista de 1 coluna
   de antes), altura desigual por causa do texto vira "escada" visual.
   Ellipsis é reforço, não a única saída de leitura — o nome sozinho já
   identifica o preset, e a descrição completa continua no `title`. */
.nx-preset__desc {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: var(--fs-xs);
  line-height: 1.45;
  color: hsl(var(--muted-foreground));
}

.nx-preset[aria-pressed="true"] .nx-preset__desc,
.nx-preset:hover .nx-preset__desc {
  color: inherit;
}

/* Paleta de atalho: as cores extras pedidas pelo dono. Amostras menores que
   as de preset, porque são muitas. */
.nx-swatches--paleta {
  gap: var(--space-1);
}

.nx-swatch--mini {
  inline-size: 1.5rem;
  block-size: 1.5rem;
  padding: 0;
  border-width: var(--hairline);
}

.nx-swatch--mini:hover {
  border-color: hsl(var(--ring));
}

@media (pointer: coarse) {
  .nx-swatch--mini {
    inline-size: 2rem;
    block-size: 2rem;
    min-inline-size: 2rem;
  }
}

/* Amostra viva da família de ícone escolhida. */
.nx-amostra {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  padding: var(--space-4);
  color: hsl(var(--foreground));
  background-color: hsl(var(--secondary));
  border: var(--hairline) solid hsl(var(--border));
  border-radius: var(--radius-md);
}

/* --------------------------------------------------------------------------
   16.1 Bloco de publicação (aba Ações)

   Um bloco só, com moldura própria, porque ele é a única parte do painel que
   sai deste navegador. Tudo acima dele muda o que o DONO vê; ele muda o que o
   VISITANTE vê, e essa fronteira precisa ser visível sem manual.

   O selo é o que responde "isto está no ar?" antes de qualquer leitura:
   `--secondary` quando publicado (calmo, é o estado normal) e `--signal`
   quando há rascunho pendente (o único token cromático do projeto, §2.2,
   usado aqui exatamente como ele existe para ser usado: um aviso pontual).
   -------------------------------------------------------------------------- */

.nx-pub {
  display: grid;
  gap: var(--space-4);
  padding: var(--space-4);
  background-color: hsl(var(--surface-2));
  border: var(--hairline) solid hsl(var(--border));
  border-radius: var(--radius-md);
}

.nx-pub__topo {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-3);
}

.nx-pub__selo {
  padding: var(--space-1) var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  font-weight: 600;
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  border-radius: var(--radius-full);
  color: hsl(var(--secondary-foreground));
  background-color: hsl(var(--secondary));
  border: var(--hairline) solid hsl(var(--border));
}

.nx-pub__selo[data-estado="rascunho"] {
  color: hsl(var(--signal-foreground));
  background-color: hsl(var(--signal));
  border-color: hsl(var(--signal));
}

.nx-pub__quando {
  font-size: var(--fs-xs);
  color: hsl(var(--muted-foreground));
}

/* O bloco herda o `.nx-field` e o `.nx-actions` do resto do painel; só a
   margem do fieldset precisa ceder, porque aqui ele já vive dentro de uma
   moldura com respiro próprio. */
.nx-pub .nx-field {
  margin: 0;
}

/* --------------------------------------------------------------------------
   16.1a Voltar atrás: os três níveis

   Pedido do dono de 6 de agosto de 2026. Três destinos diferentes que antes
   moravam em lugares diferentes do painel, com dois deles usando nomes que
   diziam a mesma coisa. Agora são um bloco só, na ordem do mais leve para o
   mais pesado, e cada um carrega a própria frase logo abaixo — a frase não é
   enfeite: é o que impede o dono de descobrir a diferença clicando.

   A separação visual é HORIZONTAL, por linha fina, e não por caixa: caixa
   dentro de caixa dentro de caixa (aba > .nx-pub > .nx-volta) vira ruído de
   moldura em 390px. O terceiro nível, o de fábrica, é o único com tinta: uma
   barra de `--signal` na borda de início, que é como o resto do painel marca
   "isto é um aviso" (§2.2).
   -------------------------------------------------------------------------- */

.nx-voltas {
  display: grid;
  gap: var(--space-3);
  padding-block-start: var(--space-4);
  border-block-start: var(--hairline) solid hsl(var(--border));
}

.nx-voltas__titulo {
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: var(--lh-tight);
}

.nx-volta {
  display: grid;
  gap: var(--space-2);
  justify-items: start;
}

.nx-volta--pesada {
  padding-inline-start: var(--space-3);
  border-inline-start: 0.1875rem solid hsl(var(--signal));
}

/* O texto explicativo de cada nível não é dica de canto: ele é a diferença
   entre os três, e por isso ganha a largura inteira em vez de ficar preso à
   coluna do botão. */
.nx-volta > .nx-hint {
  max-inline-size: 60ch;
}

/* --------------------------------------------------------------------------
   16.1b Histórico de publicações

   Dez linhas, cada uma com data, resumo e autor. A linha do topo é a que está
   no ar e por isso NÃO tem botão: "voltar para o que já está valendo" seria um
   comando que não faz nada, e um comando que não faz nada ensina o dono a
   desconfiar dos outros.
   -------------------------------------------------------------------------- */

.nx-hist {
  inline-size: 100%;
  padding: var(--space-3);
  background-color: hsl(var(--background));
  border: var(--hairline) solid hsl(var(--border));
  border-radius: var(--radius-md);
}

.nx-hist__vazio {
  font-size: var(--fs-xs);
  color: hsl(var(--muted-foreground));
}

.nx-hist__lista {
  display: grid;
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
}

.nx-hist__item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-3);
  padding-block: var(--space-2);
  border-block-end: var(--hairline) solid hsl(var(--border));
}

.nx-hist__item:last-of-type {
  border-block-end: 0;
}

.nx-hist__txt {
  min-inline-size: 0;
  flex: 1 1 12rem;
}

.nx-hist__quando {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--tracking-mono);
  color: hsl(var(--foreground));
}

/* A versão no ar se marca pelo fundo, nunca só pela palavra: quem varre a
   lista com o olho precisa achar o presente sem ler. */
.nx-hist__item[data-atual="true"] {
  padding-inline: var(--space-2);
  background-color: hsl(var(--secondary));
  border-radius: var(--radius-sm);
}

.nx-hist__resumo,
.nx-hist__quem {
  font-size: var(--fs-xs);
  color: hsl(var(--muted-foreground));
}

.nx-hist__nota {
  padding-block-start: var(--space-2);
}

/* --------------------------------------------------------------------------
   16.2 Portão de acesso do /admin-cli

   Sem sessão, /admin-cli mostra APENAS este formulário. Ele cobre a página
   inteira com fundo opaco de propósito: "apenas o formulário" não é um cartão
   flutuando sobre o site legível. O visual é o do site, com os tokens do
   projeto e o mesmo `.btn--primary` de 03-ui.css, nunca uma tinta própria.
   -------------------------------------------------------------------------- */

.nx-portao {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: grid;
  place-items: center;
  padding: var(--gutter);
  overflow-y: auto;
  color: hsl(var(--foreground));
  background-color: hsl(var(--background));
}

.nx-portao__card {
  inline-size: min(100%, 26rem);
  display: grid;
  gap: var(--space-4);
  padding: var(--space-8);
  background-color: hsl(var(--card));
  color: hsl(var(--card-foreground));
  border: var(--hairline) solid hsl(var(--border));
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
}

.nx-portao__eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  font-weight: 500;
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  color: hsl(var(--faint-foreground));
}

.nx-portao__title {
  font-size: var(--fs-h3);
  line-height: var(--lh-tight);
}

.nx-portao__lead {
  font-size: var(--fs-sm);
  color: hsl(var(--muted-foreground));
}

.nx-portao__field {
  display: grid;
  gap: var(--space-2);
}

.nx-portao__label {
  font-size: var(--fs-xs);
  font-weight: 600;
}

.nx-portao__input {
  inline-size: 100%;
  min-block-size: var(--tap-min);
  padding: var(--space-2) var(--space-3);
  font-family: inherit;
  font-size: var(--fs-sm);
  color: hsl(var(--foreground));
  background-color: hsl(var(--background));
  border: var(--hairline) solid hsl(var(--input));
  border-radius: var(--radius-sm);
}

.nx-portao__input:focus-visible {
  outline: 2px solid hsl(var(--ring));
  outline-offset: 2px;
}

.nx-portao__btn {
  justify-content: center;
  min-block-size: var(--tap-min);
}

/* Vazio quando não há erro: sem `min-block-size`, o cartão saltaria de altura
   na primeira recusa. */
.nx-portao__erro {
  min-block-size: 1.25rem;
  font-size: var(--fs-sm);
  color: hsl(var(--destructive));
}

/* --------------------------------------------------------------------------
   17. Mobile, alvo de toque e impressão
   -------------------------------------------------------------------------- */

/* Alvo de toque de 44px em TODO controle onde o dedo é o ponteiro (§7.5) */
@media (pointer: coarse) {
  .nx-swatch,
  .nx-color__pick,
  .nx-icon-btn {
    inline-size: var(--tap-min);
    block-size: var(--tap-min);
    min-inline-size: var(--tap-min);
  }

  /* Só o piso: o ícone-só (2.5rem) e o modo com rótulo (7.5rem, acima de
     1700px) continuam decidindo a largura real, este bloco só garante que
     nenhum dos dois caia abaixo de 44px de alvo de toque (§8 do contrato). */
  .nx-rail__btn {
    min-inline-size: var(--tap-min);
    min-block-size: var(--tap-min);
  }

  /* O menu de abas do mobile pelo mesmo critério. As regras base já pedem
     `min-block-size: var(--tap-min)` nos dois; aqui o piso é repetido de
     propósito, para o alvo não depender de um valor escrito longe daqui, e a
     altura sobe um degrau porque no dedo a lista é percorrida em rolagem, não
     em precisão. */
  .nx-abas__btn,
  .nx-abas__item {
    min-block-size: var(--tap-min);
    padding-block: var(--space-3);
  }

  .nx-slider {
    padding-block: var(--space-3);
  }

  .nx-color[data-compact="true"] {
    grid-template-columns: minmax(0, 1fr);
  }

  .nx-color[data-compact="true"] > .nx-color__row {
    inline-size: 100%;
  }
}

/* O painel vira folha de baixo para cima */
@media (max-width: 640px) {
  .nx-studio {
    inset-block-start: auto;
    inset-block-end: 0;
    inset-inline: 0;

    inline-size: 100%;
    block-size: 88svh;
    max-block-size: 88svh;

    border-inline-start: 0;
    border-block-start: var(--hairline) solid hsl(var(--border));
    border-start-start-radius: var(--radius-lg);
    border-start-end-radius: var(--radius-lg);

    transform: translateY(101%);
  }

  .nx-studio[data-open="true"] {
    transform: translateY(0);
  }

  .nx-studio__head,
  .nx-studio__body,
  .nx-studio__foot,
  .nx-aviso {
    padding-inline: var(--space-4);
  }

  .nx-studio-trigger {
    inset-block-end: var(--space-4);
    inset-inline-end: var(--space-4);
  }

  /* O cabeçalho em duas linhas já vale em toda largura (§3). Aqui só o vão
     entre colunas encolhe, porque em 390px os dois botões de 44px e o título
     dividem a mesma linha e cada pixel de vão sai do título. */
  .nx-studio__head {
    column-gap: var(--space-2);
  }

  /* `--fs-h3` chega a 1.75rem e é escala de TÍTULO DE SEÇÃO, não de cabeçalho
     de painel de 390px: medido em 20,72px contra 255px de nome inteiro, ele
     empurrava o botão de fechar até 2px da borda e comia os 16px de respiro
     lateral do painel. Um degrau abaixo cabe em uma linha e continua sendo o
     maior texto da barra. */
  .nx-studio__title {
    font-size: var(--fs-base);
  }

  /* ------------------------------------------------------------------------
     ÍNDICE DE ABAS EM GRADE REGULAR (mesmo defeito, segunda metade: "as duas
     fileiras de ícones de aba ficam desorganizadas").

     A causa: o índice era `flex-wrap`, e flex distribui a sobra na ÚLTIMA linha.
     Com catorze itens de largura desigual, a primeira fileira fechava justa e a
     segunda ficava com o resto espalhado, sem nenhuma coluna alinhada com a de
     cima. Lido de longe, é exatamente "desorganizado".

     Vira grade. `auto-fit` com piso de `--tap-min` escolhe a contagem de
     colunas que cabe (sete em 390px, e portanto duas fileiras exatas de sete
     para os catorze grupos) e as colunas ficam ALINHADAS entre as fileiras,
     que é o que faz o bloco ler como um teclado e não como um monte. O piso da
     trilha é o próprio alvo de toque, então a grade nunca produz um botão
     menor que o dedo, e por isso mesmo ela nunca precisa de rolagem
     horizontal: quando não cabe mais uma coluna, ela tira uma coluna.
     ------------------------------------------------------------------------ */
  .nx-studio__shell {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
  }

  /* A GRADE DE CATORZE ÍCONES DÁ LUGAR AO MENU POR NOME (revisão de 6 de agosto
     de 2026, pedido do dono: "para não ficar aquela barra enorme à toa, mas só
     no modo mobile").

     A grade regular resolveu o defeito de alinhamento que ela tinha antes, mas
     não resolveu os dois que sobraram e que o dono viu: ela custa duas fileiras
     de 44px mais respiro, cerca de um sétimo da folha de 88svh, em toda sessão
     de edição; e catorze ícones sem rótulo, num regime onde o `title` não abre
     porque não existe hover, é adivinhação. O menu ocupa uma linha e diz o nome
     do grupo aberto.

     A coluna sai por `display: none` e não por `visibility`/opacidade: ela tem
     que sair também da ordem de tabulação e da árvore de acessibilidade, senão
     o dono passaria por catorze `role="tab"` invisíveis antes de chegar ao
     primeiro controle. */
  .nx-studio__rail {
    display: none;
  }

  .nx-abas {
    display: block;
    padding: var(--space-2) var(--space-4) var(--space-3);
    background-color: hsl(var(--surface-2));
    border-block-end: var(--hairline) solid hsl(var(--border));
  }

  /* Respiro coerente entre o índice e o conteúdo da aba. */
  .nx-studio__body {
    padding-block-start: var(--space-4);
  }
}

/* Paisagem baixa: a folha não pode engolir a tela inteira */
@media (max-width: 640px) and (max-height: 520px) {
  .nx-studio {
    block-size: 94svh;
    max-block-size: 94svh;
  }
}

@media print {
  .nx-studio,
  .nx-studio-trigger,
  .nx-pattern {
    display: none;
  }
}

/* --------------------------------------------------------------------------
   18. Ponto de consumo dos eixos variáveis de peso

   DIVERGÊNCIA REGISTRADA (§0.3 do contrato pede que todo token nasça em
   01-tokens.css). As cinco fontes do projeto são variáveis e o estúdio
   passou a controlar o eixo wght, mas 02-base.css escreve os pesos como
   literais (700 no h1, 650 no h2, 600 nos demais, 400 no corpo, 650 no
   strong) e não existe token para eles. 01-tokens.css não é território
   desta entrega, então os dois tokens novos nascem aqui, com os MESMOS
   valores de fábrica que 02-base.css já usava: nenhuma página muda de
   aparência enquanto o estúdio não for tocado.

   Os degraus entre h1, h2 e h3 são preservados como deslocamentos do eixo,
   não como números soltos, para que mover o peso de display continue
   entregando a mesma hierarquia. Quando este arquivo puder ser fundido,
   as duas declarações de :root descem para 01-tokens.css e este bloco
   vira só o mapeamento.
   -------------------------------------------------------------------------- */

:root {
  --fw-display: 700;
  --fw-body: 400;
}

body {
  font-weight: var(--fw-body);
}

h1 {
  font-weight: var(--fw-display);
}

h2 {
  font-weight: calc(var(--fw-display) - 50);
}

h3,
h4,
h5,
h6 {
  font-weight: calc(var(--fw-display) - 100);
}

strong,
b {
  font-weight: calc(var(--fw-body) + 250);
}

/* ==========================================================================
   19. O QUE O ESTÚDIO PASSA A GOVERNAR NA PÁGINA

   Tudo daqui para baixo está atrás de um PORTÃO: um atributo `data-nx-*` no
   <html>, escrito por core/theme.js só quando o grupo correspondente sai do
   padrão de fábrica. Sem o atributo, nenhum seletor deste bloco casa com
   nada, e a página é byte por byte a de sempre. É o que mantém a auditoria
   de contraste (zero reprovações em cerca de 20 mil medições) e a
   divergência entre as três peles medindo o mesmo estado de antes.

   Por que o portão, e não só especificidade: esta folha carrega ANTES das
   catorze folhas de seção e das três peles. Uma regra `.btn` escrita aqui
   perderia para `[data-skin="surface"] .btn` por ordem e por
   especificidade. `html[data-nx-btn] .btn` é (0,2,1) e ganha das duas, e só
   existe quando o dono pediu.

   Índice:
   19.1 Camada de padrão de fundo que vale nas TRÊS peles
   19.2 Menu
   19.3 Botões
   19.4 Ícones
   19.5 Títulos de seção
   19.6 As catorze seções
   19.7 Destaque do exemplo (rolagem até o controle)
   ========================================================================== */

/* --------------------------------------------------------------------------
   19.0 Os valores de fábrica dos tokens novos, e por que eles vivem AQUI

   DIVERGÊNCIA REGISTRADA, do mesmo tipo da que o §18 deste arquivo já
   registra: o §0.3 do contrato manda todo token nascer em 01-tokens.css, e
   01-tokens.css não é território desta entrega.

   E eles PRECISAM existir em uma folha, não só no estado. core/theme.js
   escreve inline apenas o que DIFERE do padrão de fábrica (regra do estado
   limpo, §11): no estado de fábrica ele REMOVE `--nx-btn-fw` do <html>. Se o
   valor de fábrica não estivesse declarado em lugar nenhum,
   `font-weight: var(--nx-btn-fw)` viraria inválida no momento de computar e o
   botão cairia para o peso herdado. Foi exatamente o que a primeira medição
   em browserless pegou: com `data-nx-btn` ligado e o peso ainda de fábrica, o
   botão media `font-weight: 400` no lugar de 600.

   Cada valor abaixo é a transcrição literal do que `knobs()` emite para o
   estado de fábrica. Mexer em um obriga a mexer no outro, na mesma edição.

   QUATRO EXCEÇÕES DELIBERADAS, da rodada de agosto de 2026 (cor da barra,
   cor dos links, tamanho do logo e respiro horizontal do menu). `knobs()`
   passou a emitir `--menu-bg`, `--menu-fg`, `--logo-scale` e `--menu-pad-x`,
   e nenhum deles é declarado aqui, de propósito:

   - o consumo dos quatro vive em `sections/header.css`, que carrega DEPOIS
     desta folha, e cada um é lido com o padrão dentro do próprio `var()`
     (`var(--menu-bg, var(--background))`, `var(--logo-scale, 0.8)`). O buraco
     que criou este bloco (token removido do inline e nenhuma folha
     declarando o valor de fábrica) não existe quando o fallback está no
     ponto de uso;
   - e a diferença não é só de estilo. Declarar `--menu-fg: var(--muted-foreground)`
     aqui congelaria a substituição no <html>: o valor computado de uma
     custom property que referencia outra é resolvido no elemento onde ela é
     DECLARADA. A tinta que as peles recalibram para o ambiente delas (§2.5)
     chegaria ao link com o valor do chassi. Com o fallback no `var()` do
     ponto de uso, quem resolve é o próprio `.header__nav-link`, com a tinta
     que vale ali.
   -------------------------------------------------------------------------- */

:root {
  --nx-menu-w: var(--container);
  --nx-menu-h: var(--header-h);
  --nx-menu-fs: 1;
  --nx-menu-pad: 1;

  --nx-btn-size: 1;
  --nx-btn-radius: var(--radius-md);
  --nx-btn-px: 1;
  --nx-btn-gap: 1;
  --nx-btn-fw: 600;
  --nx-btn-fill: var(--primary);
  --nx-btn-on: var(--primary-foreground);

  --nx-icon-size: 1;
  --nx-icon-stroke: 1.6;
  --nx-icon-tint: currentColor;

  --nx-head-top: 1;
  --nx-head-bottom: 1;
  --nx-head-align: start;
  --nx-head-mis: 0px;
  --nx-head-mie: auto;
}

/* --------------------------------------------------------------------------
   19.1 O padrão de fundo passa a valer nas TRÊS peles

   DEFEITO RELATADO PELO DONO: "eu tô mudando opções no widget tipo padrão de
   fundo e ele não reflete em todas as peles, por quê?"

   CAUSA, medida antes de escrever uma linha: o padrão não é pintado por um
   token, é pintado por um ELEMENTO, `body::before` (02-base.css §6). E as
   duas peles se apropriam desse mesmo elemento para o ambiente próprio
   delas: `06-skin-glass.css` o usa para a aurora e `08-skin-surface.css`
   para os filetes do container, as duas redeclarando `background-image`,
   `mask-image`, `mix-blend-mode` e `animation` de propósito. Não é a cascata
   de `--pattern` que perde: `--pattern` chega certo em `body`, o pacote
   `--pattern-image` é resolvido certo, e não sobra ninguém para pintá-lo. A
   pele `surface` ainda declara `--pattern: none` no próprio escopo, mas isso
   é secundário, porque o estilo inline que o estúdio escreve no <html> vence
   qualquer folha: mesmo com o token certo, a camada não existia.

   CORREÇÃO: uma camada dedicada, `.nx-pattern`, que o estúdio cria como nó
   PRÓPRIO (do mesmo jeito que já cria o gatilho e o painel; ele continua sem
   tocar em um único nó da página). Ela é filha de `body`, então herda o
   pacote `--pattern-*` já resolvido lá, e vive nas três peles sem disputar o
   pseudo-elemento de ninguém. A pele continua com o ambiente dela intacto; o
   padrão do dono entra por cima do campo e por baixo de todo o conteúdo.

   Ela fica INERTE na pele padrão (`display: none`), onde `body::before` já
   faz o trabalho: duas camadas iguais dobrariam a opacidade do mesmo
   desenho.
   -------------------------------------------------------------------------- */

.nx-pattern {
  display: none;
  position: fixed;
  inset: -12%;
  z-index: -1;
  pointer-events: none;
  background-image: var(--pattern-image);
  background-size: var(--pattern-size);
  background-position: var(--pattern-position);
  background-repeat: var(--pattern-repeat);
  opacity: calc(var(--pattern-opacity) * var(--pattern-boost));
  mix-blend-mode: var(--pattern-blend);
  -webkit-mask-image: var(--pattern-mask);
  mask-image: var(--pattern-mask);
  will-change: transform;

  /* Mesma deriva de 02-base.css, e gated pelo mesmo `--motion`: com
     `--motion: 0` a duração vira 0s e nada se move. */
  animation-name: var(--pattern-anim);
  animation-duration: calc(var(--motion) * 26s);
  animation-timing-function: var(--ease-io);
  animation-iteration-count: infinite;
  animation-direction: alternate;
}

[data-skin="glass"] .nx-pattern,
[data-skin="surface"] .nx-pattern,
[data-skin="smooth"] .nx-pattern {
  display: block;
}

/* Nas peles com ambiente próprio o padrão do dono entra como CAMADA A MAIS,
   não como substituto: 70% da intensidade que ele tem na pele padrão, para
   somar ao campo em vez de brigar com ele. É o mesmo raciocínio do
   `--pattern-boost` por tema de 01-tokens.css, com o eixo trocado.

   CORREÇÃO DE 5 DE AGOSTO DE 2026: `smooth` entrou nas duas regras acima.
   Antes disso a folha da pele (10-skin-smooth.css) só chamava `.nx-pattern`
   quando `data-pattern-user` estava presente no `<html>`, e esse atributo
   nunca nasce para o valor de fábrica: `core/theme.js` só grava um atributo
   quando o valor escolhido DIFERE do padrão (§11, estado limpo), e o padrão
   de fábrica de `--pattern` é justamente `grid`. Resultado medido: a pele
   smooth abria sem nenhuma grade, e a única forma de ligá-la era o dono ir
   ao painel e trocar para qualquer OUTRO valor — voltar para "Grade" depois
   não reacendia nada, porque "Grade" é o valor de fábrica e nunca escreve o
   atributo. Com `smooth` aqui, a camada nasce visível como em `glass`
   e `surface`, no mesmo teto de 70%: a pele já tem campo de luminosidade e
   hachura própria (10-skin-smooth.css), então o padrão do estúdio soma, não
   substitui. A folha da pele ainda decide se a HACHURA PRÓPRIA cede lugar
   quando o dono troca de padrão (ela cede; ver 10-skin-smooth.css). */
[data-skin="glass"] .nx-pattern,
[data-skin="surface"] .nx-pattern,
[data-skin="smooth"] .nx-pattern {
  opacity: calc(var(--pattern-opacity) * var(--pattern-boost) * 0.7);
}

@media (prefers-reduced-motion: reduce) {
  .nx-pattern { animation: none; }
}

/* --------------------------------------------------------------------------
   19.2 Menu

   `data-nx-menu` vale "on" quando só as medidas mudaram, ou o nome da
   variante. `data-nx-menu-linha` governa o divisor.
   -------------------------------------------------------------------------- */

html[data-nx-menu] .header__bar {
  block-size: var(--nx-menu-h);
  max-inline-size: var(--nx-menu-w);
  margin-inline: auto;
  inline-size: 100%;
  gap: calc(var(--space-6) * var(--nx-menu-pad));
}

html[data-nx-menu] .header__nav-list {
  gap: calc(var(--space-6) * var(--nx-menu-pad));
}

html[data-nx-menu] .header__nav-link,
html[data-nx-menu] .header__cta {
  font-size: calc(var(--fs-sm) * var(--nx-menu-fs));
}

/* Fixo: a barra presente desde o primeiro pixel. Revisão de 6 de agosto de
   2026, bug do dono: opaca no token de fundo, a faixa marcava um degrau
   contra o hero (que pinta gradientes próprios por baixo) — "deveria ser da
   cor de baixo". Translúcida com desfoque, ela assume a cor do que estiver
   atrás em qualquer ponto da rolagem, sempre contínua. Fallback opaco para
   navegador sem backdrop-filter. */
html[data-nx-menu="fixo"] .header {
  background-color: hsl(var(--background) / 0.6);
  backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  border-block-end-color: hsl(var(--border));
}

@supports not (backdrop-filter: blur(1px)) {
  html[data-nx-menu="fixo"] .header {
    background-color: hsl(var(--background));
  }
}

/* Flutuante: a barra descola do topo e vira uma faixa com respiro em volta.
   Só transform e opacity animam; o descolamento é `inset`, estático. */
html[data-nx-menu="flutuante"] .header {
  inset-block-start: var(--space-3);
  inset-inline: var(--gutter);
  background-color: hsl(var(--background) / 0.94);
  border: var(--hairline) solid hsl(var(--border));
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
}

html[data-nx-menu="flutuante"] .header__bar {
  padding-inline: var(--space-5);
}

/* Cápsula: a navegação central ganha um preenchimento e um contorno
   próprios, e a barra em volta continua transparente. */
html[data-nx-menu="capsula"] .header__nav-list {
  padding: var(--space-1) var(--space-3);
  background-color: hsl(var(--secondary));
  border: var(--hairline) solid hsl(var(--border));
  border-radius: var(--radius-full);
}

/* Cápsula: breakpoint próprio de recolhimento (adendo de 6 de agosto de
   2026).

   DEFEITO MEDIDO: entre 880px (breakpoint mobile/desktop, literal e
   compartilhado com o matchMedia de partials/header.js — ver comentário no
   topo de sections/header.css) e 1023px, o CTA some sob a cápsula. Não é bug
   de estado: a lista de links já entra em modo desktop em 880px
   (sections/header.css §4) com `gap` fluido em `clamp()`, e a cápsula deste
   arquivo (bloco acima) soma padding e contorno próprios por cima do mesmo
   miolo. A largura combinada de marca + links + cápsula + CTA nessa faixa
   excede a barra antes de qualquer wrap possível — testado até
   `--nx-menu-fs: 0.65` (o preset já reduz a fonte do menu ao mínimo legível)
   e a sobreposição persiste, porque o problema é de LARGURA acumulada, não
   de tamanho de tipo. Não há wrap elegante dentro de uma cápsula (ela é uma
   pílula de uma linha só, por desenho) e nav com scroll interno está fora de
   cogitação (§ contrato de motion/layout deste projeto). O limite é físico
   da variante, não resolvível por preset.

   CORREÇÃO: só para esta variante, o recolhimento em botão de menu (que já
   existe e já funciona — sections/header.css §5/6) passa a valer também
   entre 880px e 1039,98px. Acima de 1040px sobra fôlego de sobra medido em
   browserless para marca + links + cápsula + CTA conviverem sem colisão em
   nenhum preset testado (inclusive "apple", cápsula mais larga). Abaixo de
   880px o comportamento já era mobile e continua idêntico — este bloco só
   estica a janela mobile pra cima, e só quando `data-nx-menu="capsula"`.

   Os quatro seletores abaixo reescrevem, com um grau a mais de
   especificidade (`html[data-nx-menu="capsula"]` põe um atributo na frente
   da classe), as quatro trocas de `display` que sections/header.css faz em
   `@media (min-width: 880px)`. Ficam presos num `max-width: 1039.98px` para
   não vazar acima de 1040px, onde o comportamento desktop de fábrica volta a
   valer sem nenhuma regra daqui competindo. Nenhum hex, nenhum !important:
   é a mesma tática de portão por atributo que o §8 deste arquivo já usa para
   os controles do dono, aplicada a um breakpoint em vez de a uma cor. */
@media (min-width: 880px) and (max-width: 1039.98px) {
  html[data-nx-menu="capsula"] .header__nav,
  html[data-nx-menu="capsula"] .header__cta {
    display: none;
  }

  html[data-nx-menu="capsula"] .header__toggle {
    display: inline-flex;
  }

  html[data-nx-menu="capsula"] .header__menu {
    display: flex;
  }
}

html[data-nx-menu="filete"] .header {
  border-block-end-color: hsl(var(--border));
}

/* Barra suave: blueprint do bloco header-1 do smoothui
   (docs/smooth-ref/HERO-OBRIGATORIO.md, ponto 2 — "a barra fica limpa, logo
   à esquerda, links centrados, sem cápsula"). A pele smooth já nasce assim
   por decreto (10-skin-smooth.css §6); esta variante entrega o mesmo
   desenho para QUALQUER pele, como opção do dono, sem duplicar a folha da
   pele smooth: mesma receita (grade de três colunas, link vira pílula só
   no hover/foco, sem cápsula fixa em volta da lista).

   Nas peles glass e surface o portão genérico
   `[data-skin="…"][data-nx-menu]:not([data-nx-menu="on"])` (06-skin-glass.css
   §12a, 08-skin-surface.css §12a) já zera a cápsula/segmentado próprios
   delas para QUALQUER variante nomeada — inclusive esta — então não é
   preciso repetir a cessão aqui.

   min-block-size no link: o alvo de toque de 44px (§8) que o botão e a
   marca já cumprem, estendido ao link de navegação nesta variante — as
   outras quatro herdam só o padding-block de sections/header.css. */
@media (min-width: 880px) {
  html[data-nx-menu="suaveum"] .header__bar {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
  }

  html[data-nx-menu="suaveum"] .header__nav {
    justify-self: center;
  }

  html[data-nx-menu="suaveum"] .header__actions {
    justify-self: end;
  }
}

html[data-nx-menu="suaveum"] .header__nav-list {
  gap: var(--space-1);
}

html[data-nx-menu="suaveum"] .header__nav-link {
  min-block-size: var(--tap-min);
  padding-inline: var(--space-4);
  border-radius: var(--radius-full);
  transition:
    background-color calc(var(--dur-fast) * var(--motion)) var(--ease-out),
    color calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

html[data-nx-menu="suaveum"] .header__nav-link::after {
  content: none;
}

html[data-nx-menu="suaveum"] .header__nav-link:hover,
html[data-nx-menu="suaveum"] .header__nav-link:focus-visible {
  background-color: hsl(var(--secondary));
  color: hsl(var(--foreground));
}

html[data-nx-menu="suaveum"] .header__toggle {
  border-radius: var(--radius-full);
}

html[data-nx-menu-linha="nenhuma"] .header,
html[data-nx-menu-linha="nenhuma"] .header--scrolled {
  border-block-end-color: transparent;
  box-shadow: none;
}

html[data-nx-menu-linha="filete"] .header,
html[data-nx-menu-linha="filete"] .header--scrolled {
  border-block-end-color: hsl(var(--border));
  box-shadow: none;
}

html[data-nx-menu-linha="sombra"] .header--scrolled {
  border-block-end-color: transparent;
  box-shadow: var(--shadow-md);
}

/* --------------------------------------------------------------------------
   19.3 Botões

   O dono pediu "todos os botões: mudar fundo, efeito, cor, modelo, tamanho,
   espaço entre outros". Modelo, tamanho, raio, respiro, peso e cor moram
   aqui; o EFEITO de hover não, ele vem do catálogo de core/fx.js e é
   aplicado por atributo, sem CSS novo.

   `--nx-btn-fill` e `--nx-btn-on` são um PAR: quando o dono escolhe o
   preenchimento, core/theme.js calcula o primeiro plano legível com a mesma
   função `readableOn()` que deriva a paleta inteira, com piso de 4,5:1. Não
   existe caminho em que o texto do botão fique sobre um fundo que ele não
   alcança, e é por isso que a cor do botão não é um `<input type=color>`
   solto escrevendo `background`.
   -------------------------------------------------------------------------- */

html[data-nx-btn] .btn {
  min-block-size: calc(var(--tap-min) * var(--nx-btn-size));
  padding-block: calc(var(--space-3) * var(--nx-btn-size));
  padding-inline: calc(var(--space-5) * var(--nx-btn-px));
  border-radius: var(--nx-btn-radius);
  font-size: calc(var(--fs-sm) * var(--nx-btn-size));
  font-weight: var(--nx-btn-fw);
}

html[data-nx-btn] .cluster,
html[data-nx-btn] .btn + .btn {
  --cluster-gap: calc(var(--space-3) * var(--nx-btn-gap));
}

/* Sólido: preenchimento cheio, sem contorno. */
html[data-nx-btn="solido"] .btn {
  background-color: hsl(var(--nx-btn-fill));
  color: hsl(var(--nx-btn-on));
  border-color: transparent;
  box-shadow: none;
}

/* Contorno: só o limite, no token calibrado para 3:1 de componente
   interativo (--input), nunca --border, que é divisor estático (§2.5). */
html[data-nx-btn="contorno"] .btn {
  background-color: transparent;
  color: hsl(var(--foreground));
  border-color: hsl(var(--input));
  box-shadow: none;
}

html[data-nx-btn="contorno"] .btn:hover {
  background-color: hsl(var(--accent));
  color: hsl(var(--accent-foreground));
}

/* Fantasma: nem preenchimento nem limite em repouso. */
html[data-nx-btn="fantasma"] .btn {
  background-color: transparent;
  color: hsl(var(--foreground));
  border-color: transparent;
  box-shadow: none;
}

html[data-nx-btn="fantasma"] .btn:hover {
  background-color: hsl(var(--accent));
  color: hsl(var(--accent-foreground));
}

/* Suave: preenchimento de superfície, texto na tinta cheia. Par sólido, sem
   alfa: alfa é aposta sobre o que está pintado atrás (§2.5). */
html[data-nx-btn="suave"] .btn {
  background-color: hsl(var(--secondary));
  color: hsl(var(--secondary-foreground));
  border-color: hsl(var(--border));
  box-shadow: none;
}

html[data-nx-btn="suave"] .btn:hover {
  background-color: hsl(var(--accent));
  color: hsl(var(--accent-foreground));
}

/* Elevado: o sólido com profundidade. A sombra respeita
   `--shadow-strength`, então em 0 ele degrada para o sólido. */
html[data-nx-btn="elevado"] .btn {
  background-color: hsl(var(--nx-btn-fill));
  color: hsl(var(--nx-btn-on));
  border-color: transparent;
  box-shadow: var(--shadow-md);
}

html[data-nx-btn="elevado"] .btn:hover {
  box-shadow: var(--shadow-lg);
}

/* Cor escolhida à mão vale mesmo quando o modelo é "da pele", desde que o
   modelo não seja um dos vazados. */
html[data-nx-btn="on"] .btn--primary {
  background-color: hsl(var(--nx-btn-fill));
  color: hsl(var(--nx-btn-on));
}

/* --------------------------------------------------------------------------
   19.4 Ícones

   Tamanho vale em toda parte, INCLUSIVE dentro do painel: o dono pediu que o
   widget refletisse as mudanças, e ícone é uma delas.

   A TINTA não entra no painel, e a razão é de auditoria, não de gosto: o
   cromo do estúdio é medido pelo mesmo piso do §8 (`contraste.mjs
   --estudio`), e uma tinta arbitrária escolhida pelo dono sobre as
   superfícies do painel criaria um par novo a cada arrasto do seletor. Na
   página ela vale, e o painel mostra a razão WCAG dela ao vivo.
   -------------------------------------------------------------------------- */

html[data-nx-icon] .nx-icon {
  font-size: calc(1em * var(--nx-icon-size));
}

html[data-nx-icon] :is(header, main, footer) .nx-icon {
  color: var(--nx-icon-tint);
}

/* --------------------------------------------------------------------------
   19.5 Títulos de seção: respiro e alinhamento
   -------------------------------------------------------------------------- */

html[data-nx-head] .section__head {
  margin-block-start: calc(var(--space-10) * (var(--nx-head-top) - 1));
  margin-block-end: calc(var(--space-10) * var(--nx-head-bottom));
  text-align: var(--nx-head-align);
  justify-items: var(--nx-head-align);
}

/* Centro e direita precisam da CAIXA deslocada, não só do texto: o cabeçalho
   tem `max-width: var(--measure)` e fica ancorado à esquerda, então
   `text-align: center` sozinho centraliza a linha dentro de uma caixa que
   continua encostada na margem, e o dono não vê diferença nenhuma. As duas
   margens são emitidas por core/theme.js como par (`auto`/`0`), porque CSS
   não ramifica em cima do valor de uma custom property. */
html[data-nx-head] .section__head:not(.section__head--split) {
  margin-inline-start: var(--nx-head-mis);
  margin-inline-end: var(--nx-head-mie);
}

/* --------------------------------------------------------------------------
   19.6 As catorze seções

   "Cada seção deveria ter a opção no widget de pôr uma borda, um fundo, um
   efeito, algo para não ficar solto." Este é o grupo mais importante do
   painel, e é o único cujo conjunto de tokens escritos VARIA com o estado:
   core/theme.js emite `--nxs-<id>-*` só para as seções que o dono tocou, e
   guarda a lista para conseguir remover a que sair.

   Duas camadas: um bloco de MAPEAMENTO por seção, que traduz
   `--nxs-hero-bw` em `--nxs-bw` dentro do escopo de `#hero`, e um bloco de
   CONSUMO só, que não sabe de qual seção está falando. É o que evita
   catorze cópias das mesmas dez declarações.
   -------------------------------------------------------------------------- */
html[data-nx-sec~="header"] #header {
  --nxs-bw: var(--nxs-header-bw);
  --nxs-bc: var(--nxs-header-bc);
  --nxs-bg: var(--nxs-header-bg);
  --nxs-r: var(--nxs-header-r);
  --nxs-sh: var(--nxs-header-sh);
  --nxs-pat: var(--nxs-header-pat);
  --nxs-pats: var(--nxs-header-pats);
  --nxs-pato: var(--nxs-header-pato);
  --nxs-py: var(--nxs-header-py);
  --nxs-al: var(--nxs-header-al);
  --nxs-mis: var(--nxs-header-mis);
  --nxs-mie: var(--nxs-header-mie);
}

html[data-nx-sec~="hero"] #hero {
  --nxs-bw: var(--nxs-hero-bw);
  --nxs-bc: var(--nxs-hero-bc);
  --nxs-bg: var(--nxs-hero-bg);
  --nxs-r: var(--nxs-hero-r);
  --nxs-sh: var(--nxs-hero-sh);
  --nxs-pat: var(--nxs-hero-pat);
  --nxs-pats: var(--nxs-hero-pats);
  --nxs-pato: var(--nxs-hero-pato);
  --nxs-py: var(--nxs-hero-py);
  --nxs-al: var(--nxs-hero-al);
  --nxs-mis: var(--nxs-hero-mis);
  --nxs-mie: var(--nxs-hero-mie);
}

html[data-nx-sec~="provas"] #provas {
  --nxs-bw: var(--nxs-provas-bw);
  --nxs-bc: var(--nxs-provas-bc);
  --nxs-bg: var(--nxs-provas-bg);
  --nxs-r: var(--nxs-provas-r);
  --nxs-sh: var(--nxs-provas-sh);
  --nxs-pat: var(--nxs-provas-pat);
  --nxs-pats: var(--nxs-provas-pats);
  --nxs-pato: var(--nxs-provas-pato);
  --nxs-py: var(--nxs-provas-py);
  --nxs-al: var(--nxs-provas-al);
  --nxs-mis: var(--nxs-provas-mis);
  --nxs-mie: var(--nxs-provas-mie);
}

html[data-nx-sec~="tese"] #tese {
  --nxs-bw: var(--nxs-tese-bw);
  --nxs-bc: var(--nxs-tese-bc);
  --nxs-bg: var(--nxs-tese-bg);
  --nxs-r: var(--nxs-tese-r);
  --nxs-sh: var(--nxs-tese-sh);
  --nxs-pat: var(--nxs-tese-pat);
  --nxs-pats: var(--nxs-tese-pats);
  --nxs-pato: var(--nxs-tese-pato);
  --nxs-py: var(--nxs-tese-py);
  --nxs-al: var(--nxs-tese-al);
  --nxs-mis: var(--nxs-tese-mis);
  --nxs-mie: var(--nxs-tese-mie);
}

html[data-nx-sec~="capacidades"] #capacidades {
  --nxs-bw: var(--nxs-capacidades-bw);
  --nxs-bc: var(--nxs-capacidades-bc);
  --nxs-bg: var(--nxs-capacidades-bg);
  --nxs-r: var(--nxs-capacidades-r);
  --nxs-sh: var(--nxs-capacidades-sh);
  --nxs-pat: var(--nxs-capacidades-pat);
  --nxs-pats: var(--nxs-capacidades-pats);
  --nxs-pato: var(--nxs-capacidades-pato);
  --nxs-py: var(--nxs-capacidades-py);
  --nxs-al: var(--nxs-capacidades-al);
  --nxs-mis: var(--nxs-capacidades-mis);
  --nxs-mie: var(--nxs-capacidades-mie);
}

html[data-nx-sec~="metodo"] #metodo {
  --nxs-bw: var(--nxs-metodo-bw);
  --nxs-bc: var(--nxs-metodo-bc);
  --nxs-bg: var(--nxs-metodo-bg);
  --nxs-r: var(--nxs-metodo-r);
  --nxs-sh: var(--nxs-metodo-sh);
  --nxs-pat: var(--nxs-metodo-pat);
  --nxs-pats: var(--nxs-metodo-pats);
  --nxs-pato: var(--nxs-metodo-pato);
  --nxs-py: var(--nxs-metodo-py);
  --nxs-al: var(--nxs-metodo-al);
  --nxs-mis: var(--nxs-metodo-mis);
  --nxs-mie: var(--nxs-metodo-mie);
}

html[data-nx-sec~="cases"] #cases {
  --nxs-bw: var(--nxs-cases-bw);
  --nxs-bc: var(--nxs-cases-bc);
  --nxs-bg: var(--nxs-cases-bg);
  --nxs-r: var(--nxs-cases-r);
  --nxs-sh: var(--nxs-cases-sh);
  --nxs-pat: var(--nxs-cases-pat);
  --nxs-pats: var(--nxs-cases-pats);
  --nxs-pato: var(--nxs-cases-pato);
  --nxs-py: var(--nxs-cases-py);
  --nxs-al: var(--nxs-cases-al);
  --nxs-mis: var(--nxs-cases-mis);
  --nxs-mie: var(--nxs-cases-mie);
}

html[data-nx-sec~="modelos"] #modelos {
  --nxs-bw: var(--nxs-modelos-bw);
  --nxs-bc: var(--nxs-modelos-bc);
  --nxs-bg: var(--nxs-modelos-bg);
  --nxs-r: var(--nxs-modelos-r);
  --nxs-sh: var(--nxs-modelos-sh);
  --nxs-pat: var(--nxs-modelos-pat);
  --nxs-pats: var(--nxs-modelos-pats);
  --nxs-pato: var(--nxs-modelos-pato);
  --nxs-py: var(--nxs-modelos-py);
  --nxs-al: var(--nxs-modelos-al);
  --nxs-mis: var(--nxs-modelos-mis);
  --nxs-mie: var(--nxs-modelos-mie);
}

html[data-nx-sec~="portfolio"] #portfolio {
  --nxs-bw: var(--nxs-portfolio-bw);
  --nxs-bc: var(--nxs-portfolio-bc);
  --nxs-bg: var(--nxs-portfolio-bg);
  --nxs-r: var(--nxs-portfolio-r);
  --nxs-sh: var(--nxs-portfolio-sh);
  --nxs-pat: var(--nxs-portfolio-pat);
  --nxs-pats: var(--nxs-portfolio-pats);
  --nxs-pato: var(--nxs-portfolio-pato);
  --nxs-py: var(--nxs-portfolio-py);
  --nxs-al: var(--nxs-portfolio-al);
  --nxs-mis: var(--nxs-portfolio-mis);
  --nxs-mie: var(--nxs-portfolio-mie);
}

html[data-nx-sec~="govtech"] #govtech {
  --nxs-bw: var(--nxs-govtech-bw);
  --nxs-bc: var(--nxs-govtech-bc);
  --nxs-bg: var(--nxs-govtech-bg);
  --nxs-r: var(--nxs-govtech-r);
  --nxs-sh: var(--nxs-govtech-sh);
  --nxs-pat: var(--nxs-govtech-pat);
  --nxs-pats: var(--nxs-govtech-pats);
  --nxs-pato: var(--nxs-govtech-pato);
  --nxs-py: var(--nxs-govtech-py);
  --nxs-al: var(--nxs-govtech-al);
  --nxs-mis: var(--nxs-govtech-mis);
  --nxs-mie: var(--nxs-govtech-mie);
}

html[data-nx-sec~="confianca"] #confianca {
  --nxs-bw: var(--nxs-confianca-bw);
  --nxs-bc: var(--nxs-confianca-bc);
  --nxs-bg: var(--nxs-confianca-bg);
  --nxs-r: var(--nxs-confianca-r);
  --nxs-sh: var(--nxs-confianca-sh);
  --nxs-pat: var(--nxs-confianca-pat);
  --nxs-pats: var(--nxs-confianca-pats);
  --nxs-pato: var(--nxs-confianca-pato);
  --nxs-py: var(--nxs-confianca-py);
  --nxs-al: var(--nxs-confianca-al);
  --nxs-mis: var(--nxs-confianca-mis);
  --nxs-mie: var(--nxs-confianca-mie);
}

html[data-nx-sec~="contratacao"] #contratacao {
  --nxs-bw: var(--nxs-contratacao-bw);
  --nxs-bc: var(--nxs-contratacao-bc);
  --nxs-bg: var(--nxs-contratacao-bg);
  --nxs-r: var(--nxs-contratacao-r);
  --nxs-sh: var(--nxs-contratacao-sh);
  --nxs-pat: var(--nxs-contratacao-pat);
  --nxs-pats: var(--nxs-contratacao-pats);
  --nxs-pato: var(--nxs-contratacao-pato);
  --nxs-py: var(--nxs-contratacao-py);
  --nxs-al: var(--nxs-contratacao-al);
  --nxs-mis: var(--nxs-contratacao-mis);
  --nxs-mie: var(--nxs-contratacao-mie);
}

html[data-nx-sec~="contato"] #contato {
  --nxs-bw: var(--nxs-contato-bw);
  --nxs-bc: var(--nxs-contato-bc);
  --nxs-bg: var(--nxs-contato-bg);
  --nxs-r: var(--nxs-contato-r);
  --nxs-sh: var(--nxs-contato-sh);
  --nxs-pat: var(--nxs-contato-pat);
  --nxs-pats: var(--nxs-contato-pats);
  --nxs-pato: var(--nxs-contato-pato);
  --nxs-py: var(--nxs-contato-py);
  --nxs-al: var(--nxs-contato-al);
  --nxs-mis: var(--nxs-contato-mis);
  --nxs-mie: var(--nxs-contato-mie);
}

html[data-nx-sec~="footer"] #footer {
  --nxs-bw: var(--nxs-footer-bw);
  --nxs-bc: var(--nxs-footer-bc);
  --nxs-bg: var(--nxs-footer-bg);
  --nxs-r: var(--nxs-footer-r);
  --nxs-sh: var(--nxs-footer-sh);
  --nxs-pat: var(--nxs-footer-pat);
  --nxs-pats: var(--nxs-footer-pats);
  --nxs-pato: var(--nxs-footer-pato);
  --nxs-py: var(--nxs-footer-py);
  --nxs-al: var(--nxs-footer-al);
  --nxs-mis: var(--nxs-footer-mis);
  --nxs-mie: var(--nxs-footer-mie);
}
html[data-nx-sec] :is(#header, #hero, #provas, #tese, #capacidades, #metodo,
  #cases, #modelos, #portfolio, #govtech, #confianca, #contratacao,
  #contato, #footer) {
  border-style: solid;
  border-width: var(--nxs-bw, 0);
  border-color: var(--nxs-bc, transparent);
  border-radius: var(--nxs-r, 0);
  background-color: var(--nxs-bg, transparent);
  box-shadow: var(--nxs-sh, none);
  position: relative;
}

/* O padrão próprio da seção entra como pseudo-elemento, para não competir
   com o preenchimento nem com o que a folha da seção já pinta em
   `background-image`. Fica preso ao raio da seção e não recebe evento. */
html[data-nx-sec] :is(#header, #hero, #provas, #tese, #capacidades, #metodo,
  #cases, #modelos, #portfolio, #govtech, #confianca, #contratacao,
  #contato, #footer)::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  border-radius: inherit;
  background-image: var(--nxs-pat, none);
  background-size: var(--nxs-pats, auto);
  opacity: var(--nxs-pato, 0);
}

/* O conteúdo da seção fica acima da camada de padrão. */
html[data-nx-sec] :is(#hero, #provas, #tese, #capacidades, #metodo,
  #cases, #modelos, #portfolio, #govtech, #confianca, #contratacao,
  #contato, #footer) > * {
  position: relative;
  z-index: 1;
}

/* Respiro vertical: o cabeçalho fica de fora porque ele é `fixed` e a
   altura dele é assunto do grupo Menu. */
html[data-nx-sec] :is(#hero, #provas, #tese, #capacidades, #metodo,
  #cases, #modelos, #portfolio, #govtech, #confianca, #contratacao,
  #contato, #footer) {
  padding-block: var(--nxs-py, var(--section-y));
}

/* Alinhamento do cabeçalho, por seção. */
html[data-nx-sec] :is(#hero, #provas, #tese, #capacidades, #metodo,
  #cases, #modelos, #portfolio, #govtech, #confianca, #contratacao,
  #contato, #footer) .section__head {
  text-align: var(--nxs-al, start);
  justify-items: var(--nxs-al, start);
  margin-inline-start: var(--nxs-mis, 0);
  margin-inline-end: var(--nxs-mie, auto);
}

/* --------------------------------------------------------------------------
   19.7 Destaque do exemplo

   "Ao alterar, poderia mover a página no fundo até um local onde é alterado
   para ver mudando." O painel rola a página até a ocorrência mais próxima do
   componente que o controle governa e a marca por um instante.

   O destaque é `outline`, não `border` e não `box-shadow`: `outline` não
   ocupa espaço, então marcar um botão não empurra a linha em que ele está, e
   `outline-offset` dá o respiro sem tocar no layout. Ele desaparece sozinho;
   studio.js tira o atributo.
   -------------------------------------------------------------------------- */

[data-nx-alvo] {
  outline: 2px solid hsl(var(--ring));
  outline-offset: 4px;
  border-radius: inherit;
  animation: nx-alvo calc(var(--motion) * 1400ms) var(--ease-out) 1;
}

@keyframes nx-alvo {
  0%, 100% { outline-color: hsl(var(--ring) / 0); }
  12%, 70% { outline-color: hsl(var(--ring)); }
}

@media (prefers-reduced-motion: reduce) {
  [data-nx-alvo] { animation: none; }
}

/* ==========================================================================
   20. Agrupadores <details> da aba Seções (Seções 2.0, Lote C)

   A aba "Seções" (studio.js §9, sectionsHTML()) deixou de ser uma pilha só
   de controles: virou cinco agrupadores nativos <details>/<summary> —
   Layout, Disposição, Fundo, Moldura, Entrada — que crescem ou encolhem
   conforme o Lote A (theme.js: SEC_CAPS, os eixos por seção) tem ou não
   controle novo para mostrar. É o MESMO mecanismo de teclado de graça que
   o subgrupo "Avançado, token a token" da aba Cor já usava (§5 acima,
   `.nx-sub`), só que promovido a nível principal da aba: por isso ganha
   classe própria em vez de reaproveitar `.nx-sub`, que continua existindo
   sozinho ali. Todo o miolo de cada agrupador é fieldset/chip/slider/campo
   de cor de sempre — nada daqui pinta controle, só o chrome do <details>.

   "Só um aberto por vez" é regra do JS (studio.js, wireSecGroups(), evento
   `toggle`), não deste arquivo: aqui só o desenho do estado nativo
   `[open]`, e do estado `[hidden]` que marca "esta seção não tem este
   eixo" — ausência, nunca controle desabilitado (§4 do contrato).
   -------------------------------------------------------------------------- */

.nx-secgroup {
  border: var(--hairline) solid hsl(var(--border));
  border-radius: var(--radius-md);
  padding-inline: var(--space-4);
  transition: border-color calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

/* Aberto pesa mais que fechado: o dono navega cinco agrupadores para achar
   o que quer editar, e "qual está aberto agora" precisa ser óbvio de
   relance, não só pela seta virada (rodada de design de 5 de agosto). */
.nx-secgroup[open] {
  border-color: hsl(var(--input));
}

/* Igual a `.nx-tab[hidden]` alguns milhares de linhas acima: o atributo já
   basta sozinho (é o comportamento nativo do UA), a regra só documenta a
   intenção no mesmo estilo do resto do arquivo. */
.nx-secgroup[hidden] {
  display: none;
}

.nx-secgroup__sum {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-inline: calc(var(--space-2) * -1);
  padding-block: var(--space-3);
  padding-inline: var(--space-2);
  cursor: pointer;
  list-style: none;
  min-block-size: var(--tap-min);
  border-radius: var(--radius-sm);
  transition: background-color calc(var(--dur-fast) * var(--motion)) var(--ease-out);
}

.nx-secgroup__sum:hover {
  background-color: hsl(var(--accent));
}

.nx-secgroup__sum::-webkit-details-marker {
  display: none;
}

.nx-secgroup__label {
  flex: 1 1 auto;
  min-inline-size: 0;
  font-family: var(--font-body);
  font-weight: 650;
  font-size: var(--fs-sm);
  line-height: 1.2;
  color: hsl(var(--foreground));
}

/* `.nx-group__chev` já existe (§5, subgrupo "Avançado"): o giro de 180° ao
   abrir é o mesmo desenho, só casado com a classe nova do <summary>. Aberto,
   a seta também ganha a tinta cheia: fechado ela é --muted-foreground (herda
   de §5), aberto ela combina com o rótulo em --foreground. */
.nx-secgroup[open] > .nx-secgroup__sum .nx-group__chev {
  transform: rotate(180deg);
  color: hsl(var(--foreground));
}

.nx-secgroup[open] > .nx-secgroup__sum {
  border-block-end: var(--hairline) solid hsl(var(--border));
  margin-block-end: var(--space-1);
}

.nx-secgroup__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
  padding-block: var(--space-3) var(--space-4);
}

/* Mesma regra anti-estouro do §4 (grid filho nasce com min-width:auto).
   `.nx-secgroup__body` fica de fora daquela lista porque é classe nova
   deste lote — a guarda equivalente vive aqui, para o painel continuar sem
   rolagem horizontal em viewport nenhuma dentro dos agrupadores novos. */
.nx-secgroup__body > * {
  min-inline-size: 0;
}

/* ==========================================================================
   Motivo por item da aba Efeitos (2026-08-05, auditoria de toggles)

   Pedido do dono: nenhum interruptor pode voltar mudo. Quando um efeito não
   liga (falta biblioteca, sem alvo nesta página, ou a tentativa em runtime
   foi recusada por outro motivo), `montarCatalogo()` (studio.js) escreve
   esta linha logo abaixo do interruptor, associada a ele por
   `aria-describedby` — leitor de tela anuncia o motivo junto do controle,
   não só quem vê a tela. Mesmo token e escala do `.nx-hint` já usado no
   resto do painel (`--muted-foreground`, `--fs-xs`), para não inventar uma
   segunda receita de "texto subordinado" dentro do mesmo painel. */
.nx-fxitem__motivo {
  margin: 0;
  padding-inline-start: calc(var(--space-6) + var(--space-2));
  font-size: var(--fs-xs);
  line-height: 1.4;
  color: hsl(var(--muted-foreground));
}

/* O interruptor desabilitado (falta detectada ANTES do clique) fica cinza
   de verdade, não só sem cursor: `disabled` já tira a interação, mas o
   trilho/joelho herdavam a mesma pintura "ligável" do estado normal, sem
   nenhum sinal visual de que aquele efeito está fora de alcance agora. */
.nx-switch__input:disabled + .nx-switch__label {
  cursor: not-allowed;
  opacity: 0.55;
}

.nx-switch__input:disabled + .nx-switch__label .nx-switch__track {
  background-color: hsl(var(--muted));
}
