/* ============================================================
   app.css · componentes próprios do Etiquetada
   Construídos sobre os tokens do design system (ds-web.css).
   Aqui entra apenas o que o DS ainda não oferece: cabeçalho do
   app, banner de alerta, tabela, grade da galeria e balãozinho.
   ============================================================ */

@font-face {
  font-family: "Playfair Display";
  src: url("/ds/Web/fontes/PlayfairDisplay-VF.ttf") format("truetype-variations");
  font-weight: 400 900;
  font-display: swap;
}

/* Libera as transições de tamanho até palavras-chave como `auto`, que de
   outro modo não são interpoláveis — usado ao abrir a "Zona de perigo". */
:root {
  interpolate-size: allow-keywords;
}

/* ---- sobrescritas do design system ---- */

/* O select do DS reserva --space-9 (96px) à direita para o chevron;
   reduzimos para --space-7, dando mais espaço útil ao texto. Regra fora
   de @layer, então vence a do ds-web.css. */
.ds-select {
  padding: var(--space-3) var(--space-7) var(--space-3) var(--space-4);
}

/* ---- estrutura da página ---- */

.app-header {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  flex-wrap: wrap;
  padding: var(--space-4) var(--space-6);
  background: var(--surface-default);
  border-bottom: var(--border-width-hairline) solid var(--border-subtle);
}

.app-header__brand {
  display: inline-flex;
  border-radius: var(--radius-sm);
}

.app-header__logo {
  height: 40px;
  width: auto;
  user-select: none;
}

.app-header__title {
  font-family: var(--font-family-display);
  font-weight: var(--font-weight-medium);
  font-size: var(--font-display-sm-font-size);
  color: var(--text-primary);
}

.app-header__actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-left: auto;
  flex-wrap: wrap;
}

/* ---- menu hamburguer ---- */

.app-menu {
  position: relative;
}

.app-menu__panel {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  z-index: var(--z-dropdown);
  width: max-content;
  padding: var(--space-2);
  background: var(--surface-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md-offset-x) var(--shadow-md-offset-y) var(--shadow-md-blur)
    var(--shadow-md-spread) var(--shadow-md-color);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.app-menu__item {
  text-align: left;
  padding: var(--space-3) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-size: var(--font-body-md-font-size);
  text-decoration: none;
  cursor: pointer;
}

.app-menu__item:hover {
  background: var(--surface-canvas);
}

/* Entrada das telas, como o design system pede em motion.social.entradaDeTexto:
   "fade + deslize sutil de baixo para cima (~24px), duração base, easing
   editorial". As etiquetas ficam de fora — usam .label-page. */
@keyframes app-entrada {
  from {
    opacity: 0;
    transform: translateY(24px);
  }
}

.app-main {
  max-width: var(--container-max-width);
  margin: 0 auto;
  padding: var(--space-5) var(--space-6) var(--space-8);
  animation: app-entrada var(--duration-base) var(--easing-editorial);
}

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

.app-toolbar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
  flex-wrap: wrap;
}

.app-toolbar--start {
  justify-content: flex-start;
}

/* Barra de busca com o ícone de busca do design system à esquerda. */
.app-search {
  position: relative;
  width: 100%;
  max-width: 480px;
}

.app-search__icon {
  position: absolute;
  left: var(--space-4);
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-secondary);
  pointer-events: none;
}

.app-search .ds-input {
  padding-left: calc(var(--space-4) + 18px + var(--space-2));
}

/* ---- banner de estado da sincronização (RF-06.1) ---- */

.app-banner {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-6);
  font-size: var(--font-body-md-font-size);
}

.app-banner--warning {
  background: color-mix(in srgb, var(--state-warning-default) 12%, var(--surface-default));
  color: var(--state-warning-default);
  border-bottom: var(--border-width-thin) solid
    color-mix(in srgb, var(--state-warning-default) 35%, transparent);
}

.app-banner--info {
  background: color-mix(in srgb, var(--state-info-default) 8%, var(--surface-default));
  color: var(--state-info-default);
}

.app-banner__note {
  color: var(--text-secondary);
  font-size: var(--font-body-sm-font-size);
}

.app-banner__admin {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  white-space: nowrap;
}

.app-banner__dismiss {
  margin-left: auto;
  display: flex;
  padding: var(--space-1);
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: inherit;
  cursor: pointer;
  opacity: 0.7;
}

/* Depois do bloco de admin, que já empurrou tudo para a direita: um segundo
   `auto` deixaria o admin no meio da sobra. */
.app-banner__admin + .app-banner__dismiss {
  margin-left: 0;
}

.app-banner__dismiss:hover {
  opacity: 1;
}

/* ---- tabela de produtos ---- */

.app-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--surface-default);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.app-table th {
  text-align: left;
  font-family: var(--font-heading-sm-font-family);
  font-weight: var(--font-heading-sm-font-weight);
  font-size: var(--font-body-sm-font-size);
  letter-spacing: var(--font-heading-sm-letter-spacing);
  text-transform: uppercase;
  color: var(--text-secondary);
  padding: var(--space-3) var(--space-4);
  position: sticky;
  top: 0;
  background: var(--surface-default);
}

.app-table td {
  padding: var(--space-2) var(--space-4);
  border-top: var(--border-width-hairline) solid var(--border-subtle);
  vertical-align: middle;
}

.app-table tbody tr:hover {
  background: var(--surface-canvas);
}

.app-table .nowrap {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* A coluna da miniatura encolhe até o conteúdo: `width: 1%` faz a tabela
   dar a ela o mínimo e distribuir o resto entre as outras. Vale também para
   a linha fantasma: sem isso a coluna mudaria de largura ao carregar. */
.app-table td:has(.app-table__thumb),
.app-table td:has(.ds-skeleton--circle) {
  width: 1%;
}

/* A caixa de seleção e a miniatura têm tamanho fixo, então as colunas delas
   também: deixadas ao algoritmo da tabela, elas ficavam com a sobra e a
   linha fantasma — que não tem caixa nenhuma — saía desalinhada das reais. */
.app-table__col--check {
  width: calc(20px + 2 * var(--space-4));
}

.app-table__col--thumb {
  width: calc(44px + 2 * var(--space-4));
}

/* Linha fantasma não é clicável: o realce de hover prometeria interação. */
.app-table__skeleton:hover {
  background: none;
}

/* O círculo do design system tem 40px; a miniatura, 44. Sem igualar, a
   coluna mudaria de largura no instante em que a lista chega. */
.app-table__skeleton .ds-skeleton--circle {
  inline-size: 44px;
  block-size: 44px;
}

.app-table__thumb {
  /* Tamanho travado: a miniatura nunca estica nem encolhe com o conteúdo. */
  width: 44px;
  height: 44px;
  min-width: 44px;
  min-height: 44px;
  max-width: 44px;
  max-height: 44px;
  object-fit: contain;
  background: var(--surface-default);
  user-select: none;
}

.app-table__link {
  color: var(--link-default);
  cursor: pointer;
  font-weight: var(--font-weight-semibold);
}

.app-table__link:hover {
  color: var(--link-hover);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.app-table__actions {
  display: flex;
  gap: var(--space-2);
  justify-content: flex-end;
}

/* Ação destrutiva: variante do botão secundário na cor de erro. */
.ds-botao--secundario.app-button--danger {
  --_text: var(--state-error-default);
  --_border: var(--state-error-default);
  --_bg-hover: var(--state-error-default);
  --_bg-active: var(--state-error-default);
}

/* Ação destrutiva primária (confirmação do diálogo): preenchida em erro. */
.ds-botao.app-button--danger-solid {
  --_bg: var(--state-error-default);
  --_bg-hover: var(--state-error-default);
  --_bg-active: var(--state-error-default);
}

/* ---- diálogos ---- */

.app-dialog {
  /* O reset do DS zera todas as margens; o margin auto do <dialog>
     nativo é o que o centraliza no viewport — restaurado aqui. */
  margin: auto;
  border: none;
  border-radius: var(--radius-lg);
  background: var(--surface-default);
  color: var(--text-primary);
  padding: var(--space-6);
  max-width: 420px;
  width: calc(100vw - 2 * var(--space-6));
  box-shadow: var(--shadow-lg-offset-x) var(--shadow-lg-offset-y) var(--shadow-lg-blur)
    var(--shadow-lg-spread) var(--shadow-lg-color);

  /* Entrada e saída animadas. `allow-discrete` nas propriedades discretas
     (display e overlay) é o que mantém o diálogo visível durante a saída —
     sem isso o display: none corta a animação de fechamento. */
  opacity: 0;
  transform: scale(0.95);
  transition:
    opacity var(--duration-fast) var(--easing-default),
    transform var(--duration-fast) var(--easing-default),
    overlay var(--duration-fast) var(--easing-default) allow-discrete,
    display var(--duration-fast) var(--easing-default) allow-discrete;
}

.app-dialog[open] {
  opacity: 1;
  transform: scale(1);
}

/* Estado de onde a entrada parte. */
@starting-style {
  .app-dialog[open] {
    opacity: 0;
    transform: scale(0.95);
  }
}

/* Diálogo largo (formulário de cadastro): comporta o grid de dois campos
   e rola internamente quando não cabe na altura da tela. */
.app-dialog--wide {
  max-width: 540px;
  max-height: calc(100vh - 2 * var(--space-6));
  overflow-y: auto;
}

/* Diálogo de filtros: um pouco mais largo que o padrão para as regras. */
.app-dialog--filters {
  max-width: 480px;
}

.app-dialog::backdrop {
  background: rgb(0 0 0 / 0);
  transition:
    background var(--duration-fast) var(--easing-default),
    overlay var(--duration-fast) var(--easing-default) allow-discrete,
    display var(--duration-fast) var(--easing-default) allow-discrete;
}

.app-dialog[open]::backdrop {
  background: rgb(0 0 0 / var(--opacity-overlay-medium, 0.5));
}

@starting-style {
  .app-dialog[open]::backdrop {
    background: rgb(0 0 0 / 0);
  }
}

/* Com um diálogo aberto, a página de trás não rola: sem isso, a roda do
   mouse continua rolando o conteúdo por baixo do modal. O gutter reservado
   mantém o espaço da barra mesmo quando ela some ao travar, evitando que o
   conteúdo salte para o lado — só nas páginas que têm diálogo, para as de
   etiqueta não reservarem espaço à toa. */
html:has(dialog) {
  scrollbar-gutter: stable;
}

html:has(dialog[open]) {
  overflow: hidden;
}

/* Ação destrutiva no rodapé do diálogo: fica oposta às demais. */
.app-dialog__actions .app-button--pull-left {
  margin-right: auto;
}

.app-dialog__title {
  font-family: var(--font-family-display);
  font-weight: var(--font-weight-medium);
  font-size: var(--font-display-sm-font-size);
  margin-bottom: var(--space-3);
}

.app-dialog__message {
  color: var(--text-secondary);
  margin-bottom: var(--space-2);
}

.app-dialog__detail {
  font-weight: var(--font-weight-semibold);
  margin-bottom: var(--space-2);
  overflow-wrap: anywhere;
}

/* Palavra digitada que libera uma ação sem volta. */
.app-dialog__challenge {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: var(--space-4) 0;
}

.app-dialog__actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  margin-top: var(--space-5);
}

/* Formulário dentro de diálogo: campos sempre empilhados. */
.app-dialog__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* Linha recém-editada: flash de destaque ao voltar do formulário. */
@keyframes app-row-highlight {
  0%, 60% {
    background-color: color-mix(in srgb, var(--state-warning-default) 22%, var(--surface-default));
  }
}

.app-table tbody tr.highlight {
  animation: app-row-highlight 4s var(--easing-default);
}

/* ---- página de sincronização ---- */

.sync-toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-bottom: var(--space-5);
  padding: var(--space-4);
  background: var(--surface-default);
  border-radius: var(--radius-md);
}

/* Antes da primeira busca o resumo não tem texto, mas o `gap` continua
   contando e desloca a linha do centro. */
.sync-toolbar > :empty {
  display: none;
}

/* As ações sobre o que já existe no app ficam na ponta, longe do fluxo
   principal de buscar e importar. */
.sync-toolbar__end {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

/* Abaixo desta largura os botões não cabem ao lado da busca e dos filtros.
   O `flex-basis` os manda para uma linha inteira só deles; a barra toda
   passa a centralizar, para as duas linhas ficarem no mesmo eixo. */
@media (max-width: 1207px) {
  .sync-toolbar {
    justify-content: center;
  }

  .sync-toolbar__end {
    margin-left: 0;
    flex-basis: 100%;
    justify-content: center;
  }
}

.sync-option {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

/* ---- ilha de importação ---- */

/* Espaço no fim da lista para a ilha não cobrir as últimas linhas. */
.import-main {
  padding-bottom: var(--space-9);
}

.import-island {
  position: fixed;
  bottom: var(--space-5);
  /* Centraliza sem transform, que fica reservado para a animação. */
  left: 0;
  right: 0;
  width: max-content;
  margin-inline: auto;
  z-index: var(--z-sticky);
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-3) var(--space-3) var(--space-5);
  background: var(--surface-default);
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-lg-offset-x) var(--shadow-lg-offset-y) var(--shadow-lg-blur)
    var(--shadow-lg-spread) var(--shadow-lg-color);
  transition:
    opacity var(--duration-fast) var(--easing-default),
    transform var(--duration-fast) var(--easing-default),
    visibility var(--duration-fast) var(--easing-default);
}

/* Sem nada selecionado a ilha desce e sai: não há o que importar. */
.import-island--oculta {
  opacity: 0;
  visibility: hidden;
  transform: translateY(150%);
}

.import-island__count {
  font-weight: var(--font-weight-semibold);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.progress-bar {
  margin-top: var(--space-3);
}

.progress-label {
  margin-top: var(--space-3);
  margin-bottom: 10px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
}

/* Resultado da importação: rótulo à esquerda, contagem à direita. */
.result-list {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--space-2) var(--space-4);
}

.result-list dd {
  text-align: right;
  font-weight: var(--font-weight-semibold);
  font-variant-numeric: tabular-nums;
}

/* Grupo de filtros (toggles) dentro do diálogo de filtros. */
.filters-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.sync-badge {
  display: inline-block;
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--font-body-sm-font-size);
  font-weight: var(--font-weight-semibold);
  white-space: nowrap;
}

.sync-badge--imported {
  color: var(--state-success-default);
  background: color-mix(in srgb, var(--state-success-default) 10%, transparent);
}

.sync-badge--existing {
  color: var(--state-warning-default);
  background: color-mix(in srgb, var(--state-warning-default) 12%, transparent);
}

.sync-badge--new {
  color: var(--state-info-default);
  background: color-mix(in srgb, var(--state-info-default) 10%, transparent);
}

/* ---- diálogo de configurações ---- */

.settings-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  align-items: flex-start;
  margin-bottom: var(--space-4);
}

.settings-section__subtitle {
  font-weight: var(--font-weight-semibold);
}

/* O divisor do design system vem sem margem: dentro do diálogo ele separa
   blocos de assunto e precisa de ar dos dois lados. */
.app-dialog .ds-divisor {
  margin-block: var(--space-3);
}

/* Excluir tudo não tem volta: fica recolhido, para não ficar à mão junto
   das opções do dia a dia. */
.settings-danger__summary {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
  font-weight: var(--font-weight-semibold);
  color: var(--state-error-default);
  border-radius: var(--radius-sm);
  /* A seta do design system substitui o triângulo nativo do <details>. */
  list-style: none;
}

.settings-danger__summary::-webkit-details-marker {
  display: none;
}

.settings-danger__chevron {
  transition: transform var(--duration-fast) var(--easing-default);
}

/* Recolhido aponta para a direita; aberto, para baixo — o giro de 90° leva
   um ícone ao outro, e o design system oferece os dois. */
.settings-danger[open] .settings-danger__chevron {
  transform: rotate(90deg);
}

/* Abertura e fechamento animados. `::details-content` é o conteúdo que o
   <details> esconde, e `allow-discrete` no content-visibility é o que o
   mantém visível durante o fechamento — sem isso ele sumiria de uma vez,
   cortando a animação. A altura vai a `auto` graças ao interpolate-size
   declarado no :root, sem o qual ela não seria interpolável. */
.settings-danger::details-content {
  block-size: 0;
  opacity: 0;
  /* `clip` e não `hidden`: hidden faria do conteúdo um container de
     rolagem, e uma barra apareceria no meio da animação. */
  overflow: clip;
  transition:
    block-size var(--duration-fast) var(--easing-default),
    opacity var(--duration-fast) var(--easing-default),
    content-visibility var(--duration-fast) var(--easing-default) allow-discrete;
}

.settings-danger[open]::details-content {
  block-size: auto;
  opacity: 1;
}

.settings-danger__summary:focus-visible {
  outline: var(--border-width-medium) solid var(--state-error-default);
  outline-offset: var(--space-1);
}

.settings-danger[open] .settings-danger__summary {
  margin-bottom: var(--space-3);
}

/* ---- listas vazias ---- */

/* Uma lista sem nenhum item some da tela e parece não existir. */
[data-empty]:empty::before,
.app-table__empty td,
.gallery-empty {
  padding: var(--space-4);
  text-align: center;
  color: var(--text-secondary);
  font-size: var(--font-body-sm-font-size);
}

/* O ::before nasce inline e não aceitaria o padding vertical. A célula da
   tabela fica de fora: `display: block` num <td> o tira do layout de
   tabela, e o colspan deixa de valer — o aviso ocuparia uma coluna só. */
[data-empty]:empty::before,
.gallery-empty {
  display: block;
}

/* Nas listas sem filtro, o aviso vem do atributo `data-empty` da própria
   lista e aparece só enquanto ela não tem filhos — some e volta sozinho,
   sem depender do JS de quem a preenche. */
[data-empty]:empty::before {
  content: attr(data-empty);
}

/* Já as listas com filtro (importação, galeria) montam o aviso no JS: elas
   continuam com filhos quando o filtro esconde todos, e `:empty` não veria
   que a tela está vazia. */
.gallery-empty {
  grid-column: 1 / -1;
}

/* O ícone do menu entra no meio da frase, para a pessoa procurar na tela o
   mesmo desenho que está lendo. */
.app-table__empty-hint {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

.settings-rules {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  width: 100%;
  margin: var(--space-3) 0;
  /* Lista longa rola dentro de si; o overscroll impede que o fim do scroll
     continue na página de trás. O padding de 2px evita que o overflow corte
     o anel de foco, e o da direita afasta as ações da barra de rolagem. */
  max-height: 250px;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 2px;
  padding-right: var(--space-3);
}

.rule-row {
  display: grid;
  grid-template-columns: 180px 1fr auto;
  gap: var(--space-2);
  align-items: center;
}

/* ---- galeria de line-arts ---- */

/* A busca fica no centro da página e com a mesma largura da tela principal;
   o botão ocupa a coluna da direita sem deslocá-la do centro. */
.gallery-panel {
  display: grid;
  grid-template-columns: 1fr minmax(0, 480px) 1fr;
  align-items: center;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
}

.gallery-panel .app-search {
  grid-column: 2;
}

.gallery-panel__add {
  grid-column: 3;
  justify-self: end;
}

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: var(--space-4);
}

/* O card inteiro abre a edição, então é um botão: o reset devolve a
   aparência de card que o <button> traz do navegador. */
.gallery-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  align-items: center;
  border: 0;
  font: inherit;
  color: inherit;
  text-align: center;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--duration-fast) var(--easing-default);
}

.gallery-card:hover {
  box-shadow: var(--shadow-md);
}

.gallery-card:focus-visible {
  outline: var(--border-width-medium) solid var(--accent);
  outline-offset: var(--space-1);
}

.gallery-card img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: contain;
}

/* Card fantasma: a mesma caixa do card real, sem o cursor e a sombra que
   prometeriam clique. */
.gallery-skeleton {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  align-items: center;
}

/* O ds-skeleton nasce com 16px de altura; aqui ele ocupa o lugar da imagem. */
.gallery-skeleton__image {
  aspect-ratio: 1;
  block-size: auto;
}

/* Uma linha de texto, que é o que o nome do card ocupa: `1lh` acompanha o
   line-height em vez de fixar um número que sairia de sincronia. */
.gallery-skeleton__name {
  block-size: 1lh;
}

.gallery-card__name {
  font-weight: var(--font-weight-semibold);
  font-variant-numeric: tabular-nums;
}

/* ---- sobre ---- */

.about__version {
  color: var(--text-secondary);
  margin-bottom: var(--space-3);
}

.about__subtitle {
  font-weight: var(--font-weight-semibold);
  margin-top: var(--space-5);
  margin-bottom: var(--space-2);
}

.about__person {
  margin-bottom: var(--space-3);
}

.about__role {
  color: var(--text-secondary);
  font-size: var(--font-body-sm-font-size);
}

.about__copyright {
  margin-top: var(--space-5);
  color: var(--text-secondary);
  font-size: var(--font-body-sm-font-size);
}

/* ---- ajuda ---- */

/* Os chips seguem a mesma coluna do texto: soltos na largura da página,
   pareceriam de outro lugar. */
.help-filters,
.help {
  max-width: 720px;
  margin-inline: auto;
}

.help-filters {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
  margin-bottom: var(--space-5);
}

.help-section {
  margin-bottom: var(--space-6);
}

.help-section__title {
  font-family: var(--font-family-display);
  font-weight: var(--font-weight-medium);
  font-size: var(--font-display-sm-font-size);
  padding-bottom: var(--space-2);
  border-bottom: var(--border-width-hairline) solid var(--border-subtle);
  margin-bottom: var(--space-4);
}

.help-item {
  margin-bottom: var(--space-4);
}

.help-item__question {
  font-weight: var(--font-weight-semibold);
  margin-bottom: var(--space-1);
}

.help-item__answer {
  color: var(--text-secondary);
}

/* ---- formulário de produto ---- */

.product-form {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-4);
}

.product-form__full {
  grid-column: 1 / -1;
}

.image-preview {
  width: 96px;
  height: 96px;
  object-fit: contain;
  background: var(--surface-canvas);
  border-radius: var(--radius-sm);
}

/* ---- balãozinho e botão de informação (RF-07.3/07.4) ---- */

.info-button {
  cursor: help;
  border: none;
  background: none;
  font-size: var(--font-body-md-font-size);
  line-height: 1;
}

.balloon {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--state-warning-default) 12%, var(--surface-default));
  color: var(--state-warning-default);
  font-size: var(--font-body-sm-font-size);
  max-width: 480px;
}

[hidden] {
  display: none !important;
}
