/* ==========================================================================
   DESIGN SYSTEM — MI7 GRUPO  v2.0
   style.css
   01. Reset & Base
   02. Variáveis / Temas (Light / Dark)
   03. Layout — App Shell
   04. Sidebar — Hamburger, Nav Groups, Submenus
   05. Header & Footer
   06. Componentes — Botões
   07. Componentes — Badges
   08. Componentes — Formulários (Input, Checkbox, Custom-Select, Multi-Select)
   09. Componentes — Filtros (Accordion, Active-Bar, Side-Drawer, Preset Panel)
   10. Componentes — Tabela (Normal / Compact / Dense)
   11. Componentes — Cards / Dashboard
   12. Componentes — Code Block
   13. Utilitários / Skeleton / Misc
   14. Responsividade
   ========================================================================== */

/* ==========================================================================
   01. RESET & BASE
   ========================================================================== */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
html {
  font-size: 16px;
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--font-family-base);
  font-size: 0.875rem;
  line-height: 1.6;
  background: var(--color-bg-base);
  color: var(--color-text-primary);
  transition:
    background-color 0.3s ease,
    color 0.3s ease;
  overflow: hidden;
}

a {
  color: var(--color-accent);
  text-decoration: none;
}
ul,
ol {
  list-style: none;
}
button {
  font-family: inherit;
  cursor: pointer;
  border: none;
  background: none;
}
input,
select,
textarea {
  font-family: inherit;
  font-size: inherit;
}
img,
svg {
  display: block;
  max-width: 100%;
}
/* O atributo `hidden` SEMPRE oculta — vence regras de componente que definem
   `display` (ex.: .info-banner, .master-detail__panel/__placeholder, dropdowns).
   Sem isso, toggles via `el.hidden = true/false` não funcionam nesses
   componentes (placeholder e painel apareciam juntos no master-detail). */
[hidden] {
  display: none !important;
}

/* ==========================================================================
   FONTES DO DESIGN SYSTEM — DM Sans (texto) + DM Mono (números/labels),
   ambas OFL, auto-hospedadas em ../fonts/ (sem CDN externo). Licenças em
   ../fonts/OFL-DMSans.txt e OFL-DMMono.txt.
   ========================================================================== */
@font-face {
  font-family: "DM Sans";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("../fonts/dmsans-300.342395bd2664.woff2") format("woff2");
}
@font-face {
  font-family: "DM Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/dmsans-400.a220a32881ae.woff2") format("woff2");
}
@font-face {
  font-family: "DM Sans";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/dmsans-500.aa952242481d.woff2") format("woff2");
}
@font-face {
  font-family: "DM Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/dmsans-600.c64569e0302e.woff2") format("woff2");
}
@font-face {
  font-family: "DM Sans";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/dmsans-700.9508ec8af518.woff2") format("woff2");
}
@font-face {
  font-family: "DM Mono";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("../fonts/dmmono-300.759da6a18725.woff2") format("woff2");
}
@font-face {
  font-family: "DM Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/dmmono-400.e1ed461ac183.woff2") format("woff2");
}
@font-face {
  font-family: "DM Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/dmmono-500.c4598219c4b8.woff2") format("woff2");
}

/* ==========================================================================
   02. VARIÁVEIS — TEMA LIGHT
   ========================================================================== */
:root {
  /* Fundos (tema light) */
  --color-bg-base: #f2f4f8;
  --color-bg-content: var(--color-bg-base);
  --color-bg-surface: #ffffff;
  --color-bg-surface-alt: #f7f9fc; /* elevated */
  /* Superfície rebaixada, tirada da superfície da paleta: acompanha
     `--color-bg-surface` e a cor de texto que o tenant define. */
  --color-bg-overlay: color-mix(in srgb, var(--color-bg-surface) 93%, var(--color-text-primary));
  --color-bg-sidebar: #ffffff;
  --color-bg-header: #ffffff;
  --color-bg-input: #f7f9fc;
  --color-bg-hover: rgba(21, 24, 40, 0.04);

  /* Textos */
  --color-text-primary: #151828;
  --color-text-secondary: rgba(21, 24, 40, 0.58);
  --color-text-muted: rgba(21, 24, 40, 0.38);
  --color-text-inverse: #ffffff;
  --color-text-sidebar: rgba(21, 24, 40, 0.58);
  --color-text-sidebar-active: #151828;

  /* Acento da marca = VERDE-LIMA (ação primária, foco, ativos, links).
     No light usa o lima escuro #9db020 para contraste sobre branco. */
  --color-accent: #9db020;
  --color-accent-hover: #c0d52a; /* hover mais vivo */
  --color-accent-dark: #7a8a10; /* texto de acento legível sobre -light */
  --color-accent-light: rgba(157, 176, 32, 0.12); /* fundo tonal (dim) */
  --color-accent-rgb: 157, 176, 32;
  --color-text-on-accent: #0e1120; /* texto sobre botão lima */

  /* Azul-céu — cor secundária de apoio. */
  --color-sky: #3787a8;
  --color-sky-dim: rgba(55, 135, 168, 0.12);

  /* Marca institucional (logo) — estável entre temas. */
  --color-brand-green: #c0d52a;
  --color-brand-navy: #151828;
  --color-brand-sky: #51a3c8;
  --color-brand-green-rgb: 192, 213, 42;
  --gradient-brand: linear-gradient(
    135deg,
    var(--color-brand-green) 0%,
    var(--color-brand-sky) 100%
  );

  /* Fonte mono — números, labels técnicos, cabeçalhos de tabela. */
  --font-mono: "DM Mono", ui-monospace, "Cascadia Code", "Consolas", monospace;

  /* Semânticas (tons suaves da referência). -light é o fundo tonal (dim);
     -text é a cor do texto/ícone sobre esse fundo (= a própria cor). */
  --color-success: #2da870;
  --color-success-light: rgba(45, 168, 112, 0.1);
  --color-success-text: var(--color-success);
  --color-warning: #c8851a;
  --color-warning-light: rgba(200, 133, 26, 0.1);
  --color-warning-text: var(--color-warning);
  --color-danger: #c94545;
  --color-danger-light: rgba(201, 69, 69, 0.1);
  --color-danger-text: var(--color-danger);
  --color-info: #3787a8;
  --color-info-light: rgba(55, 135, 168, 0.1);
  --color-info-text: var(--color-info);

  /* Bordas */
  --color-border: rgba(21, 24, 40, 0.1);
  --color-border-strong: rgba(21, 24, 40, 0.2);
  --color-border-accent: rgba(157, 176, 32, 0.4);
  --color-border-focus: var(--color-accent);

  /* Sombras */
  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.06);
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08);
  --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.1);
  --shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.12);
  --shadow-accent: 0 0 24px rgba(157, 176, 32, 0.15);
  --shadow-focus: 0 0 0 3px rgba(var(--color-accent-rgb), 0.25);

  /* Dimensões */
  --sidebar-expanded: 240px;
  --sidebar-collapsed: 64px;
  --header-height: 60px;
  --footer-height: 44px;
  /* Altura única de todo controle de toolbar/formulário: `.btn--sm`,
     `.form-input` e `.custom-select__trigger`. Os três precisam bater para a
     barra ficar alinhada, e este token é o único lugar onde a altura deles é
     definida — mexer aqui move os três. */
  --control-height: 32px;
  /* Altura fixa do resumo de filtros grudado (`.filter-toolbar.is-condensed`,
     seção 09): é dela que sai o `top` extra do controle segmentado e do
     cabeçalho da tabela quando o resumo está visível (ver seção SEGMENTED). */
  --ds-sticky-summary-h: 48px;

  /* Radii */
  --radius-xs: 4px;
  --radius-sm: 6px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-xl: 16px;
  --radius-full: 9999px;

  /* Tipografia */
  --font-family-base: "DM Sans", system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
  --font-xs: 0.75rem;
  --font-sm: 0.8125rem;
  --font-base: 0.875rem;
  --font-md: 1rem;
  --font-lg: 1.125rem;
  --font-xl: 1.25rem;

  /* Transições */
  --t-fast: 150ms ease;
  --t-base: 250ms ease;
  --t-slow: 350ms cubic-bezier(0.4, 0, 0.2, 1);

  /* Z-Index */
  --z-sidebar: 100;
  --z-header: 200;
  --z-overlay: 290;
  --z-drawer: 300;
  --z-modal: 350;
  --z-tooltip: 400;
  --z-image-viewer: 500;

  /* Overlay para modais/drawers — uso obrigatório em qualquer fundo de
     dialog full-screen para que componentes futuros do DS herdem a
     mesma opacidade/tom (rule design-system-frontend §"Nenhuma cor
     hex/rgb fora de var(--color-*)"). Tema dark redefine abaixo para
     manter contraste sobre fundos já escuros. */
  --color-overlay: rgba(10, 12, 22, 0.55);
}

/* --- TEMA DARK (paleta da referência MI7) --- */
[data-theme="dark"] {
  --color-bg-base: #0e1120;
  --color-bg-content: var(--color-bg-base);
  --color-bg-surface: #151828;
  --color-bg-surface-alt: #1c2236; /* elevated */
  --color-bg-sidebar: #151828;
  --color-bg-header: #151828;
  --color-bg-input: #1c2236;
  --color-bg-hover: rgba(192, 213, 42, 0.06);

  --color-text-primary: #eef0f8;
  --color-text-secondary: rgba(238, 240, 248, 0.55);
  --color-text-muted: rgba(238, 240, 248, 0.3);
  --color-text-sidebar: rgba(238, 240, 248, 0.55);
  --color-text-sidebar-active: #eef0f8;

  /* Acento lima — vivo sobre o escuro. */
  --color-accent: #c0d52a;
  --color-accent-hover: #d4ea3a;
  --color-accent-dark: #c0d52a;
  --color-accent-light: rgba(192, 213, 42, 0.15);
  --color-accent-rgb: 192, 213, 42;
  --color-text-on-accent: #0e1120;

  --color-sky: #51a3c8;
  --color-sky-dim: rgba(81, 163, 200, 0.15);

  --color-success: #4ec994;
  --color-success-light: rgba(78, 201, 148, 0.15);
  --color-warning: #e8a838;
  --color-warning-light: rgba(232, 168, 56, 0.15);
  --color-danger: #e05757;
  --color-danger-light: rgba(224, 87, 87, 0.15);
  --color-info: #51a3c8;
  --color-info-light: rgba(81, 163, 200, 0.15);

  --color-border: rgba(255, 255, 255, 0.08);
  --color-border-strong: rgba(255, 255, 255, 0.15);
  --color-border-accent: rgba(192, 213, 42, 0.35);

  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4);
  --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.5);
  --shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.6);
  --shadow-accent: 0 0 24px rgba(192, 213, 42, 0.2);

  --color-overlay: rgba(10, 12, 22, 0.72);
}

/* ==========================================================================
   03. LAYOUT — APP SHELL
   ========================================================================== */
.app-shell {
  display: flex;
  height: 100dvh;
  overflow: hidden;
}

.main-column {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-width: 0;
}

.main-content {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  background: var(--color-bg-content);
  /* Top reduzido p/ aproveitar a área útil (título mais alto); laterais e
     base mantêm 24px. */
  padding: 16px 24px 24px;
  scrollbar-width: thin;
  scrollbar-color: var(--color-border) transparent;
}
.main-content::-webkit-scrollbar {
  width: 6px;
}
.main-content::-webkit-scrollbar-thumb {
  background: var(--color-border);
  border-radius: 4px;
}
.main-content::-webkit-scrollbar-thumb:hover {
  background: var(--color-text-muted);
}

/* ==========================================================================
   04. SIDEBAR
   ========================================================================== */
.sidebar {
  width: var(--sidebar-expanded);
  min-width: var(--sidebar-expanded);
  background: var(--color-bg-sidebar);
  border-right: 1px solid var(--color-border);
  display: flex;
  flex-direction: column;
  transition:
    width var(--t-slow),
    min-width var(--t-slow),
    background var(--t-slow);
  overflow: hidden;
  position: relative;
  z-index: var(--z-sidebar);
  flex-shrink: 0;
}
.sidebar.is-collapsed {
  width: var(--sidebar-collapsed);
  min-width: var(--sidebar-collapsed);
}

/* --- Logo --- */
.sidebar__logo {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  padding: 10px 18px;
  min-height: var(--header-height);
  border-bottom: 1px solid var(--color-border);
  flex-shrink: 0;
  overflow: hidden;
}
.sidebar__logo-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.sidebar__logo-subtitle {
  font-size: var(--font-xs);
  color: var(--color-text-muted);
  white-space: nowrap;
  padding-left: 40px; /* alinha com o texto do logo, após o ícone/imagem */
  transition: opacity var(--t-base);
}
.sidebar.is-collapsed .sidebar__logo-subtitle {
  opacity: 0;
  pointer-events: none;
}
.sidebar__logo-icon {
  /* Símbolo circular — o SVG inline faz o ring com centro transparente */
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  object-fit: contain;
}
.sidebar__logo-text {
  font-size: var(--font-md);
  font-weight: 700;
  letter-spacing: -0.02em;
  white-space: nowrap;
  opacity: 1;
  color: var(--color-text-primary);
  transition: opacity var(--t-base);
}
.sidebar__logo-text span {
  color: var(--color-accent);
}
.sidebar.is-collapsed .sidebar__logo-text {
  opacity: 0;
  pointer-events: none;
}
/* --- Navegação --- */
.sidebar__nav {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 10px 0 16px;
  scrollbar-width: thin;
  scrollbar-color: var(--color-border-strong) transparent;
}
.sidebar__nav::-webkit-scrollbar {
  width: 4px;
}
.sidebar__nav::-webkit-scrollbar-thumb {
  background: var(--color-border-strong);
  border-radius: 4px;
}

/* --- Item simples --- */
.sidebar__item {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 18px;
  color: var(--color-text-sidebar);
  cursor: pointer;
  transition:
    background-color var(--t-fast),
    color var(--t-fast);
  white-space: nowrap;
  overflow: hidden;
  position: relative;
  width: 100%;
  text-align: left;
  border-left: 2px solid transparent;
}
.sidebar__item:hover {
  background: var(--color-bg-hover);
  color: var(--color-text-primary);
}
.sidebar__item.is-active {
  background: var(--color-accent-light);
  color: var(--color-accent);
  border-left-color: var(--color-accent);
  font-weight: 500;
}

.sidebar__item-icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  color: currentColor;
  opacity: 0.65;
  transition: opacity var(--t-fast);
}
.sidebar__item-initials {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 17px;
  height: 17px;
  font-size: 10px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.02em;
  color: currentColor;
}
.sidebar__item:hover .sidebar__item-icon,
.sidebar__group-toggle:hover .sidebar__item-icon,
.sidebar__item.is-active .sidebar__item-icon,
.sidebar__group.is-open > .sidebar__group-toggle .sidebar__item-icon {
  opacity: 1;
}
.sidebar__item-text {
  font-size: var(--font-sm);
  font-weight: 400;
  white-space: nowrap;
  opacity: 1;
  transition: opacity var(--t-base);
}
.sidebar.is-collapsed .sidebar__item-text {
  opacity: 0;
  width: 0;
  overflow: hidden;
  pointer-events: none;
}

/* Tooltip no modo collapsed */
.sidebar.is-collapsed .sidebar__item[data-tooltip]::after,
.sidebar.is-collapsed .sidebar__group-toggle[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  left: calc(100% + 10px);
  top: 50%;
  transform: translateY(-50%);
  background: var(--color-brand-navy);
  color: var(--color-text-inverse);
  font-size: var(--font-xs);
  font-weight: 400;
  padding: 5px 10px;
  border-radius: var(--radius-sm);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-fast);
  z-index: var(--z-tooltip);
  box-shadow: var(--shadow-md);
  border: 1px solid var(--color-border-strong);
}
.sidebar.is-collapsed .sidebar__item[data-tooltip]:hover::after,
.sidebar.is-collapsed .sidebar__group-toggle[data-tooltip]:hover::after {
  opacity: 1;
}

/* --- Section label --- */
.sidebar__section-label {
  font-size: 9.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--color-text-muted);
  padding: 14px 18px 5px;
  white-space: nowrap;
  transition:
    opacity var(--t-base),
    height var(--t-base),
    padding var(--t-base);
}
.sidebar.is-collapsed .sidebar__section-label {
  opacity: 0;
  height: 0;
  padding: 0;
  overflow: hidden;
}

/* --- NAV GROUP (com sub-itens) --- */
.sidebar__group {
  width: 100%;
}

.sidebar__group-toggle {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 8px 18px;
  color: var(--color-text-sidebar);
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition:
    background-color var(--t-fast),
    color var(--t-fast);
  border-left: 2px solid transparent;
}
.sidebar__group-toggle:hover {
  background: var(--color-bg-hover);
  color: var(--color-text-primary);
}
.sidebar__group.is-open > .sidebar__group-toggle {
  color: var(--color-text-primary);
}

.sidebar__group-chevron {
  margin-left: auto;
  flex-shrink: 0;
  display: flex;
  transition:
    transform var(--t-base),
    opacity var(--t-base),
    color var(--t-fast);
  color: var(--color-text-muted);
}
.sidebar__group.is-open > .sidebar__group-toggle .sidebar__group-chevron {
  transform: rotate(90deg);
  color: var(--color-accent);
}
.sidebar.is-collapsed .sidebar__group-chevron {
  opacity: 0;
}

/* --- SUBMENU --- */
.sidebar__submenu {
  max-height: 0;
  overflow: hidden;
  transition: max-height var(--t-slow);
  margin-left: 27px;
  padding-left: 0;
}

.sidebar__item--sub {
  font-size: var(--font-xs);
  padding: 6px 12px 6px 18px;
  color: var(--color-text-muted);
  display: flex;
  align-items: center;
  gap: 8px;
  position: relative;
  border-left: 2px solid transparent;
}
.sidebar__item--sub:hover {
  background: var(--color-bg-hover);
  color: var(--color-text-primary);
}
.sidebar__item--sub.is-active {
  color: var(--color-accent);
  border-left-color: var(--color-accent);
  background: var(--color-accent-light);
  font-weight: 500;
}

/* Oculta submenus no modo collapsed */
.sidebar.is-collapsed .sidebar__submenu {
  max-height: 0 !important;
}

/* ==========================================================================
   05. HEADER & FOOTER
   ========================================================================== */
/* <!-- BLOCK: header --> */
.app-header {
  height: var(--header-height);
  background: var(--color-bg-header);
  border-bottom: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 20px;
  flex-shrink: 0;
  z-index: var(--z-header);
  box-shadow: var(--shadow-xs);
  gap: 12px;
}

.header__left {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  flex: 1;
}

/* Sinalização de ambiente não-production — só o badge, header fica na cor normal */
.env-badge {
  display: inline-flex;
  align-items: center;
  margin-left: 10px;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--color-danger-text);
  background: var(--color-danger-light);
  border: 1px solid var(--color-danger);
  white-space: nowrap;
}

/* Hamburger */
.header__hamburger {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text-secondary);
  flex-shrink: 0;
  transition:
    background-color var(--t-fast),
    color var(--t-fast);
}
.header__hamburger:hover {
  background: var(--color-bg-surface-alt);
  color: var(--color-text-primary);
}

.header__breadcrumb {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--color-text-secondary);
  font-size: var(--font-sm);
  white-space: nowrap;
  overflow: hidden;
}
.header__breadcrumb strong {
  color: var(--color-text-primary);
  font-weight: 600;
}
.header__breadcrumb .sep {
  color: var(--color-text-muted);
}

.header__actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}

.header__icon-btn {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text-secondary);
  transition:
    background-color var(--t-fast),
    color var(--t-fast);
}
.header__icon-btn:hover {
  background: var(--color-bg-surface-alt);
  color: var(--color-text-primary);
}

.header__avatar {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-full);
  background: linear-gradient(135deg, var(--color-brand-green) 0%, var(--color-brand-sky) 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: var(--font-xs);
  font-weight: 700;
  cursor: pointer;
  flex-shrink: 0;
}
/* <!-- /BLOCK: header --> */

/* <!-- BLOCK: footer --> */
.app-footer {
  height: var(--footer-height);
  background: var(--color-bg-header);
  border-top: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  flex-shrink: 0;
  color: var(--color-text-muted);
  font-size: var(--font-xs);
}
.footer__version {
  display: flex;
  align-items: center;
  gap: 6px;
}
.footer__status {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--color-success);
  font-weight: 500;
}
.footer__status::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--color-success);
}
/* <!-- /BLOCK: footer --> */

/* ==========================================================================
   06. BOTÕES
   ========================================================================== */
/* <!-- BLOCK: buttons --> */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 9px 18px;
  border-radius: var(--radius-sm);
  font-size: var(--font-sm);
  font-weight: 600;
  line-height: 1;
  text-align: center;
  cursor: pointer;
  border: 1.5px solid transparent;
  transition:
    background-color var(--t-fast),
    color var(--t-fast),
    border-color var(--t-fast),
    box-shadow var(--t-fast),
    transform 80ms ease;
  user-select: none;
  white-space: nowrap;
}
.btn:active {
  transform: translateY(1px);
}
.btn:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus);
}
.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.btn--primary {
  background: var(--color-accent);
  color: var(--color-text-on-accent);
  border-color: var(--color-accent);
}
.btn--primary:hover {
  background: var(--color-accent-hover);
  border-color: var(--color-accent-hover);
  box-shadow: var(--shadow-accent);
}

.btn--secondary {
  background: var(--color-bg-surface-alt);
  color: var(--color-text-primary);
  border-color: var(--color-border-strong);
}
.btn--secondary:hover {
  border-color: var(--color-border-accent);
  color: var(--color-accent);
}

.btn--ghost {
  background: transparent;
  color: var(--color-text-secondary);
  border-color: transparent;
}
.btn--ghost:hover {
  background: var(--color-bg-surface-alt);
  color: var(--color-text-primary);
}

.btn--outline {
  background: transparent;
  color: var(--color-text-primary);
  border-color: var(--color-border);
}
.btn--outline:hover {
  border-color: var(--color-text-primary);
  background: var(--color-bg-surface-alt);
}

.btn--danger {
  background: var(--color-danger-light);
  color: var(--color-danger-text);
  border-color: var(--color-danger);
}
.btn--danger:hover {
  background: var(--color-danger);
  color: #fff;
  border-color: var(--color-danger);
  box-shadow:
    0 4px 18px rgba(239, 68, 68, 0.35),
    0 2px 6px rgba(239, 68, 68, 0.2);
}

.btn--success {
  background: var(--color-success-light);
  color: var(--color-success-text);
  border-color: var(--color-success);
}
.btn--success:hover {
  background: var(--color-success);
  color: #fff;
  border-color: var(--color-success);
  box-shadow:
    0 4px 18px rgba(34, 197, 94, 0.35),
    0 2px 6px rgba(34, 197, 94, 0.2);
}

.btn--info {
  background: var(--color-info-light);
  color: var(--color-info-text);
  border-color: var(--color-info);
}
.btn--info:hover {
  background: var(--color-info);
  color: #fff;
  border-color: var(--color-info);
  box-shadow:
    0 4px 18px rgba(59, 130, 246, 0.35),
    0 2px 6px rgba(59, 130, 246, 0.2);
}

.btn--warning {
  background: var(--color-warning-light);
  color: var(--color-warning-text);
  border-color: var(--color-warning);
}
.btn--warning:hover {
  background: var(--color-warning);
  color: #fff;
  border-color: var(--color-warning);
  box-shadow:
    0 4px 18px rgba(245, 158, 11, 0.35),
    0 2px 6px rgba(245, 158, 11, 0.2);
}

/* Mesma altura de .form-input/.custom-select__trigger, pra nunca sobrar em
   degrau ao lado de um campo de busca/select na mesma toolbar (ver
   `--control-height` no :root). */
.btn--sm {
  padding: 4px 12px;
  font-size: var(--font-xs);
  height: var(--control-height);
}
.btn--lg {
  padding: 12px 24px;
  font-size: var(--font-base);
  border-radius: var(--radius-md);
}
.btn--icon {
  padding: 8px;
}

/* Loading state */
.btn[aria-busy="true"] {
  cursor: wait;
  opacity: 0.8;
}
@keyframes btn-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

/* Dark mode — texto claro nos fundos sólidos do hover. O texto de repouso
   já vem dos tokens --color-*-text (redefinidos no tema dark). */
[data-theme="dark"] .btn--success:hover,
[data-theme="dark"] .btn--danger:hover,
[data-theme="dark"] .btn--warning:hover,
[data-theme="dark"] .btn--info:hover {
  color: #fff;
}
/* <!-- /BLOCK: buttons --> */

/* ==========================================================================
   07. BADGES
   ========================================================================== */
/* <!-- BLOCK: badges --> */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 10px;
  border-radius: var(--radius-full);
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  font-weight: 500;
  line-height: 1.6;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.badge--success {
  background: var(--color-success-light);
  color: var(--color-success-text);
}
.badge--danger {
  background: var(--color-danger-light);
  color: var(--color-danger-text);
}
.badge--warning {
  background: var(--color-warning-light);
  color: var(--color-warning-text);
}
.badge--info {
  background: var(--color-info-light);
  color: var(--color-info-text);
}
.badge--neutral {
  background: var(--color-bg-surface-alt);
  color: var(--color-text-secondary);
}
.badge--accent {
  background: var(--color-accent-light);
  color: var(--color-accent-dark);
}
/* Variante de alta ênfase — fundo cheio com a cor da marca.
   Use quando o badge é a *informação principal* do contexto (ex.:
   contagem total de registros no rodapé de uma tabela). */
.badge--solid {
  background: var(--color-accent);
  color: var(--color-text-inverse);
}

.badge .badge__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}

/* Marca de confirmação do selo — alternativa ao ponto, no mesmo espaço. */
.badge .badge__mark {
  width: 11px;
  height: 11px;
  stroke-width: 3;
  flex-shrink: 0;
}

/* Filter badge (removível) */
.filter-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px 4px 12px;
  border-radius: var(--radius-full);
  font-size: var(--font-xs);
  font-weight: 500;
  background: var(--color-accent-light);
  color: var(--color-accent);
  border: 1px solid rgba(var(--color-accent-rgb), 0.25);
  white-space: nowrap;
}
.filter-badge__remove {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: rgba(var(--color-accent-rgb), 0.15);
  color: var(--color-accent);
  transition: background var(--t-fast);
  cursor: pointer;
}
.filter-badge__remove:hover {
  background: var(--color-accent);
  color: #fff;
}
/* <!-- /BLOCK: badges --> */

/* ==========================================================================
   08. FORMULÁRIOS
   ========================================================================== */
/* <!-- BLOCK: forms --> */
.form-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.form-label {
  font-size: var(--font-xs);
  font-weight: 600;
  color: var(--color-text-secondary);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.form-label.is-required::after {
  content: " *";
  color: var(--color-danger);
}

.form-input {
  width: 100%;
  padding: 6px 12px;
  background: var(--color-bg-input);
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-primary);
  font-size: var(--font-sm);
  transition:
    border-color var(--t-fast),
    box-shadow var(--t-fast);
  appearance: none;
  outline: none;
}
/* Altura padronizada (`--control-height`) — mesma de `.custom-select__trigger`
   e `.btn--sm`, pra input/select/botão nunca ficarem em "degrau" na mesma
   toolbar. `:not(textarea)` porque `.form-input` também é reusada em
   textarea (ex.: descrição do produto), que precisa da altura de `rows`. */
.form-input:not(textarea) {
  height: var(--control-height);
}
.form-input::placeholder {
  color: var(--color-text-muted);
}
.form-input:hover {
  border-color: var(--color-text-muted);
}
.form-input:focus {
  border-color: var(--color-accent);
  box-shadow: var(--shadow-focus);
}
.form-input.is-error {
  border-color: var(--color-danger);
}
.form-input.is-error:focus {
  box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.2);
}
.form-input:disabled {
  background: var(--color-bg-surface-alt);
  cursor: not-allowed;
}

.form-hint {
  font-size: var(--font-xs);
  color: var(--color-text-muted);
}
.form-hint.is-error {
  color: var(--color-danger);
}

/* Read-only "input" — usado em drawers view-only para exibir um valor
   formatado sem aceitar edição. Mantém alinhamento visual com
   ``.form-input`` (background, borda, raio, font) para não criar uma
   variante destoante quando colocado lado a lado num ``.form-grid``. */
.form-readonly {
  display: inline-block;
  padding: 8px 10px;
  min-height: 36px;
  color: var(--color-text-primary);
  background: var(--color-bg-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: var(--font-sm);
  line-height: 1.4;
  word-break: break-word;
}

/* Erro genérico — funciona com .field__input (login) e .form-input (demais páginas) */
input.is-error,
select.is-error,
textarea.is-error {
  border-color: var(--color-danger) !important;
}
input.is-error:focus,
select.is-error:focus,
textarea.is-error:focus {
  box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.2) !important;
}

.form-input-wrapper {
  position: relative;
}
.form-input-wrapper .form-input {
  padding-left: 36px;
}
.form-input-icon {
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--color-text-muted);
  pointer-events: none;
  display: flex;
}
/* Miniatura de preview de uma URL de imagem informada em formulário (ex.:
   link da imagem do produto). `hidden` por padrão — sem URL válida, não
   reserva espaço nem move o layout do form. */
.form-image-preview {
  display: block;
  width: 64px;
  height: 64px;
  margin-top: 8px;
  object-fit: cover;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg-surface-alt);
}

/* Checkbox */
.form-checkbox {
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  user-select: none;
}
.form-checkbox input[type="checkbox"] {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.form-checkbox__box {
  width: 17px;
  height: 17px;
  border-radius: var(--radius-xs);
  border: 2px solid var(--color-border);
  background: var(--color-bg-input);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition:
    border-color var(--t-fast),
    background var(--t-fast);
}
.form-checkbox input:checked + .form-checkbox__box {
  background: var(--color-accent);
  border-color: var(--color-accent);
}
.form-checkbox input:focus-visible + .form-checkbox__box {
  box-shadow: var(--shadow-focus);
}
.form-checkbox:hover .form-checkbox__box {
  border-color: var(--color-accent);
}
.form-checkbox__check {
  color: var(--color-text-on-accent);
  opacity: 0;
  transform: scale(0.5);
  transition:
    opacity var(--t-fast),
    transform var(--t-fast);
}
.form-checkbox input:checked + .form-checkbox__box .form-checkbox__check {
  opacity: 1;
  transform: scale(1);
}
.form-checkbox__label {
  font-size: var(--font-sm);
  color: var(--color-text-primary);
}

/* Custom Select */
.custom-select {
  position: relative;
  user-select: none;
}
.custom-select__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 6px 12px;
  background: var(--color-bg-input);
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-primary);
  font-size: var(--font-sm);
  cursor: pointer;
  gap: 8px;
  transition:
    border-color var(--t-fast),
    box-shadow var(--t-fast);
}
.custom-select.is-open .custom-select__trigger {
  border-color: var(--color-accent);
  box-shadow: var(--shadow-focus);
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}
.custom-select__trigger-text {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.custom-select__trigger-text.is-placeholder {
  color: var(--color-text-muted);
}
.custom-select__chevron {
  flex-shrink: 0;
  color: var(--color-text-muted);
  transition: transform var(--t-base);
}
.custom-select.is-open .custom-select__chevron {
  transform: rotate(180deg);
}

/* "× limpar" injetado pelo JS dentro do trigger. Visível apenas quando
   há valor selecionado (``hidden`` controlado pelo JS). Cor já vermelha
   (discreta) para deduzir a função; hover intensifica + cresce levemente
   para confirmar a affordance. */
.custom-select__clear {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  padding: 0;
  margin: 0;
  background: transparent;
  border: none;
  color: var(--color-danger);
  opacity: 0.5;
  border-radius: var(--radius-full);
  cursor: pointer;
  transform: scale(1);
  transition:
    opacity var(--t-fast),
    transform var(--t-fast),
    background var(--t-fast);
}
.custom-select__clear:hover,
.custom-select__clear:focus-visible {
  opacity: 1;
  transform: scale(1.18);
  background: var(--color-danger-light);
}

.custom-select__dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--color-bg-surface);
  border: 1.5px solid var(--color-accent);
  border-top: none;
  border-bottom-left-radius: var(--radius-sm);
  border-bottom-right-radius: var(--radius-sm);
  z-index: var(--z-drawer);
  box-shadow: var(--shadow-md);
  display: none;
  flex-direction: column;
  max-height: 240px;
  overflow: hidden;
}
.custom-select.is-open .custom-select__dropdown {
  display: flex;
}
/* Auto-flip: quando aplicada via JS, o dropdown abre para CIMA. Usado em
   selects próximos ao fim de áreas com overflow (ex.: drawer body). */
.custom-select.is-open-up .custom-select__dropdown {
  top: auto;
  bottom: 100%;
  border-top: 1.5px solid var(--color-accent);
  border-bottom: none;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}
.custom-select.is-open-up.is-open .custom-select__trigger {
  border-bottom-left-radius: var(--radius-sm);
  border-bottom-right-radius: var(--radius-sm);
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

.custom-select__search {
  padding: 8px;
  border-bottom: 1px solid var(--color-border);
  flex-shrink: 0;
}
.custom-select__search input {
  width: 100%;
  padding: 6px 10px;
  background: var(--color-bg-surface-alt);
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-xs);
  color: var(--color-text-primary);
  font-size: var(--font-sm);
  outline: none;
  transition: border-color var(--t-fast);
}
.custom-select__search input:focus {
  border-color: var(--color-accent);
}

.custom-select__options {
  overflow-y: auto;
  flex: 1;
  scrollbar-width: thin;
}
.custom-select__option {
  padding: 8px 14px;
  font-size: var(--font-sm);
  color: var(--color-text-primary);
  cursor: pointer;
  transition: background var(--t-fast);
  outline: none;
}
.custom-select__option:hover {
  background: var(--color-bg-hover);
}
.custom-select__option.is-selected {
  color: var(--color-accent);
  font-weight: 600;
  background: var(--color-accent-light);
}
.custom-select__option.is-hidden {
  display: none;
}

/* Multiselect */
.multiselect {
  position: relative;
  user-select: none;
}
/* Mesmo layout de trigger do `.custom-select` de seleção única: uma linha,
   texto resumido à esquerda, chevron fixo à direita. O detalhamento por
   valor mora na barra de filtros ativos, não aqui. */
.multiselect__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 6px 12px;
  background: var(--color-bg-input);
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-primary);
  font-size: var(--font-sm);
  cursor: pointer;
  gap: 8px;
  transition:
    border-color var(--t-fast),
    box-shadow var(--t-fast);
}
.multiselect.is-open .multiselect__trigger {
  border-color: var(--color-accent);
  box-shadow: var(--shadow-focus);
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}
.multiselect__placeholder {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.multiselect__placeholder.is-placeholder {
  color: var(--color-text-muted);
}
.multiselect__chevron {
  flex-shrink: 0;
  color: var(--color-text-muted);
  transition: transform var(--t-base);
}
.multiselect.is-open .multiselect__chevron {
  transform: rotate(180deg);
}

.multiselect__dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--color-bg-surface);
  border: 1.5px solid var(--color-accent);
  border-top: none;
  border-bottom-left-radius: var(--radius-sm);
  border-bottom-right-radius: var(--radius-sm);
  z-index: var(--z-drawer);
  box-shadow: var(--shadow-md);
  display: none;
  flex-direction: column;
  max-height: 220px;
}
.multiselect.is-open .multiselect__dropdown {
  display: flex;
}
.multiselect__options {
  overflow-y: auto;
  flex: 1;
  scrollbar-width: thin;
}

.multiselect__option {
  padding: 8px 14px;
  font-size: var(--font-sm);
  color: var(--color-text-primary);
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 10px;
  transition: background var(--t-fast);
}
.multiselect__option:hover {
  background: var(--color-bg-hover);
}
.multiselect__option-check {
  width: 15px;
  height: 15px;
  border-radius: var(--radius-xs);
  border: 2px solid var(--color-border);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: all var(--t-fast);
}
.multiselect__option.is-selected .multiselect__option-check {
  background: var(--color-accent);
  border-color: var(--color-accent);
}
/* <!-- /BLOCK: forms --> */

/* ==========================================================================
   09. FILTROS
   ========================================================================== */
/* <!-- BLOCK: filters --> */
.filter-toolbar {
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  margin-bottom: 16px;
  box-shadow: var(--shadow-sm);
  /* overflow: hidden removido — clipava o dropdown do custom-select */
}
/* Barra travada durante a carga da listagem (`FilterBusyManager`): o `inert`
   do JS já bloqueia clique, foco e Tab; esmaecer é só o sinal visual de
   "inativo" pra não parecer clicável à toa — mesma escolha do
   `.side-drawer__body[inert]`. */
.filter-toolbar[inert] {
  opacity: 0.7;
  transition: opacity 0.12s ease;
}
.filter-toolbar__bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  flex-wrap: wrap;
}
.filter-toolbar__search {
  flex: 1;
  min-width: 200px;
}
/* `<label>` é `inline` por padrão — sem `display: block`, `margin-bottom`
   não teria efeito visual nenhum (margem vertical não se aplica a inline).
   Sem isso, o espaço entre o rótulo e o campo vinha só do `line-height`
   (1,6 do body) sobrando em cima do texto, descontrolado — maior e menos
   previsível que o `margin-bottom: 4px` que a linha de filtros já usa
   (`.form-group > .form-label`, seção FORMULÁRIOS). Padroniza pro mesmo
   valor. */
.filter-toolbar__search > .form-label {
  display: block;
  margin-bottom: 4px;
}
/* Busca por typeahead: a célula é mais alta que uma linha de controle, porque o
   `.tag-typeahead__selected` fica acima do campo. Com `align-items: center` da
   barra o botão cairia no meio dessa altura; em `flex-end` ele fica na linha do
   campo, que tem a mesma `--control-height`. */
.filter-toolbar__bar:has(.tag-typeahead) {
  align-items: flex-end;
}
.filter-toolbar__actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

/* Modificador `--sticky` (estático, escolhido no template): gruda o
   `.filter-toolbar` inteiro no topo enquanto o resto da página rola (quem
   rola é o `.main-content`) — mesma técnica de `.segmented-row--sticky`.
   `scroll-collapse.js` alterna `.is-condensed` pela DIREÇÃO da rolagem
   (desce → condensa; sobe → expande na hora, sem precisar voltar ao topo
   da página) e `.is-pinned` por estar de fato grudado (via
   `IntersectionObserver`, independente da direção — cobre também o
   expandido-mas-já-pinado, nos primeiros px de rolagem antes do limiar de
   condensar). Os dois são estado em tempo real, não variante — por isso
   `.is-*` (html_guide.md), e não mais um `--modificador`.
   `top: -16px` cancela o `padding-top: 16px` do `.main-content` (style.css
   :337): sem isso sobraria uma faixa vazia entre o header e o toolbar
   grudado, quebrando a leitura de "extensão do header". Se aquele padding
   mudar, este valor tem que acompanhar. `z-index` acima do
   `.segmented-row--sticky` (3) e do `thead` grudado (2): o toolbar é o
   primeiro da pilha grudada e tem que ficar por cima dos dois quando o
   conteúdo passa por baixo dele durante a rolagem. */
.filter-toolbar--sticky {
  position: sticky;
  top: -16px;
  z-index: 4;
}
/* Pinado (expandido ou condensado), o toolbar estica até a largura do
   header: margem negativa igual ao padding horizontal do `.main-content`
   (24px, style.css :337) — sem isso ele ficava mais estreito que o
   header, com a mesma margem do card branco que só faz sentido fora do
   estado grudado. Some a borda/raio laterais e do topo (o de baixo
   continua, separando do que vem a seguir); se aquele padding mudar, este
   valor tem que acompanhar. A faixa de cobertura usa o fundo do próprio
   card branco (`--color-bg-surface`, já opaco) — só quando também
   condensado é que ela troca para o fundo de página (regra abaixo).
   Escopado a desktop pelo mesmo motivo que `.is-condensed` (regra
   adiante): `scroll-collapse.js` não confere viewport, e a sentinela do
   `IntersectionObserver` sai de vista ao rolar a página em mobile — logo
   `.is-pinned` chega a ser alternada lá, onde o toolbar já é `position:
   static` (seção 15) e a margem negativa/faixa de cobertura seriam um
   artefato visual no meio da página. */
@media (min-width: 769px) {
  .filter-toolbar--sticky.is-pinned {
    margin-left: -24px;
    margin-right: -24px;
    border-left: 0;
    border-right: 0;
    border-top: 0;
    border-radius: 0;
    box-shadow: 0 -40px 0 var(--color-bg-surface);
  }
  .filter-toolbar--sticky.is-pinned.is-condensed {
    background: var(--color-bg-content);
    box-shadow: 0 -40px 0 var(--color-bg-content);
  }
}
/* Estado `.is-condensed`: com o toolbar já grudado, esconde
   `.filter-toolbar__bar` e `.filter-toolbar__filters`, deixando à mostra só
   a `.active-filters-bar` (o resumo do que está filtrado). `max-height`
   grande o suficiente para nunca cortar o conteúdo aberto — é o que permite
   animar até 0 (`none` não é animável). Escopado a desktop: `scroll-
   collapse.js` não confere viewport (só direção de rolagem), então em
   mobile `.is-condensed` chega a ser alternada mesmo com `.main-content`
   sem `overflow` próprio — sem esse escopo, o toolbar encolheria em mobile
   apesar de já não ser `--sticky` lá (seção 15). */
@media (min-width: 769px) {
  .filter-toolbar__bar,
  .filter-toolbar__filters {
    max-height: 600px;
    transition:
      max-height var(--t-slow),
      opacity var(--t-slow),
      padding-top var(--t-slow),
      padding-bottom var(--t-slow);
  }
  .filter-toolbar.is-condensed .filter-toolbar__bar,
  .filter-toolbar.is-condensed .filter-toolbar__filters {
    max-height: 0;
    opacity: 0;
    overflow: hidden;
    padding-top: 0;
    padding-bottom: 0;
    border-top-color: transparent;
  }
  @media (prefers-reduced-motion: reduce) {
    .filter-toolbar__bar,
    .filter-toolbar__filters {
      transition: none;
    }
  }
}

/* Accordion */
.filter-accordion__toggle {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 6px;
  border-top: 1px solid var(--color-border);
  padding: 8px 16px;
  font-size: var(--font-xs);
  font-weight: 600;
  color: var(--color-text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  cursor: pointer;
  transition:
    background var(--t-fast),
    color var(--t-fast);
  background: var(--color-bg-surface-alt);
  text-align: left;
}
.filter-accordion__toggle:hover {
  color: var(--color-accent);
}
.filter-accordion__toggle .acc-chevron {
  margin-left: auto;
  transition: transform var(--t-base);
}
.filter-accordion.is-open .filter-accordion__toggle .acc-chevron {
  transform: rotate(180deg);
}

.filter-accordion__body {
  display: none;
  padding: 16px;
  gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  border-top: 1px solid var(--color-border);
  background: var(--color-bg-surface);
  animation: slideDown 0.25s ease;
}
.filter-accordion.is-open .filter-accordion__body {
  display: grid;
}
/* Mesmo grid do `.filter-accordion__body`, mas sempre visível — sem
   `display: none` nem animação de abertura. Padding vertical igual ao
   `.filter-toolbar__bar` logo acima (12px, não os 16px do
   `.filter-accordion__body`): as duas linhas do toolbar têm que respirar
   igual — o acordeão, sozinho num popover, não tem essa vizinha pra
   comparar. */
.filter-toolbar__filters {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 16px;
  padding: 12px 16px;
  border-top: 1px solid var(--color-border);
}
.filter-accordion__body .form-group,
.filter-toolbar__filters .form-group {
  display: flex;
  flex-direction: column;
}
.filter-accordion__body .form-group > .form-label,
.filter-toolbar__filters .form-group > .form-label {
  margin-bottom: 4px;
}
.filter-accordion__body .form-group > .form-input,
.filter-accordion__body .form-group > .custom-select,
.filter-accordion__body .form-group > .form-checkbox,
.filter-toolbar__filters .form-group > .form-input,
.filter-toolbar__filters .form-group > .custom-select,
.filter-toolbar__filters .form-group > .form-checkbox {
  margin-top: auto;
}

@keyframes slideDown {
  from {
    opacity: 0;
    transform: translateY(-8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Active filters bar */
.active-filters-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 10px 16px;
  border-top: 1px solid var(--color-border);
  background: var(--color-bg-surface);
  animation: slideDown 0.2s ease;
}
.active-filters-bar__label {
  font-size: var(--font-xs);
  font-weight: 600;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  flex-shrink: 0;
}
.active-filters-bar__badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  flex: 1;
}
.active-filters-bar__actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
.active-filters-bar__clear {
  font-size: var(--font-xs);
  font-weight: 600;
  color: var(--color-danger);
  cursor: pointer;
  padding: 4px 8px;
  border-radius: var(--radius-xs);
  transition: background var(--t-fast);
}
.active-filters-bar__clear:hover {
  background: var(--color-danger-light);
}

/* Com o `.filter-toolbar` já `.is-condensed` (grudado, mostrando só o
   resumo), a `.active-filters-bar` vira linha única com altura fixa
   (`--ds-sticky-summary-h`): previsível porque o `top` do controle
   segmentado e do cabeçalho da tabela dependem dela (ver seção SEGMENTED).
   Os badges ganham rolagem horizontal própria em vez de quebrar e crescer
   em altura. Fora do `.is-condensed`, o resumo some — os filtros abertos já
   mostram os valores selecionados em cada select, então o resumo ali seria
   redundante. `filter-controller.js` controla `display` por `style` inline
   (mostra/esconde por ter filtro ativo ou não); aqui a preocupação é outra
   (condensado ou não), então zera altura/borda em vez de mexer em
   `display` — não compete com o inline style, só encolhe a caixa a nada
   visível quando expandido.
   Escopado a desktop: `scroll-collapse.js` não confere viewport, só
   direção de rolagem — `.is-condensed` pode acabar alternada mesmo em
   mobile. O `@media` aqui é o que garante que isso não tem efeito nenhum
   lá, e o resumo continua aparecendo do jeito que já era antes desta
   issue. */
@media (min-width: 769px) {
  .filter-toolbar.is-condensed .active-filters-bar {
    height: var(--ds-sticky-summary-h);
    box-sizing: border-box;
    border-top: 0;
    flex-wrap: nowrap;
  }
  .filter-toolbar.is-condensed .active-filters-bar__badges {
    flex-wrap: nowrap;
    overflow-x: auto;
  }
  .filter-toolbar--sticky:not(.is-condensed) .active-filters-bar {
    max-height: 0;
    padding: 0;
    border: 0;
    overflow: hidden;
  }
}

/* Barra de ações em massa — some acima da tabela, só quando há seleção
   (nenhuma linha marcada = elemento removido do fluxo via `hidden`, não só
   invisível). Tom accent para se destacar da `.active-filters-bar` (neutra). */
.bulk-select-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 10px 16px;
  margin-bottom: 12px;
  background: var(--color-accent-light);
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-md);
  animation: slideDown 0.2s ease;
}
.bulk-select-bar[hidden] {
  display: none;
}
.bulk-select-bar__label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--font-sm);
  font-weight: 600;
  color: var(--color-text-primary);
}
.bulk-select-bar__label i {
  width: 16px;
  height: 16px;
  color: var(--color-accent);
}
.bulk-select-bar__actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

/* Preset panel */
#filter-preset-panel {
  display: none;
  border-top: 1px solid var(--color-border);
  padding: 12px 16px 14px;
  background: var(--color-bg-surface-alt);
  animation: slideDown 0.2s ease;
}

.preset-save-section {
  margin-bottom: 12px;
}
.preset-save-section__label {
  font-size: var(--font-xs);
  font-weight: 600;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 6px;
}
.preset-save-section__row {
  display: flex;
  gap: 6px;
  align-items: center;
}

.preset-list__title {
  font-size: var(--font-xs);
  font-weight: 600;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 4px;
}

.preset-row {
  display: flex;
  align-items: center;
  gap: 4px;
  border-bottom: 1px solid var(--color-border);
  padding: 2px 0;
}
.preset-row:last-child {
  border-bottom: none;
}
.preset-row__load {
  flex: 1;
  justify-content: flex-start !important;
  text-align: left;
  gap: 6px;
}
.preset-row__load:hover {
  color: var(--color-accent) !important;
}

/* Overlay */
.overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.35);
  z-index: var(--z-overlay);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-slow);
  backdrop-filter: blur(2px);
}
.overlay.is-visible {
  opacity: 1;
  pointer-events: auto;
}

/* Véu de espera da página — o `BusyManager` do core.js cria e remove. Trava a
   tela enquanto uma operação longa roda (ex.: o servidor gerando um Excel).
   Fica em `--z-modal`, acima de overlay e drawer: pode aparecer sobre um drawer
   já aberto. O bloqueio de teclado não é daqui — é o `inert` que o manager põe
   na casca do app. */
.busy-veil {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.35);
  backdrop-filter: blur(2px);
}
.busy-veil__card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 20px;
  border-radius: var(--radius-md);
  background: var(--color-bg-surface);
  box-shadow: var(--shadow-md);
  color: var(--color-text-primary);
  font-size: var(--font-sm);
  font-weight: 600;
}
/* Reusa o `btn-spin` do botão em loading — um só keyframe de rotação no DS. */
.busy-veil__spinner {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  border: 2px solid var(--color-border);
  border-top-color: var(--color-accent);
  border-radius: 50%;
  animation: btn-spin 0.8s linear infinite;
}

/* Side Drawer */
.side-drawer {
  position: fixed;
  top: 0;
  right: 0;
  height: 100dvh;
  width: 380px;
  max-width: 90vw;
  background: var(--color-bg-surface);
  z-index: var(--z-drawer);
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-lg);
  transform: translateX(100%);
  transition: transform var(--t-slow);
}
.side-drawer.is-open {
  transform: translateX(0);
}

/* Modificadores de largura para drawers — escolha pelo conteúdo:
   - default (380px) : detalhes / formulário simples de 1 coluna
   - --md (560px)    : formulário típico de edição
   - --lg (800px)    : formulário com várias colunas ou tabs com 4 abas
   - --xl (1080px)   : tabs com 5+ abas + form-grid denso
   - --full (100%)   : fluxo de trabalho que ocupa a tela inteira */
.side-drawer--md {
  width: 560px;
}
.side-drawer--lg {
  width: 800px;
}
.side-drawer--xl {
  width: 1180px;
}
.side-drawer--2xl {
  width: 1340px;
}
.side-drawer--full {
  width: 100%;
  /* Sem o teto de 90vw do `.side-drawer` base — aqui é a tela inteira. */
  max-width: 100vw;
}

.side-drawer__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 20px;
  border-bottom: 1px solid var(--color-border);
  flex-shrink: 0;
}
.side-drawer__title {
  font-size: var(--font-base);
  font-weight: 700;
  color: var(--color-text-primary);
}
.side-drawer__close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
  transition:
    background var(--t-fast),
    color var(--t-fast);
}
.side-drawer__close:hover {
  background: var(--color-bg-surface-alt);
  color: var(--color-text-primary);
}
.side-drawer__close i,
.side-drawer__close svg {
  width: 18px;
  height: 18px;
  display: block;
}
/* Agrupa ações extras do header do drawer (ex.: Histórico) ao lado do
   botão de fechar, mantendo o título à esquerda. */
.side-drawer__header-actions {
  display: flex;
  align-items: center;
  gap: 4px;
}

/* Estado "ocupado" — enquanto um POST está em andamento (via
   withLoadingButton/DrawerManager.setBusy), o drawer inteiro fica inerte:
   body/footer não recebem clique, o X é desabilitado visualmente e o cursor
   indica espera. O botão em loading (spinner) permanece como feedback. */
.side-drawer.is-busy {
  cursor: wait;
}
.side-drawer.is-busy .side-drawer__body,
.side-drawer.is-busy .side-drawer__footer {
  pointer-events: none;
}
.side-drawer.is-busy .side-drawer__close {
  pointer-events: none;
  opacity: 0.5;
}

.side-drawer__body {
  flex: 1;
  overflow-y: auto;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  scrollbar-width: thin;
}
/* Sem isto, um corpo de drawer com conteúdo mais alto que a viewport (ex.:
   gráfico + tabela) encolhe os filhos em vez de rolar: o item flex sem
   `flex-shrink: 0` tem `min-height: auto` resolvido pelo próprio conteúdo, e
   um `<div>` comum (não substituído, sem tamanho intrínseco como um `<img>`/
   `<svg width height>`) pode ser espremido até quase 0px pelo algoritmo de
   flexbox — visto ao vivo no drawer de histórico de preço: `.segmented`
   media ~2px de altura numa tela mais baixa, cortando os botões pela metade,
   enquanto o `<svg>` do gráfico (tamanho intrínseco) resistiu ao encolhimento
   e ficou do tamanho certo. `overflow-y: auto` acima só cuida do que
   *sobra* depois do encolhimento — não evita o encolhimento em si. */
.side-drawer__body > * {
  flex-shrink: 0;
}
/* O `.side-drawer__body` é `flex-direction: column` com `align-items: stretch`
   implícito, e isso estica o `.segmented` (que é `inline-flex`) até a largura
   toda do corpo — por isso a borda arredondada do segmentado de janela não
   fechava no botão de "90 dias". `align-self: flex-start` devolve ao
   segmentado a largura do próprio conteúdo. */
.side-drawer__body > .segmented {
  align-self: flex-start;
}

/* Campo em carregamento (`DrawerManager.setLoading`): o próprio input/select
   real ganha o shimmer no lugar do valor (ainda não chegou); o rótulo é
   estático (vem do template, não da API) e não muda. Mesmo elemento, mesma
   posição — nada para reposicionar quando o valor chega. */
.form-input.is-field-loading,
.form-readonly.is-field-loading,
.custom-select.is-field-loading .custom-select__trigger {
  background: linear-gradient(
    90deg,
    var(--color-bg-surface-alt) 25%,
    var(--color-border) 50%,
    var(--color-bg-surface-alt) 75%
  );
  background-size: 200% 100%;
  animation: skeleton-shimmer 1.4s infinite;
  color: transparent;
}
.form-input.is-field-loading::placeholder {
  color: transparent;
}
.custom-select.is-field-loading .custom-select__chevron,
.custom-select.is-field-loading .custom-select__clear {
  visibility: hidden;
}
.form-checkbox.is-field-loading {
  opacity: 0.4;
  pointer-events: none;
}
/* Qualquer outro widget do corpo sem classe DS conhecida (ex.: a árvore de
   grants de `PermissionGroup`) não ganha shimmer próprio, mas o `inert` do
   JS já bloqueia o clique — esmaecer aqui é só o sinal visual de "inativo"
   pra não parecer clicável à toa. */
.side-drawer__body[inert] {
  opacity: 0.7;
}
/* O drawer abre antes do GET resolver — sem isto, o rodapé (Salvar/
   Cancelar) continuaria clicável enquanto os campos ainda carregam. */
.side-drawer__body.is-field-loading ~ .side-drawer__footer {
  pointer-events: none;
  opacity: 0.6;
}

.side-drawer__footer {
  padding: 16px 20px;
  border-top: 1px solid var(--color-border);
  display: flex;
  gap: 10px;
  flex-shrink: 0;
  justify-content: flex-end;
}
/* Botões do footer mantêm o tamanho natural (definido pelo ``size`` do
   {% ds_btn %}). Sem ``flex: 1`` para não esticarem para 50% cada — o
   conjunto fica ancorado à direita, compacto. */
.side-drawer__footer .btn {
  flex: 0 0 auto;
}

/* Drawer com abas: header, ABAS e footer ficam FIXOS; só o painel ativo
   rola. Boa prática de UI/UX — mantém contexto e ações sempre visíveis
   (o cabeçalho/abas sumirem no scroll é anti-padrão). Aplica-se a todos os
   drawers que usam .tabs no corpo. */
.side-drawer__body:has(> .tabs) {
  overflow: hidden;
  padding: 0;
  gap: 0;
}
.side-drawer__body > .tabs {
  flex: 1;
  min-height: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
}
.side-drawer__body > .tabs > .tabs__list {
  flex-shrink: 0;
  margin: 0;
  padding: 12px 20px 0;
}
.side-drawer__body > .tabs > .tabs__panel.is-active {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 16px 20px;
  scrollbar-width: thin;
}

/* ---------------------------------------------------------------------
   Side-drawer — barras inline DENTRO de abas (não confundir com
   ``.side-drawer__footer`` que vive fora das abas e tem border-top).

   Caso de uso: aba CRUD inline (Concorrente > Parâmetros / Departamentos /
   Faixas / Tags) com cabeçalho (título + ação de criar) + formulário
   inline reveláve / quick-add + rodapé com botão de "Salvar tudo".

   Promovido ao DS global em PR de padronização da aba Tags — antes
   essas classes existiam como órfãs no template (sem CSS), só
   funcionando por defaults do browser. */
.side-drawer__inline-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-bottom: 10px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--color-border);
}
.side-drawer__inline-title {
  font-size: var(--font-sm);
  font-weight: 600;
  color: var(--color-text-primary);
}
/* Bloco do formulário inline (revelado pelo botão "Adicionar"). Cartão
   levemente recuado do painel da aba para deixar claro que é uma área
   editável; ``hidden`` por default — caller controla via JS. */
.side-drawer__inline-form {
  background: var(--color-bg-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 12px;
  margin-bottom: 12px;
}
/* Linha de ações alinhada à direita (Cancelar/Salvar do form inline ou
   "Salvar tudo" no rodapé da aba). Substitui o anti-padrão
   ``style="display:flex;gap:8px;justify-content:flex-end;"`` espalhado
   pelos templates. ``--spaced`` aplica margem superior para uso como
   rodapé de aba (sem competir com border-top do drawer global). */
.side-drawer__inline-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
}
.side-drawer__inline-actions--spaced {
  margin-top: 16px;
}
/* "Quick-add" — input + botão para criação inline a partir da própria
   toolbar (ex.: criar tag pela aba Tags). Input compactado para não
   ocupar a faixa inteira e bater visualmente com botão ``btn--sm``. */
.side-drawer__inline-quick-add {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.side-drawer__inline-quick-add .form-input {
  width: 220px;
  min-height: 32px;
  padding: 4px 10px;
  font-size: var(--font-xs);
}

/* ---------------------------------------------------------------------
   Tag-typeahead — multi-seleção com busca lazy (carrega opções sob
   demanda do backend). Usado em aba de drawer com volume grande de
   opções, onde carregar tudo upfront é desperdício. Composto por:
     .tag-typeahead                  — root
     .tag-typeahead__selected        — área dos chips selecionados
     .tag-typeahead__chip            — chip de tag selecionada (com X)
     .tag-typeahead__chip-remove     — botão X
     .tag-typeahead__search          — wrapper do input
     .tag-typeahead__search-icon     — lupa
     .tag-typeahead__dropdown        — lista de resultados
     .tag-typeahead__option          — item do dropdown
     .tag-typeahead__option.is-active — destaque do keyboard nav
     .tag-typeahead__empty           — estado vazio do dropdown */
.tag-typeahead {
  position: relative;
  /* Largura do campo e do dropdown num só lugar: os dois têm de casar, senão a
     lista abre mais estreita (ou mais larga) que o campo. */
  --tag-typeahead-width: 440px;
}
.tag-typeahead__selected {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 8px;
  min-height: 28px;
}
/* Sem chip selecionado, a altura mínima só reserva espaço vazio acima do
   campo de busca — não tem o que estabilizar ainda. `:empty` cobre esse
   caso sem mudar a reserva de altura quando já há pelo menos um chip
   (onde ela evita o campo pular ao adicionar/remover). */
.tag-typeahead__selected:empty {
  display: none;
  margin-bottom: 0;
}
.tag-typeahead__chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 4px 4px 10px;
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-full);
  background: var(--color-accent-light);
  color: var(--color-accent);
  font-size: var(--font-xs);
  font-weight: 600;
}
.tag-typeahead__chip-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--color-accent);
  cursor: pointer;
  padding: 0;
  font-size: 14px;
  line-height: 1;
}
.tag-typeahead__chip-remove:hover {
  background: var(--color-accent);
  color: var(--color-text-inverse);
}
.tag-typeahead__search {
  position: relative;
  max-width: var(--tag-typeahead-width);
}
.tag-typeahead__search .form-input {
  min-height: 32px;
  padding: 4px 10px 4px 32px;
  font-size: var(--font-xs);
}
.tag-typeahead__search-icon {
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--color-text-muted);
  pointer-events: none;
}
.tag-typeahead__dropdown {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  width: 100%;
  max-width: var(--tag-typeahead-width);
  max-height: 260px;
  overflow-y: auto;
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  z-index: var(--z-drawer);
}
.tag-typeahead__dropdown[hidden] {
  display: none;
}
.tag-typeahead__option {
  padding: 6px 12px;
  font-size: var(--font-xs);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tag-typeahead__option:hover,
.tag-typeahead__option.is-active {
  background: var(--color-bg-surface-alt);
}
.tag-typeahead__empty {
  padding: 12px;
  text-align: center;
  color: var(--color-text-muted);
  font-size: var(--font-xs);
}

/* Master-Detail: layout lista + painel à direita, usado em abas de drawer
   com CRUD inline (Contatos do Cliente, Permissões/Horários do Usuário…).
   Container horizontal; mobile estreito empilha vertical.

   ``align-items: flex-start`` mantém o painel do form com altura natural: ele
   não acompanha a altura da tabela (que pode ser longa), garantindo que o
   rodapé com o botão Salvar fique sempre visível sem rolagem. */
.master-detail {
  display: flex;
  gap: 16px;
  align-items: flex-start;
}
.master-detail__list {
  flex: 1 1 60%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
/* Toolbar com botão "Incluir" alinhado à direita acima da tabela. */
.master-detail__toolbar {
  display: flex;
  justify-content: flex-end;
}
.master-detail__form {
  flex: 1 1 40%;
  min-width: 320px;
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
/* Placeholder centrado quando nenhum item está selecionado. */
.master-detail__placeholder {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  text-align: center;
  color: var(--color-text-muted);
  padding: 24px 16px;
}
.master-detail__placeholder p {
  margin: 0;
  font-size: var(--font-sm);
  max-width: 240px;
  line-height: 1.5;
}
.master-detail__panel {
  display: flex;
  flex-direction: column;
  gap: 12px;
  flex: 1;
}
.master-detail__panel-header {
  border-bottom: 1px solid var(--color-border);
  padding-bottom: 8px;
}
.master-detail__panel-title {
  margin: 0;
  font-size: var(--font-base);
  font-weight: 600;
  color: var(--color-text-primary);
}
.master-detail__panel-footer {
  margin-top: auto;
  padding-top: 12px;
  border-top: 1px solid var(--color-border);
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  flex-wrap: wrap;
}
/* Excluir empurrado para a esquerda — separação visual de "cancelar/salvar". */
.master-detail__panel-delete {
  margin-right: auto;
}
@media (max-width: 900px) {
  .master-detail {
    flex-direction: column;
  }
  .master-detail__list,
  .master-detail__form {
    flex: 1 1 auto;
    min-width: 0;
  }
}
/* <!-- /BLOCK: filters --> */

/* ==========================================================================
   10. TABELA
   ========================================================================== */
/* <!-- BLOCK: table --> */
.table-wrapper {
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.table-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
  border-bottom: 1px solid var(--color-border);
  flex-wrap: wrap;
  gap: 10px;
}
.table-header__title {
  font-size: var(--font-base);
  font-weight: 600;
  color: var(--color-text-primary);
}
.table-header__right {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Density control */
.table-density-control {
  display: flex;
  align-items: center;
  background: var(--color-bg-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.table-density-control [data-density] {
  padding: 5px 10px;
  font-size: var(--font-xs);
  font-weight: 600;
  color: var(--color-text-muted);
  cursor: pointer;
  transition:
    background var(--t-fast),
    color var(--t-fast);
  white-space: nowrap;
}
.table-density-control [data-density]:hover {
  background: var(--color-bg-hover);
  color: var(--color-text-primary);
}
.table-density-control [data-density].is-active {
  background: var(--color-accent);
  color: #fff;
}

.table-scroll {
  overflow-x: auto;
  /* Clipa o eixo vertical: a tabela não tem scroll vertical próprio no
     desktop (quem rola é o .main-content). Sem isto, ``overflow-x: auto``
     força ``overflow-y: auto`` implícito (spec CSS) e geraria uma barra de
     rolagem vertical indesejada. O scroll vertical próprio existe apenas no
     mobile (media query, com max-height). */
  overflow-y: hidden;
  scrollbar-width: thin;
  scrollbar-color: var(--color-border) transparent;
}
/* Modificador `--sticky-head`: o cabeçalho da tabela gruda no topo da tela
   enquanto a página rola, e as linhas correm por baixo dele.
   O `thead th` já é `sticky` no DS, mas `sticky` resolve contra o scroll
   container mais próximo — e tanto o `.table-wrapper` (`overflow: hidden`) como
   o `.table-scroll` (`overflow-x: auto`) são um. Aqui os dois voltam a
   `overflow: visible`, e quem rola passa a ser o `.main-content` — o scroll da
   página, um só.
   Não dê altura própria à área de dados para isto: scroll de dentro encurta a
   página, e aí o scroll dela acaba antes de o que está grudado alcançar o topo.
   Custo: esta tabela perde o scroll horizontal próprio. Use o modificador só
   onde as colunas caibam na largura do container (ex.: larguras em %). */
.table-wrapper--sticky-head {
  /* `visible` e não `clip`: `clip` não cria scroll container, mas cria contexto
     de recorte, e recorte sobre elemento grudado rende pintura fora de lugar.
     Sem recorte aqui, o canto arredondado sai do próprio `th` (regra abaixo). */
  overflow: visible;
}
.table-wrapper--sticky-head .table-scroll {
  overflow: visible;
}
/* O wrapper não recorta mais, então as pontas do cabeçalho acompanham o raio da
   borda na mão — senão o fundo cinza do `th` vaza o canto arredondado. */
.table-wrapper--sticky-head .data-table thead th:first-child {
  border-top-left-radius: var(--radius-md);
}
.table-wrapper--sticky-head .data-table thead th:last-child {
  border-top-right-radius: var(--radius-md);
}
/* Em `border-collapse: collapse` a borda pertence à tabela, não ao `th`: ela
   fica na posição original e não acompanha o cabeçalho grudado. A sombra
   interna redesenha o separador, então a linha que passa por baixo nunca
   encosta no texto do cabeçalho. */
.table-wrapper--sticky-head .data-table thead th {
  box-shadow: inset 0 -1.5px 0 var(--color-border);
}
/* Com uma `.segmented-row--sticky` grudada acima, o cabeçalho para logo abaixo
   dela; senão os dois disputam o topo e o cabeçalho fica escondido atrás.
   A fileira mede controle + 2px de borda do `.segmented` + 16px de padding
   (50px), e o cabeçalho para 2px ANTES disso, encostando por baixo dela (que
   tem `z-index` maior e o esconde). Encontro no pixel exato abriria uma fresta
   de subpixel em tela com escala fracionária (Windows a 125%/150%), e é por
   fresta assim que a linha da tabela aparece entre os dois. */
.segmented-row--sticky ~ .table-wrapper--sticky-head .data-table thead th {
  top: calc(var(--control-height) + 16px);
}
/* Quando há um `.filter-toolbar--sticky` antes na página (seção 09), o
   cabeçalho soma a altura REAL do toolbar grudado (`--sticky-toolbar-h`,
   publicada por `scroll-collapse.js` via `ResizeObserver` — 0 quando o
   toolbar não está pinado) menos os mesmos 16px do `top: -16px` do
   toolbar, que fecha o padding-top fixo do `.main-content`. Não dá pra
   usar um valor fixo por estado aqui: condensado a altura é previsível
   (~48px), mas ainda expandido-e-pinado (revelado ao subir a rolagem, sem
   voltar ao topo) ela varia com a largura — a busca e a grade de filtros
   quebram linha diferente conforme o viewport. Medir de verdade é o que
   garante que a fileira/cabeçalho nunca fiquem escondidos atrás do
   toolbar nesse estado. Encadeia por `.segmented-row--sticky` (não só
   `~ .table-wrapper--sticky-head`) de propósito: com a mesma
   especificidade da regra genérica acima, as duas empatariam e quem
   vence seria só a ordem no arquivo — uma reorganização futura da seção
   inverteria isso em silêncio. Encadear a fileira também é mais específico
   de verdade (reflete a estrutura real: toolbar → fileira → tabela), não
   uma amarração por ordem. */
.filter-toolbar--sticky ~ .segmented-row--sticky
  ~ .table-wrapper--sticky-head
  .data-table
  thead
  th {
  top: calc(var(--control-height) + 16px - 16px + var(--sticky-toolbar-h, 0px));
}
.table-scroll::-webkit-scrollbar {
  height: 5px;
}
.table-scroll::-webkit-scrollbar-thumb {
  background: var(--color-border);
  border-radius: 4px;
}
/* Cabeçalho grudado COM scroll horizontal preservado: quem rola é o próprio
   `.table-scroll`, nos dois eixos, e o `thead th` (já `position: sticky; top: 0`)
   resolve contra ele. Use este quando a tabela tem coluna de ações pinada ou
   colunas que não cabem na largura do container; o `--sticky-head` é para o caso
   oposto (scroll da página, tabela que cabe). */
.table-wrapper--sticky-head-inner .table-scroll {
  overflow-y: auto;
  max-height: var(--table-scroll-max-h, 70dvh);
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  min-width: 700px;
}
/* Sem o min-width de listagem de página — usada em tabela pequena dentro de
   drawer/modal, onde o container já é mais estreito que 700px. */
.data-table--fit {
  min-width: 0;
}

/* Normal */
.data-table thead th {
  padding: 5px 12px;
  text-align: left;
  font-size: var(--font-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-muted);
  background: var(--color-bg-surface-alt);
  border-bottom: 1.5px solid var(--color-border);
  white-space: nowrap;
  /* Header fixo: gruda no topo do .table-scroll durante o scroll vertical
     (mobile) e mantém o cabeçalho visível. O background opaco impede que as
     linhas vazem por baixo. Em border-collapse o sticky precisa ficar no
     th (não no thead/tr) para funcionar no Chrome. */
  position: sticky;
  top: 0;
  z-index: 2;
}
/* Colunas ordenáveis — JS aplica is-sortable / is-sort-asc / is-sort-desc e
   injeta o ícone Lucide ``.sort-icon`` (ver designsystem/js/components/
   sort-header.js). Página é dona da regra de toggle (asc/desc/off). */
.data-table thead th.is-sortable {
  cursor: pointer;
  user-select: none;
  padding-right: 26px;
}
.data-table thead th.is-sortable .sort-icon {
  position: absolute;
  right: 8px;
  top: 50%;
  width: 12px;
  height: 12px;
  transform: translateY(-50%);
  color: var(--color-text-muted);
  opacity: 0.45;
  transition:
    opacity var(--t-fast),
    color var(--t-fast);
  pointer-events: none;
}
.data-table thead th.is-sortable:hover .sort-icon {
  opacity: 0.85;
}
.data-table thead th.is-sort-asc,
.data-table thead th.is-sort-desc {
  color: var(--color-accent);
}
.data-table thead th.is-sort-asc .sort-icon,
.data-table thead th.is-sort-desc .sort-icon {
  color: var(--color-accent);
  opacity: 1;
}
/* Default da tabela: célula NUNCA quebra linha. Linha que precisa
   quebrar usa ``cell-wrap`` (opt-in explícito); célula com texto longo
   que precisa ellipsis + tooltip usa ``cell-truncate``. Sem isso, qualquer
   td com texto longo arrebenta a altura da linha — vide regra
   "Linha não pode ficar gigante porque uma célula tem texto comprido"
   em FRONTEND_STYLE_GUIDE.md. */
.data-table tbody td {
  padding: 2px 12px;
  vertical-align: middle;
  line-height: 1.25;
  white-space: nowrap;
}
.data-table tbody tr:not(:last-child) td {
  border-bottom: 1px solid var(--color-border);
}
/* Linha clicável por padrão — em todas as tabelas, clicar na linha abre o
   detalhe/edição do registro. JS é responsável por escutar o clique
   e disparar a ação; o CSS só sinaliza visualmente (cursor de link). */
.data-table tbody tr,
.data-table tbody tr td {
  cursor: pointer;
}
.data-table tbody tr {
  transition: background var(--t-fast);
}
.data-table tbody tr:hover td {
  background: rgba(var(--color-accent-rgb), 0.07);
}
/* Elementos interativos dentro da linha mantêm seu próprio cursor. */
.data-table tbody tr td input[type="checkbox"],
.data-table tbody tr td button,
.data-table tbody tr td a {
  cursor: pointer;
}
.data-table tbody tr td input[type="text"],
.data-table tbody tr td input[type="email"],
.data-table tbody tr td input[type="number"],
.data-table tbody tr td select,
.data-table tbody tr td textarea {
  cursor: text;
}
/* Coluna de ações: largura de conteúdo (``width: 1%`` + ``nowrap``), à
   direita; as colunas de dados absorvem a folga restante. */
.data-table thead th.col-actions,
.data-table td.col-actions {
  text-align: center;
  width: 1%;
  white-space: nowrap;
}

/* Coluna de seleção em massa — checkbox compacto, sempre na primeira
   coluna. Ocupa largura mínima para não desperdiçar espaço, alinhado
   ao centro para que header e linha fiquem coincidentes verticalmente. */
.data-table thead th.col-bulk-select,
.data-table td.col-bulk-select {
  width: 32px;
  padding-left: 8px;
  padding-right: 8px;
  text-align: center;
}
.data-table td.col-bulk-select .form-checkbox,
.data-table th.col-bulk-select .form-checkbox {
  margin: 0;
  cursor: pointer;
}

/* Dropdown da toolbar para ações em massa — segue a aparência de
   ``custom-select``: trigger via botão DS, painel abaixo com itens em
   coluna. Item é um ``<button>`` para herdar focus/hover do DS. */
.bulk-actions-menu {
  position: relative;
  display: inline-block;
}
.bulk-actions-menu__panel {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  min-width: 240px;
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: 4px 0;
  z-index: 20;
  display: none;
}
.bulk-actions-menu.is-open .bulk-actions-menu__panel {
  display: block;
}
.bulk-actions-menu__item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  background: transparent;
  border: 0;
  text-align: left;
  padding: 8px 12px;
  font-size: var(--font-size-sm);
  color: var(--color-text);
  cursor: pointer;
}
.bulk-actions-menu__item:hover,
.bulk-actions-menu__item:focus-visible {
  background: var(--color-bg-hover);
  outline: none;
}
.bulk-actions-menu__item[disabled] {
  color: var(--color-text-muted);
  cursor: not-allowed;
  background: transparent;
}
.bulk-actions-menu__sep {
  height: 1px;
  background: var(--color-border);
  margin: 4px 0;
}

/* Seletor de dias da semana — toolbar de atalhos + grid de checkboxes.
   Reusável em qualquer aba que precise selecionar dias da semana
   (Cliente: dias de integração; CCT: dias de envio). */
.weekday-picker__toolbar {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}
.weekday-picker__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 8px;
}

/* Ações nunca empilham na vertical — quando não couberem na horizontal,
   substitua por um dropdown ("…") em vez de quebrar a linha. */
.data-table td.col-actions {
  white-space: nowrap;
}
.data-table td.col-actions > .table-actions,
.data-table td.col-actions > * {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  flex-wrap: nowrap;
}
.data-table td.col-actions > .table-actions {
  justify-content: center;
}

/* ==========================================================================
   Pin da coluna de ações — botão no header + coluna fixa (sticky right).
   Preferência GLOBAL persistida em localStorage (mi7-table-pin-actions);
   gerenciada por PinActionsManager (js/core.js). A classe .data-table--pin-actions
   é alternada no <table>.
   ========================================================================== */

/* Botão de pin injetado ao lado do rótulo "Ações" no header. */
.table-pin-actions {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  margin-left: 6px;
  padding: 0;
  vertical-align: middle;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text-muted);
  cursor: pointer;
  transition:
    color var(--t-fast),
    background var(--t-fast);
}
.table-pin-actions:hover,
.table-pin-actions:focus-visible {
  background: var(--color-bg-hover);
  color: var(--color-text-primary);
  outline: none;
}
/* Estado fixado: cor accent + pílula tonal, distinto do estado solto
   (muted). O usuário identifica de relance se a coluna está ou não presa. */
.table-pin-actions.is-active,
.table-pin-actions.is-active:hover,
.table-pin-actions.is-active:focus-visible {
  color: var(--color-accent);
  background: var(--color-accent-light);
}
/* Ícone rotacionado reforça o estado "fixado". */
.table-pin-actions.is-active i {
  transform: rotate(45deg);
}

/* Coluna de ações fixa à direita durante o scroll horizontal. */
.data-table--pin-actions th.col-actions,
.data-table--pin-actions td.col-actions {
  position: sticky;
  right: 0;
  /* Separador/sombra à esquerda para descolar do conteúdo que rola sob. */
  box-shadow: -8px 0 8px -8px rgba(0, 0, 0, 0.18);
}
/* Corpo: fundo opaco obscurece as células que passam por baixo no scroll. */
.data-table--pin-actions tbody td.col-actions {
  background-color: var(--color-bg-surface);
  z-index: 1;
}
/* Hover mantém o tom accent da linha, mas opaco (gradiente sobre o fundo). */
.data-table--pin-actions tbody tr:hover td.col-actions {
  background-color: var(--color-bg-surface);
  background-image: linear-gradient(
    rgba(var(--color-accent-rgb), 0.07),
    rgba(var(--color-accent-rgb), 0.07)
  );
}
/* Header da coluna é o "canto" (sticky topo + direita): acima de tudo.
   O th já tem background opaco e z-index:2 em .data-table thead th. */
.data-table--pin-actions thead th.col-actions {
  z-index: 3;
}

/* Duas últimas colunas fixas à direita: a etapa da tratativa acompanha a
   coluna de ações, deslocada pela largura real dela (`--pin-tail-offset`, que
   a página mede a cada pintura). */
.data-table--pin-tail th.col-actions,
.data-table--pin-tail td.col-actions,
.data-table--pin-tail th.col-stage,
.data-table--pin-tail td.col-stage {
  position: sticky;
}
.data-table--pin-tail th.col-actions,
.data-table--pin-tail td.col-actions {
  right: 0;
}
.data-table--pin-tail th.col-stage,
.data-table--pin-tail td.col-stage {
  right: var(--pin-tail-offset, 0);
  /* Fio contínuo à esquerda da cauda, mostrando onde a dupla fixa começa. Em
     sombra interna porque `border-collapse: collapse` deixa a borda com a
     tabela, que rola. */
  box-shadow: inset 1px 0 0 var(--color-border-strong);
}
/* A sombra da cauda entra só quando existe coluna passando por baixo dela. */
.data-table--pin-tail.is-scrolled th.col-stage,
.data-table--pin-tail.is-scrolled td.col-stage {
  box-shadow:
    inset 1px 0 0 var(--color-border-strong),
    -10px 0 10px -8px rgba(0, 0, 0, 0.28);
}
/* Rolagem horizontal visível em repouso na tabela de cauda fixa, que é onde
   existem colunas escondidas sob a cauda. */
.table-scroll:has(.data-table--pin-tail) {
  scrollbar-color: var(--color-border-strong) var(--color-bg-overlay);
}
.table-scroll:has(.data-table--pin-tail)::-webkit-scrollbar {
  height: 10px;
}
.table-scroll:has(.data-table--pin-tail)::-webkit-scrollbar-track {
  background: var(--color-bg-overlay);
  border-radius: 5px;
}
.table-scroll:has(.data-table--pin-tail)::-webkit-scrollbar-thumb {
  background: var(--color-border-strong);
  border-radius: 5px;
}
/* Largura fixa: o selo de etapa muda de tamanho com o rótulo, e a coluna fixa
   mantém a mesma largura a cada pintura. Cabe o rótulo mais longo
   ("2ª Reincidência") na fonte mono da tabela. */
.col-stage {
  width: 168px;
  min-width: 168px;
}
/* O selo nunca passa da célula: rótulo maior corta com reticência em vez de
   empurrar a coluna fixa. */
.col-stage .badge {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.data-table--pin-tail tbody td.col-actions,
.data-table--pin-tail tbody td.col-stage {
  background-color: var(--color-bg-surface);
  z-index: 1;
}
.data-table--pin-tail tbody tr:hover td.col-actions,
.data-table--pin-tail tbody tr:hover td.col-stage {
  background-color: var(--color-bg-surface);
  background-image: linear-gradient(
    rgba(var(--color-accent-rgb), 0.07),
    rgba(var(--color-accent-rgb), 0.07)
  );
}
.data-table--pin-tail thead th.col-actions,
.data-table--pin-tail thead th.col-stage {
  z-index: 3;
}

/* Com a coluna fixada cada td.col-actions vira um stacking context próprio
   (sticky + z-index:1). O tooltip (::after) dos botões da 1ª linha ficava
   coberto — pra cima pelo header (z-index:3), pra baixo pela célula sticky
   da linha seguinte (z-index:1, mais à frente no DOM). Ao passar o mouse,
   elevamos a célula de ações acima do header e das vizinhas para o balão
   do tooltip aparecer. Vale para qualquer linha (a 1ª é a mais afetada). */
.data-table--pin-actions tbody td.col-actions:hover {
  z-index: 4;
}

/* Toggle de ativação em tabelas. A cor reflete o estado atual do
   registro: ativo verde, inativo vermelho — o usuário identifica o
   estado de relance. No hover do registro ativo a cor vira vermelho,
   antecipando a ação destrutiva (vai inativar). No registro inativo o
   hover vira verde, antecipando a ativação.
   Especificidade dupla (``.table-action-btn.action-toggle-*``) para
   sobrescrever o ``color: muted`` do ``.table-action-btn`` que vem
   depois no arquivo. */
.table-action-btn.action-toggle-on {
  color: var(--color-success);
}
.table-action-btn.action-toggle-off {
  color: var(--color-danger);
}
.table-action-btn.action-toggle-on:hover,
.table-action-btn.action-toggle-on:focus-visible {
  color: var(--color-danger);
}
.table-action-btn.action-toggle-off:hover,
.table-action-btn.action-toggle-off:focus-visible {
  color: var(--color-success);
}

/* Truncamento opt-in: célula com texto longo encurta com elipse e mantém
   a altura da linha. Combine com `data-ui-tooltip` para mostrar o texto
   completo no hover.
   Para o ellipsis funcionar, a coluna precisa de largura limitada — defina
   ``style="max-width:200px"`` no <th> correspondente ou aplique
   ``.data-table--fixed`` no <table> (table-layout:fixed).
   O overflow do ellipsis vive no wrapper interno (`.cell-truncate__inner`,
   criado automaticamente por `enhanceTruncatedCells`), que também aplica o
   `data-ui-tooltip` com o texto completo — exibido pelo balão global
   `.ui-tooltip` (portado ao body, sem clipping). */
.data-table td.cell-truncate {
  max-width: 0;
  position: relative;
}
.data-table td.cell-truncate > .cell-truncate__inner {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Wrap explícito: célula com observações/descrições que devem quebrar.
   Ela cresce só na linha em que aparece — as demais permanecem compactas. */
.data-table td.cell-wrap {
  white-space: normal;
}

/* Layout fixo para colunas com ellipsis homogêneo. Use quando todas as
   colunas tiverem largura previsível. */
.data-table--fixed {
  table-layout: fixed;
}

/* Célula de duas linhas: título em destaque (ex.: código) e subtítulo
   truncado com reticências (ex.: descrição) — usada onde uma linha de
   tabela mostra dois campos relacionados na mesma célula, sem virar duas
   colunas. `max-width:0` é o mesmo truque de `.cell-truncate` para a coluna
   não crescer além da largura definida no `<th>`. */
.data-table td.cell-two-line {
  max-width: 0;
}
.cell-two-line__subtitle {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--color-text-muted);
  font-size: var(--font-xs);
}

/* Compact — mesma densidade da tabela padrão. Usada em drawers para que a
   tabela de dentro fique tão compacta quanto as listagens de fora. */
.data-table--compact thead th {
  padding: 5px 12px;
}
.data-table--compact tbody td {
  padding: 2px 12px;
  font-size: 12px;
}

/* Dense — ainda mais apertada (listas longas em pouco espaço). */
.data-table--dense thead th {
  padding: 3px 10px;
}
.data-table--dense tbody td {
  padding: 1px 10px;
  font-size: 11px;
}

/* Comfortable — linhas com respiro vertical. Para tabelas SEM coluna de ações
   (read-only: modais e abas de drawer), onde o padding tight padrão (2px)
   deixa as linhas coladas perto das listagens cujas linhas têm a altura dos
   botões de ação. Opt-in: adicione `data-table--comfortable` ao <table>. */
.data-table--comfortable tbody td {
  padding-top: 7px;
  padding-bottom: 7px;
}

.table-cell__primary {
  font-weight: 600;
  color: var(--color-text-primary);
}
.table-cell__secondary {
  color: var(--color-text-secondary);
  font-size: var(--font-xs);
  margin-top: 1px;
}

/* Ações */
.table-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 2px;
}
.table-action-btn {
  width: 28px;
  height: 28px;
  border-radius: var(--radius-xs);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text-muted);
  transition:
    background var(--t-fast),
    color var(--t-fast);
}
/* Hover ÚNICO para toda ação de linha: azul info (destaque imediato em
   tema claro e escuro). Proibido override de cor por ação — a exceção é
   o par toggle-on/off acima, cuja cor antecipa o efeito de
   ativar/desativar. Não usar --color-accent em hover: contraste baixo
   demais sobre o fundo da linha. */
.table-action-btn:hover {
  background: var(--color-bg-surface-alt);
  color: var(--color-info);
}

/* Estado desabilitado: ação de linha indisponível (ex.: excluir só do dia).
   O atributo `disabled` nativo já impede o clique; a classe `is-disabled`
   garante o estado visual mesmo em <span>/<a>. Declarado DEPOIS do `:hover`
   base e com a mesma especificidade: no hover do botão desabilitado estas
   regras vencem por ordem de fonte, neutralizando background e cor SEM um
   seletor `:hover` próprio (a política do DS reserva override de hover ao
   par toggle-on/off — ver test_action_button_hover.py). */
.table-action-btn:disabled,
.table-action-btn.is-disabled {
  color: var(--color-text-muted);
  background: transparent;
  opacity: 0.45;
  cursor: not-allowed;
}

/* Custom Tooltips — padrão DS para qualquer elemento.
   Use `data-ui-tooltip="Texto"` em <button>/<a>/<span>/etc.
   Combine com `aria-label` para acessibilidade.

   O balão é um único nó ``.ui-tooltip`` portado para ``document.body`` e
   posicionado via JS (``components/ui-tooltip.js``) com ``position: fixed``.
   Isso evita o clipping que o antigo pseudo-elemento ``::after`` sofria
   dentro de ``overflow:hidden`` (``.table-wrapper``) ou ``transform``
   (``.side-drawer``) — ex.: tooltip alto da 1ª linha cortado no topo. Por
   isso não há mais regras de âncora por posição (1ª linha, bordas da
   paginação, última ação): o JS calcula flip vertical + clamp horizontal. */
.ui-tooltip {
  position: fixed;
  z-index: var(--z-tooltip);
  max-width: 360px;
  width: max-content;
  padding: 4px 8px;
  background: var(--color-brand-navy);
  color: var(--color-text-inverse);
  font-size: var(--font-xs);
  font-weight: 400;
  line-height: 1.4;
  text-align: left;
  white-space: normal;
  word-break: break-word;
  border-radius: var(--radius-xs);
  box-shadow: var(--shadow-sm);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-fast);
}
.ui-tooltip.is-visible {
  opacity: 1;
}
/* Variantes semânticas (``data-ui-tooltip-variant``): o balão assume a cor do
   elemento apontado — ex.: fatia de gráfico. Métrica maior que a do balão de
   botão/tabela, porque aqui ele é o rótulo de leitura do dado, não uma dica. */
.ui-tooltip--success,
.ui-tooltip--danger,
.ui-tooltip--warning,
.ui-tooltip--info,
.ui-tooltip--neutral,
.ui-tooltip--accent {
  padding: 8px 12px;
  border-radius: var(--radius-md);
  font-size: var(--font-sm);
  font-weight: 400;
}
.ui-tooltip--success,
.ui-tooltip--danger,
.ui-tooltip--warning,
.ui-tooltip--info,
.ui-tooltip--neutral {
  color: var(--color-text-inverse);
}
.ui-tooltip__value {
  margin-left: 5px;
  font-weight: 600;
}
.ui-tooltip--success {
  background: var(--color-success);
}
.ui-tooltip--danger {
  background: var(--color-danger);
}
.ui-tooltip--warning {
  background: var(--color-warning);
}
.ui-tooltip--info {
  background: var(--color-info);
}
.ui-tooltip--neutral {
  background: var(--color-text-secondary);
}
.ui-tooltip--accent {
  background: var(--color-accent);
  color: var(--color-text-on-accent);
}

/* Table Hover Minicard (Detalhes) */
.table-hover-card-wrapper {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  cursor: help;
}
.table-hover-card {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-md);
  border-radius: var(--radius-md);
  padding: 12px 14px;
  min-width: 220px;
  z-index: var(--z-tooltip);
  opacity: 0;
  pointer-events: none;
  transition: all var(--t-fast);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.table-hover-card-wrapper:hover .table-hover-card {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  pointer-events: auto;
}
.table-hover-card__row {
  display: flex;
  justify-content: space-between;
  font-size: var(--font-xs);
}
.table-hover-card__label {
  color: var(--color-text-muted);
  font-weight: 600;
  text-transform: uppercase;
}
.table-hover-card__value {
  color: var(--color-text-primary);
  font-weight: 500;
  text-align: right;
}
.table-hover-card::after {
  /* seta */
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border-width: 5px;
  border-style: solid;
  border-color: var(--color-bg-surface) transparent transparent transparent;
}
.table-hover-card::before {
  /* borda da seta */
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border-width: 6px;
  border-style: solid;
  border-color: var(--color-border) transparent transparent transparent;
  margin-top: 1px;
  z-index: -1;
}

/* Estado vazio/erro do corpo da tabela (linha única, centralizada). */
.data-table__empty {
  text-align: center;
  padding: 32px;
  color: var(--color-text-muted);
}
.data-table__empty--error {
  color: var(--color-danger);
}

/* Conteúdo da linha-grupo de uma listagem agrupada (o `<td colspan>` que abre
   as linhas-filhas): botão de expandir, rótulo e badges na mesma linha.
   `.table-action-btn` é `display: flex` — solto na célula ele viraria um bloco
   e jogaria o texto para a linha de baixo. */
.data-table__group-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
/* Grupo aberto (`.is-expanded` no `<tr>`, quem põe é o JS da página): fundo
   próprio na linha do `>`, que passa a ler como cabeçalho das filhas que
   abriu. O fundo vai no `td` porque é assim que o DS pinta linha (ver o
   `:hover` de `.data-table tbody tr`). */
.data-table tbody tr.is-expanded > td {
  background: var(--color-bg-surface-alt);
}
/* Hover explícito, senão a regra de cima (mesma especificidade, declarada
   depois) engoliria o realce de linha justo no grupo aberto. */
.data-table tbody tr.is-expanded:hover > td {
  background: rgba(var(--color-accent-rgb), 0.12);
}

/* Larguras fixas das colunas de filtro do toolbar (substitui flex inline). */
.filter-col--180 {
  flex: 0 0 180px;
}
.filter-col--200 {
  flex: 0 0 200px;
}
.filter-col--220 {
  flex: 0 0 220px;
}
.filter-col--240 {
  flex: 0 0 240px;
}
.filter-col--280 {
  flex: 0 0 280px;
}

/* Footer / Paginação */
.table-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 16px;
  border-top: 1px solid var(--color-border);
  background: var(--color-bg-surface-alt);
  flex-wrap: wrap;
  gap: 10px;
}
.table-footer__info {
  font-size: var(--font-xs);
  color: var(--color-text-muted);
}
.table-footer__controls {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.table-pagination {
  display: flex;
  align-items: center;
  gap: 3px;
}
.pagination-btn {
  min-width: 28px;
  height: 28px;
  padding: 0 4px;
  border-radius: var(--radius-xs);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-xs);
  font-weight: 600;
  color: var(--color-text-secondary);
  transition:
    background var(--t-fast),
    color var(--t-fast);
}
.pagination-btn:hover {
  background: var(--color-bg-surface);
}
.pagination-btn.is-active {
  background: var(--color-accent);
  color: var(--color-text-inverse);
}
.pagination-btn:disabled {
  opacity: 0.4;
  pointer-events: none;
}

/* Input que substitui o botão da página atual em paginações com muitas
   páginas (modo condensado). Visualmente parece um campo editável (fundo
   claro + borda accent grossa) — distinto dos botões numéricos sólidos —
   sinalizando "página atual + você pode digitar e Enter para saltar". */
.pagination-input {
  width: 52px;
  height: 28px;
  padding: 0 6px;
  border: 1.5px solid var(--color-accent);
  border-radius: var(--radius-xs);
  background: var(--color-accent-light);
  color: var(--color-accent-dark);
  font-size: var(--font-xs);
  font-weight: 600;
  text-align: center;
  -moz-appearance: textfield;
  transition:
    border-color var(--t-fast),
    box-shadow var(--t-fast);
}
.pagination-input::-webkit-inner-spin-button,
.pagination-input::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.pagination-input:focus {
  outline: none;
  box-shadow: 0 0 0 3px rgba(var(--color-accent-rgb), 0.28);
}
.pagination-input.is-invalid {
  border-color: var(--color-danger);
  color: var(--color-danger);
  box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.22);
  animation: pagination-shake 0.3s ease;
}

/* Go-to page */
.pagination-goto {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-left: 8px;
  padding-left: 8px;
  border-left: 1px solid var(--color-border);
}
.pagination-goto__label {
  font-size: var(--font-xs);
  color: var(--color-text-muted);
  white-space: nowrap;
}
.pagination-goto__input {
  width: 44px;
  height: 28px;
  padding: 0 4px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xs);
  background: var(--color-bg-input);
  color: var(--color-text-primary);
  font-size: var(--font-xs);
  font-weight: 600;
  text-align: center;
  transition:
    border-color var(--t-fast),
    box-shadow var(--t-fast);
  -moz-appearance: textfield;
}
.pagination-goto__input::-webkit-inner-spin-button,
.pagination-goto__input::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.pagination-goto__input:focus {
  outline: none;
  border-color: var(--color-accent);
  box-shadow: 0 0 0 3px rgba(var(--color-accent-rgb), 0.18);
}
.pagination-goto__input.is-invalid {
  border-color: var(--color-danger);
  box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.18);
  animation: pagination-shake 0.3s ease;
}
@keyframes pagination-shake {
  0%,
  100% {
    transform: translateX(0);
  }
  25% {
    transform: translateX(-3px);
  }
  75% {
    transform: translateX(3px);
  }
}

/* Seletor de itens por página (preferência global, ver page-size.js) */
.pagination-page-size {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding-left: 8px;
  border-left: 1px solid var(--color-border);
}
.pagination-page-size__label {
  font-size: var(--font-xs);
  color: var(--color-text-muted);
  white-space: nowrap;
}
/* Itens por página é navegação, não filtro opcional — sempre tem um valor
   (ver `#selleranalysis-seller-select` em selleranalysis.css, mesmo padrão).
   Esconde o "×" de limpar que `custom-select.js` injeta por padrão quando há
   seleção, que zeraria `page_size` (sem opção válida "nenhum"). */
.pagination-page-size__select .custom-select__clear {
  display: none;
}
.pagination-page-size__select {
  width: 64px;
}
.pagination-page-size__select .custom-select__trigger {
  height: 28px;
  padding: 0 8px;
  font-size: var(--font-xs);
}

/* Skeleton */
.skeleton-line {
  height: 14px;
  border-radius: 4px;
  background: linear-gradient(
    90deg,
    var(--color-bg-surface-alt) 25%,
    var(--color-border) 50%,
    var(--color-bg-surface-alt) 75%
  );
  background-size: 200% 100%;
  animation: skeleton-shimmer 1.4s infinite;
}
@keyframes skeleton-shimmer {
  0% {
    background-position: 200% 0;
  }
  100% {
    background-position: -200% 0;
  }
}
/* Variante de bloco do `.skeleton-line` — gráfico e card, mesmo shimmer.
   A altura final vem inline (`showChartSkeleton`), reservando o espaço
   exato que o gráfico real vai ocupar. */
.skeleton-block {
  width: 100%;
  border-radius: var(--radius-md);
  background: linear-gradient(
    90deg,
    var(--color-bg-surface-alt) 25%,
    var(--color-border) 50%,
    var(--color-bg-surface-alt) 75%
  );
  background-size: 200% 100%;
  animation: skeleton-shimmer 1.4s infinite;
}
/* Linha em operação (ex.: toggle ativo/inativo aguardando o PATCH): opaca e
   sem clique até a resposta chegar. */
.data-table tr[aria-busy="true"] {
  opacity: 0.5;
  pointer-events: none;
}
/* Escrita de linha no ar: a tabela inteira para de aceitar clique até a
   resposta chegar. */
.data-table.is-busy tbody {
  pointer-events: none;
}
/* <!-- /BLOCK: table --> */

/* ==========================================================================
   11. CARDS / DASHBOARD
   ========================================================================== */
.card {
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 20px 24px;
  box-shadow: var(--shadow-sm);
}
.card__title {
  font-size: var(--font-base);
  font-weight: 600;
  color: var(--color-text-primary);
  margin-bottom: 16px;
}

/* Empilhamento vertical de cards, um abaixo do outro. Espaça sem exigir
   margin inline por página. */
.card + .card {
  margin-top: 16px;
}

/* Miniatura de imagem vinda de URL externa (foto do produto do vendedor).
   Quadro fixo com `contain`: a proporção original é preservada e a moldura
   não varia com a imagem que o vendedor publicou. */
.thumb {
  width: 96px;
  height: 96px;
  object-fit: contain;
  background: var(--color-bg-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  transition:
    width 150ms ease,
    height 150ms ease;
}
/* Alterna com o botão "Expandir"/"Recolher" (ex.: drawer de match) — sem
   componente novo de galeria, só um tamanho maior da mesma miniatura. */
.thumb--expanded {
  width: 240px;
  height: 240px;
}

/* KPI Cards */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
  margin-bottom: 24px;
}
/* Como último elemento de um `.card` (ex.: o card "Por ocorrência" do
   relatório de política), a margem acima soma com o padding do `.card` e
   sobra um vão vazio grande no fim — os outros cards da tela terminam logo
   após o último texto, sem essa folga extra. */
.card > .kpi-grid:last-child {
  margin-bottom: 0;
}
.kpi-card {
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 20px;
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 10px;
  position: relative;
  overflow: hidden;
  transition:
    box-shadow var(--t-fast),
    transform var(--t-fast);
}
/* Barra de identidade — gradiente da marca no topo do card */
.kpi-card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: var(--gradient-brand);
}
.kpi-card:hover {
  box-shadow:
    var(--shadow-lg),
    0 0 0 1px rgba(var(--color-accent-rgb), 0.15);
  transform: translateY(-3px);
}
.kpi-card__label {
  font-size: var(--font-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-muted);
}
.kpi-card__value {
  font-size: 1.875rem;
  font-weight: 800;
  color: var(--color-text-primary);
  line-height: 1;
}
.kpi-card__change {
  font-size: var(--font-xs);
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 4px;
}
.kpi-card__change.up {
  color: var(--color-success);
}
.kpi-card__change.down {
  color: var(--color-danger);
}
.kpi-card__icon {
  position: absolute;
  top: 16px;
  right: 16px;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0.15;
  font-size: 22px;
}

/* Shortcut cards na home */
.shortcut-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 12px;
  margin-bottom: 24px;
}
.shortcut-card {
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 18px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  cursor: pointer;
  transition:
    box-shadow var(--t-fast),
    border-color var(--t-fast),
    transform var(--t-fast);
  text-decoration: none;
}
.shortcut-card:hover {
  border-color: transparent;
  background:
    linear-gradient(var(--color-bg-surface), var(--color-bg-surface)) padding-box,
    linear-gradient(135deg, var(--color-brand-green) 0%, var(--color-brand-sky) 100%) border-box;
  box-shadow: var(--shadow-lg);
  transform: translateY(-3px);
}
.shortcut-card__icon {
  color: var(--color-accent);
}
.shortcut-card__title {
  font-size: var(--font-sm);
  font-weight: 600;
  color: var(--color-text-primary);
}
.shortcut-card__desc {
  font-size: var(--font-xs);
  color: var(--color-text-muted);
}

/* ==========================================================================
   12. CODE BLOCK (páginas de documentação)
   ========================================================================== */
.code-demo-section {
  margin-bottom: 32px;
}
.code-demo-section__title {
  font-size: var(--font-sm);
  font-weight: 700;
  color: var(--color-text-primary);
  margin-bottom: 12px;
  padding-bottom: 8px;
  border-bottom: 2px solid;
  border-image: var(--gradient-brand) 1;
  display: inline-block;
}
.code-demo-row {
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
  margin-bottom: 16px;
  box-shadow: var(--shadow-sm);
}
.code-demo-row__preview {
  padding: 24px 20px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  border-bottom: 1px solid var(--color-border);
  background: var(--color-bg-base);
}
.code-demo-row__code {
  padding: 0;
  background: var(--color-brand-navy);
  position: relative;
}
[data-theme="dark"] .code-demo-row__code {
  background: #0b0d18;
}
.code-demo-row__code pre {
  overflow-x: auto;
  padding: 16px 20px;
  margin: 0;
  font-family: "JetBrains Mono", "Fira Code", monospace;
  font-size: 0.775rem;
  line-height: 1.65;
  color: #c8cddf;
}
.code-demo-row__code code .kw {
  color: #569cd6;
}
.code-demo-row__code code .str {
  color: #ce9178;
}
.code-demo-row__code code .cm {
  color: #6a9955;
  font-style: italic;
}
.code-demo-row__code code .fn {
  color: #dcdcaa;
}
.code-demo-row__code code .va {
  color: #9cdcfe;
}

.copy-btn {
  position: absolute;
  top: 10px;
  right: 10px;
  background: rgba(255, 255, 255, 0.08);
  color: rgba(255, 255, 255, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: var(--radius-xs);
  padding: 4px 10px;
  font-size: var(--font-xs);
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  transition:
    background var(--t-fast),
    color var(--t-fast);
}
.copy-btn:hover {
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
}

/* Page Title */
.page-title {
  font-size: var(--font-xl);
  font-weight: 700;
  color: var(--color-text-primary);
  margin-bottom: 4px;
  padding-bottom: 12px;
  position: relative;
}
/* Traço de identidade abaixo do título de cada página */
.page-title::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 36px;
  height: 3px;
  background: var(--gradient-brand);
  border-radius: 2px;
}
.page-subtitle {
  font-size: var(--font-sm);
  color: var(--color-text-secondary);
  margin-bottom: 24px;
}

/* Page Header — cabeçalho compacto que aproveita a área útil: título (menor)
   e subtítulo na MESMA faixa, separados por um divisor vertical, com uma
   linha fina sob a largura do conteúdo (não a largura total da tela). O
   container seguinte (toolbar/tabela) fica logo abaixo, perto mas não
   grudado. Envolve ``.page-title`` + ``.page-subtitle``; quando presente,
   neutraliza o espaçamento e o traço de 36px herdados das versões soltas. */
.page-header {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  width: fit-content;
  max-width: 100%;
  margin-bottom: 14px;
  padding-bottom: 8px;
}
/* Linha de identidade (gradiente da marca) sob a largura do conteúdo —
   mesmo estilo do antigo traço de 36px do .page-title, porém abrangendo
   título + subtítulo. */
.page-header::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 3px;
  background: var(--gradient-brand);
  border-radius: 2px;
}
.page-header .page-title {
  font-size: var(--font-lg);
  margin-bottom: 0;
  padding-bottom: 0;
}
.page-header .page-title::after {
  content: none;
}
.page-header .page-subtitle {
  margin-bottom: 0;
}
/* Divisor vertical elegante entre título e subtítulo (não o caractere "|"). */
.page-header .page-subtitle::before {
  content: "";
  display: inline-block;
  width: 2px;
  height: 1.05em;
  margin: 0 12px;
  background: var(--color-border);
  vertical-align: -0.15em;
  border-radius: 1px;
}
.section-divider {
  border: none;
  border-top: 1px solid var(--color-border);
  margin: 28px 0;
}

/* ==========================================================================
   13. UTILITÁRIOS / MISC
   ========================================================================== */
.u-text-muted {
  color: var(--color-text-muted);
}
.u-text-sm {
  font-size: var(--font-sm);
}
.u-font-mono {
  font-family: "JetBrains Mono", "Fira Code", monospace;
}
.u-flex {
  display: flex;
}
.u-flex-1 {
  flex: 1;
}
.u-items-center {
  align-items: center;
}
.u-justify-between {
  justify-content: space-between;
}
.u-gap-4 {
  gap: 4px;
}
.u-gap-8 {
  gap: 8px;
}
.u-gap-12 {
  gap: 12px;
}
.u-w-64 {
  width: 64px;
}
.u-mt-8 {
  margin-top: 8px;
}
.u-mt-16 {
  margin-top: 16px;
}
.u-mb-16 {
  margin-bottom: 16px;
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

/* ==========================================================================
   13-B. COMPONENTES — TOAST / NOTIFICAÇÕES
   ========================================================================== */
.toast-container {
  position: fixed;
  bottom: 24px;
  right: 24px;
  z-index: 9999;
  display: flex;
  flex-direction: column-reverse;
  gap: 10px;
  pointer-events: none;
  width: 320px;
}

.toast {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 14px;
  border-radius: var(--radius-md);
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border-strong);
  box-shadow: var(--shadow-lg);
  pointer-events: all;
  font-size: var(--font-sm);
  color: var(--color-text-primary);
  opacity: 0;
  transform: translateX(20px);
  transition:
    opacity var(--t-base),
    transform var(--t-base);
}
.toast.is-visible {
  opacity: 1;
  transform: translateX(0);
}

/* Superfície sólida + barra de cor à esquerda (referência) — sem fundo
   translúcido, que ficaria transparente sobre a página. */
.toast--error {
  border-left: 3px solid var(--color-danger);
}
.toast--success {
  border-left: 3px solid var(--color-success);
}
.toast--warning {
  border-left: 3px solid var(--color-warning);
}
.toast--info {
  border-left: 3px solid var(--color-info);
}

.toast__icon {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  margin-top: 1px;
}
.toast--error .toast__icon {
  color: var(--color-danger);
}
.toast--success .toast__icon {
  color: var(--color-success);
}
.toast--warning .toast__icon {
  color: var(--color-warning);
}
.toast--info .toast__icon {
  color: var(--color-info);
}

.toast__message {
  flex: 1;
  line-height: 1.5;
}
.toast__close {
  flex-shrink: 0;
  color: var(--color-text-muted);
  padding: 2px;
  border-radius: var(--radius-xs);
  transition: color var(--t-fast);
}
.toast__close:hover {
  color: var(--color-text-primary);
}
.toast__close i,
.toast__close svg {
  width: 14px;
  height: 14px;
  display: block;
}

/* ==========================================================================
   14. MODAL
   ========================================================================== */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(11, 13, 24, 0.55);
  z-index: var(--z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
  backdrop-filter: blur(3px);
}
.modal-overlay.is-open {
  opacity: 1;
  pointer-events: auto;
}

.modal {
  background: var(--color-bg-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  width: 100%;
  max-width: 440px;
  /* Cabe em qualquer viewport (notebook ou monitor) sem sair da tela — o
     corpo rola por dentro (ver .modal__body); header/footer ficam fixos. */
  max-height: calc(100vh - 40px);
  display: flex;
  flex-direction: column;
  transform: scale(0.94) translateY(10px);
  opacity: 0;
  transition:
    transform 0.25s ease,
    opacity 0.25s ease;
  overflow: hidden;
}
.modal-overlay.is-open .modal {
  transform: scale(1) translateY(0);
  opacity: 1;
}

/* Tamanho largo (formulários, etc.) */
.modal--lg {
  max-width: 620px;
}
/* Tamanho extra-largo (tabelas, históricos, listas com muitas colunas). */
.modal--xl {
  max-width: 960px;
}
/* Tamanho 2xl (comparação de imagens lado a lado — precisa de mais largura
   que qualquer formulário/tabela hoje no DS). */
.modal--2xl {
  max-width: 1200px;
  width: 95vw;
}

/* Ícone centralizado no topo */
.modal__icon-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: var(--radius-full);
  margin: 28px auto 0;
  flex-shrink: 0;
}
.modal__icon-wrap i,
.modal__icon-wrap svg {
  width: 24px;
  height: 24px;
  display: block;
}

/* Variantes de cor do ícone */
.modal--danger .modal__icon-wrap {
  background: var(--color-danger-light);
  color: var(--color-danger);
}
.modal--warning .modal__icon-wrap {
  background: var(--color-warning-light);
  color: var(--color-warning);
}
.modal--success .modal__icon-wrap {
  background: var(--color-success-light);
  color: var(--color-success);
}
.modal--info .modal__icon-wrap {
  background: var(--color-info-light);
  color: var(--color-info);
}
.modal--neutral .modal__icon-wrap {
  background: var(--color-bg-surface-alt);
  color: var(--color-text-secondary);
}

/* Cabeçalho */
.modal__header {
  padding: 16px 24px 0;
  text-align: center;
}
.modal__title {
  font-size: 1rem;
  font-weight: 700;
  color: var(--color-text-primary);
  line-height: 1.35;
}

/* Corpo */
.modal__body {
  padding: 10px 24px 0;
  color: var(--color-text-secondary);
  font-size: var(--font-sm);
  line-height: 1.65;
  text-align: center;
  /* Junto com o `max-height`/flex-column de `.modal`: header/footer ficam
     fixos e só o corpo rola quando o conteúdo não cabe na viewport. */
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}
/* Quando modal tem conteúdo estilo formulário — alinha à esquerda */
.modal--lg .modal__body {
  text-align: left;
}
.modal--lg .modal__header {
  text-align: left;
}
.modal--lg .modal__icon-wrap {
  margin-left: 24px;
}

/* Rodapé */
.modal__footer {
  padding: 22px 24px 24px;
  display: flex;
  gap: 10px;
  justify-content: center;
}
.modal--lg .modal__footer {
  justify-content: flex-end;
}
.modal__footer .btn {
  min-width: 110px;
  justify-content: center;
}

/* Divisor opcional no header de modais grandes */
.modal__header--bordered {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 20px;
  border-bottom: 1px solid var(--color-border);
  text-align: left;
}
.modal__header--bordered .modal__title {
  font-size: var(--font-base);
}
/* Texto de apoio abaixo do título, em headers com mais contexto (ex.:
   comparação de imagens). Opcional — headers sem subtítulo não usam. */
.modal__subtitle {
  margin-top: 2px;
  color: var(--color-text-secondary);
  font-size: var(--font-xs);
  font-weight: 400;
  line-height: 1.4;
}
.modal__close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
  transition:
    background var(--t-fast),
    color var(--t-fast);
  flex-shrink: 0;
}
.modal__close:hover {
  background: var(--color-bg-surface-alt);
  color: var(--color-text-primary);
}
.modal__close i,
.modal__close svg {
  width: 18px;
  height: 18px;
  display: block;
}

.modal__body--padded {
  padding: 20px;
  text-align: left;
}
.modal__body--padded + .modal__footer,
.modal__header--bordered + .modal__body--padded {
  border-top: 1px solid var(--color-border);
}

/* Escopo da ação (confirm-modal): seletor "selecionados × filtrado". */
.modal__scope {
  padding: 14px 24px 0;
}

/* Modal de histórico (components/actionlog.js). */
.action-log__empty {
  text-align: center;
  color: var(--color-text-muted);
  padding: 24px;
}
.action-log__col--date {
  width: 160px;
}
.action-log__col--op {
  width: 120px;
}
.action-log__col--user {
  width: 180px;
}
.action-log__details {
  margin-top: 6px;
}
.action-log__details-summary {
  cursor: pointer;
  color: var(--color-text-muted);
  font-size: var(--font-xs);
  user-select: none;
}
.action-log__details-pre {
  margin: 6px 0 0;
  padding: 8px 10px;
  background: var(--color-bg-surface-alt);
  border-radius: var(--radius-sm);
  font-size: var(--font-xs);
  color: var(--color-text-primary);
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 240px;
  overflow: auto;
}

/* ==========================================================================
   14a-bis. CHOICE-LIST — grupo de rádios em "cartões"
   --------------------------------------------------------------------------
   Lista de opções mutuamente exclusivas apresentadas como cartões
   clicáveis. Usado no seletor de escopo do confirm-modal; reutilizável em
   qualquer escolha binária/enumerada dentro de modais e drawers.
   ========================================================================== */
.choice-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}
.choice-list__option {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition:
    border-color var(--t-fast),
    background var(--t-fast);
}
.choice-list__option:hover {
  border-color: var(--color-border-accent);
}
.choice-list__option:has(input:checked) {
  border-color: var(--color-accent);
  background: var(--color-accent-light);
}
.choice-list__option:has(input:disabled) {
  cursor: not-allowed;
  opacity: 0.55;
}
.choice-list__option input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.choice-list__indicator {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  border-radius: var(--radius-full);
  border: 2px solid var(--color-border);
  transition: border-color var(--t-fast);
}
.choice-list__option:has(input:checked) .choice-list__indicator {
  border-color: var(--color-accent);
  box-shadow: inset 0 0 0 4px var(--color-accent);
}
.choice-list__option input:focus-visible + .choice-list__indicator {
  box-shadow: var(--shadow-focus);
}
.choice-list__label {
  font-size: var(--font-sm);
  color: var(--color-text-primary);
  line-height: 1.4;
}

/* ==========================================================================
   14b. TABS
   ========================================================================== */
.tabs__list {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--color-border);
  margin-bottom: 16px;
  overflow-x: auto;
}
.tabs__tab {
  padding: 10px 14px;
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--color-text-muted);
  cursor: pointer;
  font-size: var(--font-sm);
  font-weight: 500;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition:
    color var(--t-fast),
    border-color var(--t-fast);
}
.tabs__tab > i,
.tabs__tab > svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}
.tabs__tab:hover {
  color: var(--color-accent);
}
.tabs__tab.is-active {
  color: var(--color-accent);
  border-bottom-color: var(--color-accent);
}
.tabs__tab:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus);
  border-radius: var(--radius-xs);
}
.tabs__tab[disabled],
.tabs__tab[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}
.tabs__panel {
  display: none;
}
.tabs__panel.is-active {
  display: block;
}

/* ==========================================================================
   14b. FORMULÁRIO — GRID, ERRO, TOOLTIP DE AJUDA, LINHA DE SUB-RECURSO
   ========================================================================== */

/* Grid auto-responsivo de campos de formulário.
   Use em <form>/<div> que contenha vários .form-group lado a lado. */
.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
}
/* Variante de 1 coluna (campos largos: URLs longas, textos extensos). */
.form-grid--1 {
  grid-template-columns: 1fr;
}
/* Variante de 2 colunas fixas (drawer view-only/edição estreito).
   Responsivo: colapsa para 1 col < 600px. */
.form-grid--2 {
  grid-template-columns: repeat(2, 1fr);
}
/* Variante de 4 colunas fixas para formulários densos (drawer de edição).
   Responsivo: 4 cols ≥ 1100px; 2 cols 600–1099px; 1 col < 600px. */
.form-grid--4 {
  grid-template-columns: repeat(4, 1fr);
}

.form-grid__col--full {
  grid-column: 1 / -1;
}
.form-grid__col--span-2 {
  grid-column: span 2;
}
.form-grid__col--span-3 {
  grid-column: span 3;
}
.form-grid__col--new-line {
  grid-column-start: 1;
} /* força quebra de linha */
.form-grid__col--inline {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--font-sm);
  color: var(--color-text-primary);
}

/* Alinhamento estrutural (NÃO-NEGOCIÁVEL — ver
   .claude/rules/design-system-frontend.md):

   1. ``[hidden]`` precisa ser ``display: none`` mesmo quando o seletor
      por classe (``.form-error``, ``.help-tooltip``) define display:block.
      Sem isso, ``<small class="form-error" hidden>`` em UM form-group
      ocupa altura enquanto outros vizinhos não têm o ``<small>``, e a
      célula stretched do grid fica desigual → inputs desalinham.
   2. ``align-self: stretch`` no .form-group garante que o item de fato
      preenche a célula (em alguns navegadores um flex-column sem altura
      explícita colapsa para o conteúdo, e ``margin-top: auto`` fica sem
      efeito porque não há espaço para empurrar).
   3. .form-input e .custom-select__trigger têm a mesma height explícita —
      independente de diferenças de user-agent entre <input> e <button>.
      A height precisa ser explícita porque padding + line-height herdado do
      body (1.6) já ultrapassam a altura alvo sozinhos, o que torna um
      min-height inócuo. Com height explícita (+ box-sizing: border-box
      global), os três — input, select e .btn--sm — batem exatamente
      `--control-height`, o token único do :root. */
.form-error[hidden],
.help-tooltip[hidden],
.form-hint[hidden] {
  display: none;
}

.custom-select__trigger {
  height: var(--control-height);
  box-sizing: border-box;
}

/* Custom-select travado (campo read-only via JS — ex.: país fixo após
   criação). Visual desabilitado + tooltip via data-ui-tooltip. */
.custom-select__trigger.is-locked,
.custom-select__trigger[disabled] {
  background: var(--color-bg-surface-alt);
  color: var(--color-text-muted);
  cursor: not-allowed;
  pointer-events: auto; /* preserva hover para o tooltip */
}

.form-grid--4 > .form-group {
  align-self: stretch;
  display: flex;
  flex-direction: column;
}
.form-grid--4 > .form-group > .form-label {
  margin-bottom: 4px;
}
.form-grid--4 > .form-group > .form-input,
.form-grid--4 > .form-group > .custom-select,
.form-grid--4 > .form-group > textarea.form-input {
  margin-top: auto;
}
.form-grid--4 > .form-checkbox.form-grid__col--inline {
  align-self: end;
  padding-bottom: 10px; /* alinha visualmente com a base do input */
}

/* Variante .form-grid--align-top: alinha inputs/selects pelo topo da
   célula. Usar em forms que mostram hints/erros dinâmicos abaixo de
   alguns campos — top-align mantém os campos com e sem hint na mesma
   linha visual. */
.form-grid--align-top > .form-group > .form-input,
.form-grid--align-top > .form-group > .custom-select,
.form-grid--align-top > .form-group > textarea.form-input {
  margin-top: 0;
}

/* Cabeçalho de seção dentro de .form-grid (ex.: "Entrada", "Saída", "Execução")
   que ocupa toda a largura. Compacto: border lateral accent + background bem
   suave — suficiente para separar visualmente sem competir com os campos. */
.form-grid__section-title {
  grid-column: 1 / -1;
  margin: 10px 0 2px;
  padding: 4px 10px;
  background: var(--color-accent-light);
  border-left: 3px solid var(--color-accent);
  border-bottom: none;
  border-radius: var(--radius-sm);
  font-size: var(--font-xs);
  font-weight: 600;
  color: var(--color-accent-dark);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  line-height: 1.6;
}
.form-grid__section-title:first-child {
  margin-top: 0;
}

/* Trilha horizontal de chips (ex.: hierarquia comercial de um seller),
   com seta entre níveis consecutivos. */
.hierarchy-trail {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.hierarchy-chip {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px 6px 8px;
  background: var(--color-bg-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  font-size: var(--font-sm);
}
.hierarchy-chip .level {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  white-space: nowrap;
}
.hierarchy-chip.is-holder {
  background: var(--color-accent-light);
  border-color: rgba(var(--color-accent-rgb), 0.35);
}
.hierarchy-chip.is-holder .level {
  color: var(--color-accent-dark);
}
.hierarchy-chip .name {
  font-weight: 600;
  color: var(--color-text-primary);
  white-space: nowrap;
}
.hierarchy-arrow {
  color: var(--color-text-muted);
  display: flex;
  flex-shrink: 0;
}
.hierarchy-arrow svg {
  width: 14px;
  height: 14px;
}

/* Lista compacta de lojas vinculadas a um seller, com canal/permite-match
   como badges ao lado do nome. */
.accounts-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.account-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 12px;
  background: var(--color-bg-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}
.account-row .name {
  font-size: var(--font-sm);
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}
.account-row .name svg {
  width: 14px;
  height: 14px;
  color: var(--color-text-muted);
  flex-shrink: 0;
}
.account-row .tags {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}

/* Árvore de hierarquia comercial quando o seller tem mais de um executivo
   vinculado: os níveis em comum (`.tree__level`) aparecem uma vez só,
   ramificando (`.tree__branches` › `.tree__branch`) só onde as cadeias de
   fato divergem. Com um único executivo, reduz a um `.tree__level` só. */
.tree {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.tree__level {
  padding: 6px 0;
}
.tree__branches {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-left: 30px;
  margin-left: 15px;
  border-left: 1px dashed var(--color-border-strong);
}
.tree__branch {
  padding: 2px 0;
}
/* O traço liga na altura do próprio chip do ramo (`.tree__level`), nunca
   centralizado pela altura do `.tree__branch` inteiro — que também inclui
   os sub-ramos dele quando o ramo se ramifica de novo. */
.tree__branch > .tree__level {
  position: relative;
}
.tree__branch > .tree__level::before {
  content: "";
  position: absolute;
  left: -30px;
  top: 50%;
  width: 22px;
  height: 1px;
  background: var(--color-border-strong);
}

/* Mensagem de erro abaixo de um campo. */
.form-error {
  display: block;
  margin-top: 4px;
  font-size: var(--font-xs);
  color: var(--color-danger);
}
.form-group.is-invalid .form-input,
.form-group.is-invalid .custom-select__trigger {
  border-color: var(--color-danger);
}

/* Tooltip de ajuda contextual ao lado de um label.
   Estrutura:
     <span class="help-tooltip">
       <button class="help-tooltip__trigger" aria-label="Ajuda">?</button>
       <span class="help-tooltip__content">Texto / HTML de ajuda</span>
     </span>

   O balão é portado para `document.body` pelo JS (designsystem/js/
   components/help-tooltip.js) ao abrir, com `position: fixed` e
   top/left calculados a partir do rect do trigger. Isso evita
   clipping em ancestrais com `overflow:auto` (drawer body) ou
   `transform` (o próprio .side-drawer cria containing block).
*/
.help-tooltip {
  position: relative;
  display: inline-flex;
  align-items: center;
}
.help-tooltip__trigger {
  background: var(--color-accent-light);
  border: 1px solid rgba(var(--color-accent-rgb), 0.35);
  border-radius: 50%;
  padding: 2px;
  margin-left: 4px;
  width: 20px;
  height: 20px;
  color: var(--color-accent);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition:
    background var(--t-fast),
    color var(--t-fast),
    border-color var(--t-fast),
    box-shadow var(--t-fast),
    transform var(--t-fast);
}
.help-tooltip__trigger > i,
.help-tooltip__trigger > svg {
  width: 14px;
  height: 14px;
  stroke-width: 2.75;
}
.help-tooltip__trigger:hover,
.help-tooltip__trigger:focus-visible {
  background: var(--color-accent);
  color: #fff;
  border-color: var(--color-accent);
  box-shadow: 0 0 0 3px rgba(var(--color-accent-rgb), 0.22);
  transform: scale(1.08);
  outline: none;
}
/* Variante do gatilho para um ícone semântico (ex.: lojas) em vez da bolha
   "?" de ajuda: sem círculo/realce de accent, fundo transparente e quadrado
   28x28 como um botão de ação de linha. Reutilizável em qualquer help-tooltip
   cujo gatilho seja um ícone. */
.help-tooltip__trigger--icon {
  background: transparent;
  border: 0;
  border-radius: var(--radius-xs);
  width: 28px;
  height: 28px;
  color: var(--color-text-muted);
}
.help-tooltip__trigger--icon:hover,
.help-tooltip__trigger--icon:focus-visible {
  background: var(--color-bg-surface-alt);
  color: var(--color-info);
  border-color: transparent;
  box-shadow: none;
  transform: none;
}
.help-tooltip__content {
  position: fixed;
  z-index: var(--z-tooltip);
  min-width: 240px;
  max-width: 480px;
  max-height: calc(100vh - 32px);
  overflow-y: auto;
  padding: 10px 14px;
  background: var(--color-bg-surface);
  color: var(--color-text-primary);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
  font-size: var(--font-xs);
  line-height: 1.5;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-fast);
  display: none;
}
.help-tooltip__content.is-visible {
  display: block;
  opacity: 1;
  pointer-events: auto;
}

/* Mini-tabela reutilizável dentro de help-tooltip/popover. O
   ``.table-wrapper`` global (que dá borda arredondada às tabelas) não
   envolve conteúdo de tooltip, então esta classe traz a borda arredondada
   própria + células compactas. Reutilizável em qualquer popover do DS. */
.tooltip-table {
  width: 100%;
  margin-top: 6px;
  border-collapse: separate;
  border-spacing: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  font-size: var(--font-xs);
}
.tooltip-table th,
.tooltip-table td {
  padding: 4px 8px;
  text-align: left;
  border-bottom: 1px solid var(--color-border);
}
.tooltip-table thead th {
  background: var(--color-bg-surface-alt);
  font-weight: 600;
  color: var(--color-text-muted);
}
.tooltip-table tbody tr:last-child td {
  border-bottom: none;
}

/* Linha de sub-recurso (item filho dentro de um drawer/CRUD aninhado),
   com botão de remover à direita.
   Ex.: dia de envio, concorrente, contato. */
.subitem-row {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  padding: 8px;
  margin-bottom: 8px;
  background: var(--color-bg-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  transition:
    opacity 0.25s ease,
    background-color 0.25s ease;
}
.subitem-row > .form-group {
  margin-bottom: 0;
}
/* Estado de remoção pendente (soft-delete): a linha existente fica
   esmaecida até o save confirmar a exclusão no backend. */
.subitem-row.is-pending-remove {
  opacity: 0.45;
  background: var(--color-danger-light);
}
.subitem-row.is-pending-remove > input,
.subitem-row.is-pending-remove > select,
.subitem-row.is-pending-remove > label,
.subitem-row.is-pending-remove > textarea {
  pointer-events: none;
}
.subitem-row.is-pending-remove .subitem-row__remove {
  color: var(--color-danger);
}
.subitem-row__remove {
  margin-left: auto;
  background: transparent;
  border: 0;
  padding: 4px;
  color: var(--color-text-muted);
  border-radius: var(--radius-xs);
  cursor: pointer;
  display: inline-flex;
}
.subitem-row__remove:hover,
.subitem-row__remove:focus-visible {
  color: var(--color-danger);
  background: var(--color-bg-hover);
  outline: none;
}

/* Espaçador flexível dentro de .filter-toolbar__actions — empurra os botões
   subsequentes para a direita, separando ações primárias (esquerda) de
   ações secundárias/em-massa (direita). */
.filter-toolbar__actions {
  flex-wrap: wrap;
}
.filter-toolbar__spacer {
  flex: 1 1 0;
  min-width: 8px;
}

/* Indicador de ordenação para colunas clicáveis em .data-table.
   Use o atributo `data-sort` no <th> e troque a classe ascendente/descendente via JS. */
.data-table th[data-sort] {
  cursor: pointer;
  user-select: none;
}
.data-table th[data-sort].is-sort-asc::after {
  content: " ▲";
  opacity: 0.6;
}
.data-table th[data-sort].is-sort-desc::after {
  content: " ▼";
  opacity: 0.6;
}

/* ===== Segmented Progress =====
   Barra única dividida em N segmentos binários (concluído/pendente). Substitui
   filas de badges horizontais em colunas que rastreiam etapas booleanas de um
   pipeline. Helper JS: js/components/segmented-progress.js.

   Cada segmento tem ``data-ui-tooltip`` (exibido pelo balão global
   ``.ui-tooltip``, portado ao body). As bordas arredondadas das pontas
   ficam no primeiro/último ``__segment`` via ``:first-child`` /
   ``:last-child``. */
.segmented-progress {
  display: flex;
  width: 100%;
  gap: 2px;
  height: 8px;
  background: var(--color-bg-surface-alt);
  border-radius: var(--radius-sm);
}
.segmented-progress__segment {
  flex: 1 1 0;
  min-width: 4px;
  background: var(--color-border);
  transition: background var(--t-fast);
}
.segmented-progress__segment:first-child {
  border-top-left-radius: var(--radius-sm);
  border-bottom-left-radius: var(--radius-sm);
}
.segmented-progress__segment:last-child {
  border-top-right-radius: var(--radius-sm);
  border-bottom-right-radius: var(--radius-sm);
}
.segmented-progress__segment.is-done {
  background: var(--color-success);
}
.segmented-progress__segment.is-in-progress {
  background: var(--color-warning);
}
.segmented-progress__segment.is-pending {
  background: var(--color-danger);
}
/* ===== End Segmented Progress ===== */

/* ==========================================================================
   14c. COMPARAÇÃO DE IMAGENS — modal "Comparar imagens" (Política de preços)
   ========================================================================== */
.image-compare {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  /* `stretch`: os dois cards ficam da mesma altura mesmo quando uma descrição
     ocupa mais linhas que a outra. */
  align-items: stretch;
  gap: 16px;
  margin-bottom: 16px;
}
.image-compare__card {
  display: flex;
  flex-direction: column;
  background: var(--color-bg-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.image-compare__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--color-border);
}
.image-compare__label {
  font-size: var(--font-xs);
  font-weight: 600;
  color: var(--color-text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.image-compare__header .badge i,
.image-compare__header .badge svg {
  width: 12px;
  height: 12px;
}
/* Cabeçalho do lado do vendedor: faixa em tom de acento com o nome da conta.
   O lado do cliente segue na faixa neutra. */
.image-compare__header--seller {
  background: var(--color-accent-light);
}
.image-compare__label--seller {
  font-size: var(--font-sm);
  font-weight: 700;
  color: var(--color-accent-dark);
}
.image-compare__label--client {
  color: var(--color-text-primary);
}
.image-compare__figure {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Moldura quadrada de lado fixo: `flex: 0 0 auto` trava o tamanho — sem ele
     ela cede ao conteúdo e cada lado fica de um tamanho (idem `aspect-ratio`).
     Os 380px descontados são o resto do modal, para crescer sem gerar rolagem. */
  flex: 0 0 auto;
  align-self: center;
  width: min(100%, clamp(220px, calc(100vh - 380px), 460px));
  height: clamp(220px, calc(100vh - 380px), 460px);
  background: var(--color-bg-surface);
}
/* `contain` sobre a moldura toda: a imagem ocupa o maior tamanho que caiba, nas
   proporções naturais dela — nunca distorce, e imagem pequena não fica um selo
   no meio do quadro. É o que mantém as duas comparáveis a olho. */
.image-compare__img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.image-compare__skeleton {
  position: absolute;
  inset: 8px;
  height: auto;
}
.image-compare__state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 0 16px;
  color: var(--color-text-muted);
  font-size: var(--font-sm);
  text-align: center;
}
.image-compare__zoom-btn {
  position: absolute;
  top: 10px;
  right: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-full);
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  color: var(--color-text-secondary);
  box-shadow: var(--shadow-sm);
  transition:
    background var(--t-fast),
    color var(--t-fast);
}
.image-compare__zoom-btn:hover:not(:disabled) {
  background: var(--color-accent-light);
  color: var(--color-accent);
}
.image-compare__zoom-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.image-compare__zoom-btn i,
.image-compare__zoom-btn svg {
  width: 15px;
  height: 15px;
}
/* Descrição do produto do card. É o que identifica a imagem, então tem peso de
   texto principal, e não de metadado. */
.image-compare__meta {
  /* `margin-top: auto` cola a descrição no rodapé do card, alinhando as duas. */
  margin: auto 0 0;
  padding: 10px 12px;
  color: var(--color-text-primary);
  font-size: var(--font-sm);
  font-weight: 600;
  line-height: 1.35;
  border-top: 1px solid var(--color-border);
  background: var(--color-bg-surface-alt);
}

/* Botão central não-interativo — só reforça visualmente a comparação, sem
   ação de troca (ver contrato da issue #239). */
.image-compare__divider {
  display: flex;
  align-items: center;
  justify-content: center;
  align-self: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-full);
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border-strong);
  color: var(--color-text-muted);
  box-shadow: var(--shadow-sm);
}
.image-compare__divider i,
.image-compare__divider svg {
  width: 16px;
  height: 16px;
}

/* ==========================================================================
   14d. VISUALIZADOR DE IMAGENS (FULLSCREEN) — zoom, pan, navegação
   ========================================================================== */
.image-viewer {
  position: fixed;
  inset: 0;
  z-index: var(--z-image-viewer);
  display: flex;
  flex-direction: column;
  background: var(--color-bg-surface);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-base);
}
.image-viewer.is-open {
  opacity: 1;
  pointer-events: auto;
}

.image-viewer__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 20px 28px;
  border-bottom: 1px solid var(--color-border);
  flex-shrink: 0;
}
.image-viewer__title-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.image-viewer__title {
  font-size: 1rem;
  font-weight: 700;
  color: var(--color-text-primary);
}
.image-viewer__counter {
  padding: 2px 10px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  color: var(--color-text-secondary);
}
.image-viewer__badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 6px;
  font-size: var(--font-sm);
  font-weight: 600;
}
.image-viewer__badge--success {
  color: var(--color-success-text);
}
.image-viewer__badge--info {
  color: var(--color-info-text);
}
.image-viewer__badge--neutral {
  color: var(--color-text-secondary);
}
.image-viewer__badge i,
.image-viewer__badge svg {
  width: 14px;
  height: 14px;
}
.image-viewer__meta {
  display: flex;
  gap: 16px;
  margin-top: 4px;
  color: var(--color-text-primary);
  font-size: var(--font-sm);
  font-weight: 600;
}
.image-viewer__meta span {
  white-space: nowrap;
}
.image-viewer__header-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-shrink: 0;
}
.image-viewer__esc-hint {
  color: var(--color-text-muted);
  font-size: var(--font-xs);
  white-space: nowrap;
}

.image-viewer__stage {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.image-viewer__stage.is-zoomable .image-viewer__image {
  cursor: grab;
}
.image-viewer__stage.is-dragging .image-viewer__image {
  cursor: grabbing;
}
.image-viewer__image {
  max-width: 82%;
  max-height: 88%;
  object-fit: contain;
  user-select: none;
  touch-action: none;
  transition: transform 60ms linear;
}
/* Ocupa o lugar da imagem enquanto ela baixa, na mesma proporção do palco. */
.image-viewer__skeleton {
  width: min(60vw, 520px);
  height: min(60vh, 420px);
}
.image-viewer__state {
  color: var(--color-text-muted);
  font-size: var(--font-sm);
}

.image-viewer__icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-full);
  background: var(--color-bg-surface-alt);
  border: 1px solid var(--color-border);
  color: var(--color-text-secondary);
  transition:
    background var(--t-fast),
    color var(--t-fast);
  flex-shrink: 0;
}
.image-viewer__icon-btn:hover:not(:disabled) {
  background: var(--color-accent-light);
  color: var(--color-accent);
}
.image-viewer__icon-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}
.image-viewer__icon-btn i,
.image-viewer__icon-btn svg {
  width: 17px;
  height: 17px;
}
.image-viewer__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  box-shadow: var(--shadow-sm);
}
.image-viewer__nav--prev {
  left: 28px;
}
.image-viewer__nav--next {
  right: 28px;
}

.image-viewer__footer {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 16px 24px 24px;
  flex-shrink: 0;
}
.image-viewer__zoom {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 10px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: var(--color-bg-surface-alt);
  box-shadow: var(--shadow-sm);
}
.image-viewer__zoom-value {
  min-width: 44px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  color: var(--color-text-secondary);
}
.image-viewer__zoom-sep {
  width: 1px;
  height: 20px;
  background: var(--color-border);
}
.image-viewer__zoom .btn {
  height: 32px;
}
.image-viewer__hint {
  color: var(--color-text-muted);
  font-size: var(--font-xs);
}

/* Reusada pelo drawer de associação da tela de Produto
   (`drawer-associate.js`): linha compacta de campos com divisórias finas
   entre eles (a primeira coluna não tem divisória à esquerda). */
.match-drawer-offer__fields > .form-group:not(:first-child) {
  border-left: 1px solid var(--color-border);
  padding-left: 14px;
}

/* Coluna "Associação" da listagem de Produto: contador "X/Y" (contas de seller
   resolvidas/habilitadas) sobre a barra da fração + badge de situação. */
.association-cell {
  min-width: 130px;
}
.association-cell__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}

/* Barra da fração de contas resolvidas: a matiz vem do JS por linha
   (`--association-bar-hue`, vermelho no zero e verde no total); a saturação e a
   luminosidade são do tema. Número na cor cheia, fundo na mesma cor clareada. */
:root {
  --association-bar-sat: 56%;
  --association-bar-light: 38%;
  --association-bar-alpha: 0.14;
}
[data-theme="dark"] {
  --association-bar-light: 64%;
  --association-bar-alpha: 0.18;
}
/* Largura fixa para o número cair na mesma coluna em toda linha: o badge ao
   lado varia de largura com o rótulo. */
.association-bar {
  --association-bar-hue: 0;
  flex: none;
  width: 62px;
  padding: 2px 7px;
  border-radius: var(--radius-sm);
  background: hsl(
    var(--association-bar-hue) var(--association-bar-sat) var(--association-bar-light) /
    var(--association-bar-alpha)
  );
}
.association-bar__value {
  display: block;
  text-align: right;
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: hsl(var(--association-bar-hue) var(--association-bar-sat) var(--association-bar-light));
}
/* Numerador em largura de dois dígitos: "0/51" e "17/51" põem a "/" na mesma
   coluna. */
.association-bar__done {
  display: inline-block;
  min-width: 2ch;
  text-align: right;
}

/* Selo de produto reservado por outra pessoa na revisão de associação. Âmbar
   (não é erro, é "ocupado") e com o lápis escrevendo, para a linha travada
   saltar aos olhos numa tabela cheia. */
:root {
  --review-lock-hue: 50;
  --review-lock-text: hsl(var(--review-lock-hue) 96% 24%);
  --review-lock-bg: hsl(var(--review-lock-hue) 96% 88%);
  --review-lock-border: hsl(var(--review-lock-hue) 88% 62%);
}
[data-theme="dark"] {
  --review-lock-text: hsl(var(--review-lock-hue) 96% 70%);
  --review-lock-bg: hsl(var(--review-lock-hue) 62% 15%);
  --review-lock-border: hsl(var(--review-lock-hue) 68% 36%);
}
.review-lock-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 100%;
  padding: 3px 10px 3px 8px;
  border: 1px solid var(--review-lock-border);
  border-radius: var(--radius-full);
  background: var(--review-lock-bg);
  color: var(--review-lock-text);
  font-size: var(--font-xs);
  font-weight: 500;
  line-height: 1.4;
  white-space: nowrap;
  /* Dois ciclos de escrita por respiração da borda: os dois se encontram no
     mesmo instante em vez de deslizarem um sobre o outro. */
  animation: review-lock-pulse 3.6s ease-in-out infinite;
}
.review-lock-badge__name {
  overflow: hidden;
  text-overflow: ellipsis;
}
/* O lápis e o risco que ele deixa. As duas animações têm a mesma duração, as
   mesmas paradas e tempo linear: em cada quadro a largura do traço é o mesmo
   número do deslocamento do lápis, então a ponta fica sempre no fim do risco.
   O ciclo é o de uma mão: pousa, escreve da esquerda para a direita, levanta,
   volta no ar. `--review-lock-run` é o percurso da ponta. */
.review-lock-badge__pen {
  --review-lock-run: 7px;
  position: relative;
  flex: none;
  display: inline-flex;
  align-items: center;
  width: calc(13px + var(--review-lock-run));
  padding-bottom: 3px;
}
/* O traço tem a largura final fixa e cresce por `scaleX`: mesma sincronia com
   a ponta que animar `width` daria, sem tirar layout do navegador a cada
   quadro. */
.review-lock-badge__pen::after {
  content: "";
  position: absolute;
  left: 2px;
  bottom: 0;
  width: var(--review-lock-run);
  height: 1.5px;
  border-radius: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  animation: review-lock-stroke 1.8s linear infinite;
}
.review-lock-badge i,
.review-lock-badge svg {
  flex: none;
  width: 13px;
  height: 13px;
  transform-origin: 15% 85%;
  animation: review-lock-write 1.8s linear infinite;
}
@keyframes review-lock-stroke {
  0%,
  12% {
    transform: scaleX(0);
    opacity: 0.85;
  }
  38% {
    transform: scaleX(0.42);
  }
  62% {
    transform: scaleX(0.74);
  }
  76% {
    transform: scaleX(1);
    opacity: 0.85;
  }
  88% {
    transform: scaleX(1);
    opacity: 0.35;
  }
  100% {
    transform: scaleX(1);
    opacity: 0;
  }
}
/* O ciclo da mão, nas mesmas paradas do traço: pousa (12%), escreve com o
   sobe-e-desce da letra (38% e 62%), termina (76%), levanta (88%) e volta no
   ar até o começo. A inclinação varia pouco — lápis que gira muito vira
   ventilador, não escrita. */
@keyframes review-lock-write {
  0% {
    transform: translate(0, -2px) rotate(-16deg);
  }
  12% {
    transform: translate(0, 0) rotate(-8deg);
  }
  38% {
    transform: translate(calc(var(--review-lock-run) * 0.42), -0.6px) rotate(-5deg);
  }
  62% {
    transform: translate(calc(var(--review-lock-run) * 0.74), 0.4px) rotate(-9deg);
  }
  76% {
    transform: translate(var(--review-lock-run), 0) rotate(-6deg);
  }
  88% {
    transform: translate(var(--review-lock-run), -2px) rotate(-16deg);
  }
  100% {
    transform: translate(0, -2px) rotate(-16deg);
  }
}
/* A borda respira junto, para o selo ser visto pelo canto do olho. */
@keyframes review-lock-pulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 hsl(var(--review-lock-hue) 90% 55% / 0);
  }
  50% {
    box-shadow: 0 0 0 3px hsl(var(--review-lock-hue) 90% 55% / 0.22);
  }
}
@media (prefers-reduced-motion: reduce) {
  .review-lock-badge,
  .review-lock-badge i,
  .review-lock-badge svg {
    animation: none;
  }
}

/* Indicadores clicáveis acima da tabela ("N produtos", "N não iniciadas", …)
   — compactos, não substituem os filtros. Pílula ativa (`.is-active`) reflete
   o filtro "Associação" corrente. */
.association-summary {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
  font-size: var(--font-xs);
}
.association-summary__total {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  border-radius: var(--radius-full);
  background: var(--color-bg-surface-alt);
  color: var(--color-text-secondary);
  white-space: nowrap;
}
.association-summary__total span {
  font-weight: 700;
  color: var(--color-text-primary);
}
.association-summary__pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: var(--color-bg-surface);
  color: var(--color-text-secondary);
  font-size: var(--font-xs);
  cursor: pointer;
  white-space: nowrap;
}
.association-summary__pill span {
  font-weight: 700;
  color: var(--color-text-primary);
}
.association-summary__pill.is-active {
  border-color: var(--color-accent);
  background: var(--color-accent-light);
  color: var(--color-accent-dark);
}
.association-summary__pill.is-active span {
  color: var(--color-accent-dark);
}

/* Cabeçalho do drawer "Associar produto": grid de 2 colunas (mídia fixa +
   texto) na superfície padrão do DS. `min-height` acompanha o conteúdo
   variável do texto. */
.product-associate-header {
  display: flex;
  align-items: stretch;
  min-height: 100px;
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.product-associate-header__media {
  width: 120px;
  flex-shrink: 0;
  align-self: stretch;
  background: var(--color-bg-surface);
  border-right: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10px;
  box-sizing: border-box;
}
.product-associate-header__thumb {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
/* Estado "sem imagem" da mídia: ícone + texto legível, no lugar de PNG. */
.product-associate-header__no-image {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  color: var(--color-text-secondary);
  font-size: 12px;
  font-weight: 600;
}
.product-associate-header__no-image svg {
  width: 22px;
  height: 22px;
}
.product-associate-header__info {
  flex: 1;
  min-width: 0;
  padding: 12px 16px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 8px;
}
/* Linha primária: código (chip mono) e descrição fortes, no mesmo eixo. */
.product-associate-header__title {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 10px;
}
.product-associate-header__code {
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: var(--font-sm);
  color: var(--color-accent-dark);
  background: var(--color-accent-light);
  border-radius: var(--radius-sm);
  padding: 2px 8px;
}
.product-associate-header__title strong {
  font-size: 16px;
  font-weight: 700;
  color: var(--color-text-primary);
}
/* No resumo do header o par rótulo/valor é leitura, não formulário: o valor
   perde a caixa do `.form-readonly` e ganha peso de texto. */
.product-associate-header__info .form-readonly {
  background: transparent;
  border: none;
  padding: 0;
  min-height: 0;
  font-weight: 600;
}
.product-associate-header__info .form-group {
  gap: 2px;
}
.product-associate-header__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.product-associate-header__chip {
  background: var(--color-bg-overlay);
  border-radius: 5px;
  padding: 5px 9px;
  font-size: 12px;
  color: var(--color-text-secondary);
}
.product-associate-header__chip b {
  margin-right: 4px;
  color: var(--color-text-primary);
  font-weight: 700;
}
/* Chip do caminho da estrutura mercadológica: 13px, em fundo e texto de
   acento. */
.product-associate-header__chip--path,
.product-associate-header__chip--path b {
  color: var(--color-accent-dark);
}
.product-associate-header__chip--path {
  background: var(--color-accent-light);
  font-size: 13px;
}

/* Cabeçalho acima da barra de progresso: hint à esquerda, contador de
   pendentes à direita. */
.associate-sellers__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 10px 0 8px;
}
.associate-sellers__lead {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}
.associate-sellers__head .associate-sellers__hint {
  margin: 0;
}
.associate-sellers__count {
  font-weight: 700;
  color: var(--color-text-primary);
  white-space: nowrap;
}
.associate-sellers__hint {
  margin: 4px 0 0;
  font-size: var(--font-xs);
  color: var(--color-text-secondary);
}

/* Barra fina de progresso das contas, entre o cabeçalho da seção e o
   carrossel — sem cartão próprio. */
.associate-progress-track {
  height: 5px;
  border-radius: var(--radius-full);
  background: var(--color-bg-overlay);
  margin: 0 0 10px;
  overflow: hidden;
}
.associate-progress-fill {
  height: 100%;
  border-radius: var(--radius-full);
  background: var(--color-accent);
}

/* Linha do carrossel com as setas de navegação nas duas pontas. */
.associate-carousel-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.associate-carousel-row .associate-carousel {
  flex: 1;
}
.associate-carousel__nav {
  flex-shrink: 0;
}

/* Barra acima da tabela de sugestões: busca no portfólio do seller — a
   ordenação é pelo cabeçalho da tabela (`sort-header.js`). */
.associate-suggestions-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 8px 0 10px;
}
.associate-suggestions-search {
  flex: 1;
}

/* Carrossel de contas de seller do drawer "Associar produto": página de
   `--carousel-cols` cards do mesmo tamanho, com avanço por página inteira e
   rolagem animada. O card selecionado ganha o contorno de acento. */
.associate-carousel {
  --carousel-cols: 8;
  --carousel-gap: 10px;
  display: flex;
  gap: var(--carousel-gap);
  overflow-x: hidden;
  scroll-behavior: smooth;
  padding: 4px 0;
}
.associate-carousel__card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  flex: 0 0 calc((100% - (var(--carousel-cols) - 1) * var(--carousel-gap)) / var(--carousel-cols));
  min-width: 0;
  padding: 7px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg-surface);
  cursor: pointer;
}
/* A conta em que o usuário está trabalhando: fundo de acento e anel duplo —
   destaque forte, não só uma borda. */
.associate-carousel__card.is-selected {
  border-color: var(--color-accent);
  box-shadow: 0 0 0 2px var(--color-accent);
  background: var(--color-accent-light);
}
.associate-carousel__card.is-selected .associate-carousel__name {
  color: var(--color-accent-dark);
  font-weight: 700;
}
/* Enquanto os candidatos da conta carregam, o carrossel fica bloqueado —
   junto com as setas e a busca (desabilitadas pelo JS). */
.associate-carousel.is-busy {
  pointer-events: none;
  opacity: 0.55;
  transition: opacity 150ms ease;
}
.associate-carousel__name {
  font-size: var(--font-xs);
  font-weight: 500;
  color: var(--color-text-primary);
  text-align: center;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Destaque momentâneo quando o carrossel avança sozinho pro próximo seller
   pendente (depois de associar). */
@keyframes associate-carousel-flash {
  0% {
    box-shadow: 0 0 0 3px var(--color-accent-light);
  }
  100% {
    box-shadow: none;
  }
}
.associate-carousel__card.is-flash {
  animation: associate-carousel-flash 900ms ease-out;
}
@media (prefers-reduced-motion: reduce) {
  .associate-carousel__card.is-flash {
    animation: none;
  }
}

/* Modo play: a linha da tabela de candidatos selecionada pelo teclado —
   fundo de acento e filete na borda esquerda, mesmo vocabulário do card
   selecionado no carrossel. */
.data-table tr.is-kbd-active td {
  background: var(--color-accent-light);
}
.data-table tr.is-kbd-active td:first-child {
  box-shadow: inset 3px 0 0 var(--color-accent);
}

/* Barra de atalhos do modo play, ancorada à esquerda no rodapé do drawer
   (o "Cancelar" continua à direita). As teclas usam o acento do DS — é o
   mapa de operação do modo, não uma nota de rodapé. */
.associate-shortcuts {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
  margin-right: auto;
  font-size: var(--font-xs);
  font-weight: 600;
  color: var(--color-text-primary);
}
.associate-shortcuts__item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  white-space: nowrap;
}
.associate-shortcuts kbd {
  padding: 2px 7px;
  border: 1px solid var(--color-accent);
  border-bottom-width: 2px;
  border-radius: var(--radius-sm);
  background: var(--color-accent-light);
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 700;
  line-height: 1.4;
  color: var(--color-accent-dark);
}

/* Identificação do produto do vendedor no modal de confirmação da
   associação: código em chip mono numa linha, descrição na outra. */
.associate-confirm {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  margin-bottom: 12px;
}
.associate-confirm__code {
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: var(--font-sm);
  color: var(--color-accent-dark);
  background: var(--color-accent-light);
  border-radius: var(--radius-sm);
  padding: 2px 8px;
}
.associate-confirm__description {
  margin: 0;
  font-weight: 600;
  color: var(--color-text-primary);
}
/* Rótulo de cada um dos dois lados no modal de revinculação. */
.associate-relink__label {
  margin: 0 0 4px;
  font-size: var(--font-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-secondary);
}
.associate-confirm__hint {
  margin: 4px 0 0;
  font-size: var(--font-xs);
  color: var(--color-text-secondary);
}

/* Corpo do drawer "Associar produto": o corpo NÃO rola — os dados do produto
   e o carrossel de contas ficam sempre visíveis e quem rola é só a tabela de
   candidatos (o thead sticky resolve contra o `.table-scroll`). Em altura
   curta (zoom do SO, notebook) a tabela encolhe, nunca o cabeçalho — as setas
   do teclado navegam sem tirar o produto da tela. Gap mais compacto que o
   padrão de 18px do `.side-drawer__body`, pela mesma razão de altura. */
[data-product-associate-drawer-body] {
  display: flex;
  flex-direction: column;
  gap: 12px;
  overflow-y: hidden;
}
[data-product-associate-drawer-body] > section {
  flex-shrink: 0;
}
[data-product-associate-suggestions]:not([hidden]) {
  display: flex;
  flex-direction: column;
  flex: 1 1 0;
  min-height: 0;
}
[data-product-associate-suggestions] .table-wrapper--sticky-head-inner {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}
[data-product-associate-suggestions] .table-scroll {
  flex: 1;
  min-height: 0;
  max-height: none;
  overflow-y: auto;
}

/* Corpo do drawer "Corrigir associação": o cabeçalho do produto do vendedor
   fica sempre visível, e quem rola é só a tabela de busca. */
[data-correct-match-drawer-body] {
  display: flex;
  flex-direction: column;
  gap: 12px;
  overflow-y: hidden;
}
[data-correct-match-drawer-body] > section {
  flex-shrink: 0;
}
[data-correct-match-suggestions] {
  display: flex;
  flex-direction: column;
  flex: 1 1 0;
  min-height: 0;
}
[data-correct-match-suggestions] .table-wrapper--sticky-head-inner {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}
[data-correct-match-suggestions] .table-scroll {
  flex: 1;
  min-height: 0;
  max-height: none;
  overflow-y: auto;
}

/* ==========================================================================
   15. RESPONSIVIDADE
   ========================================================================== */
@media (max-width: 768px) {
  body {
    overflow: initial;
  }
  /* Shell flui com o conteúdo e quem rola é o documento. A altura fixa
     (100dvh) + overflow:hidden de .app-shell/.main-column clipavam o
     conteúdo que ultrapassasse a viewport em telas mais baixas — o iPhone
     Pro Max (tela alta) escondia o bug porque tudo cabia em 100dvh. */
  .app-shell {
    overflow: initial;
    height: auto;
    min-height: 100dvh;
  }
  .main-column {
    overflow: initial;
  }
  .main-content {
    overflow: initial;
    padding: 16px;
    /* Respeita o home indicator do iPhone para o conteúdo (rodapé da
       tabela, paginação) não ficar sob a barra inferior. */
    padding-bottom: max(16px, env(safe-area-inset-bottom));
  }

  .sidebar {
    position: fixed;
    top: 0;
    left: 0;
    height: 100dvh;
    z-index: var(--z-sidebar);
  }
  .sidebar.is-collapsed {
    transform: translateX(-100%);
    width: var(--sidebar-expanded);
    min-width: var(--sidebar-expanded);
  }

  .side-drawer {
    width: 100%;
    max-width: 100vw;
  }

  .kpi-grid {
    grid-template-columns: 1fr 1fr;
  }

  .form-grid {
    grid-template-columns: 1fr;
  }
  .form-grid--2 {
    grid-template-columns: 1fr;
  }
  .form-grid--4 {
    grid-template-columns: 1fr;
  }
  .form-grid__col--span-2,
  .form-grid__col--span-3 {
    grid-column: 1 / -1;
  }

  /* Tabela: em mobile a tabela cresce até o conteúdo e quem rola é o
     documento (.main-content/body), igual ao desktop. NÃO usar max-height
     fixo aqui: um offset hardcoded não acompanha a altura real acima da
     tabela (accordion de filtros, título/subtítulo) nem as safe-area insets
     do iPhone, e acabava clipando as últimas linhas e o footer.
     overflow-y herda 'hidden' do default — com altura = conteúdo nada é
     clipado verticalmente; overflow-x: auto mantém o scroll horizontal. */
  .table-scroll {
    max-height: none;
  }
  /* O `--sticky-head` sai de cena em mobile: aqui a tabela precisa do scroll
     horizontal próprio, que é o preço do cabeçalho grudado. */
  .table-wrapper--sticky-head {
    overflow: hidden;
  }
  .table-wrapper--sticky-head .table-scroll {
    overflow-x: auto;
    overflow-y: hidden;
  }
  /* A fileira de controles também não gruda: em tela estreita ela quebra em
     duas linhas e comeria boa parte da altura útil. */
  .segmented-row--sticky {
    position: static;
    padding: 0;
    /* Fora do sticky a faixa opaca não tem função e cobriria o painel de cima. */
    box-shadow: none;
  }
  /* Drawers têm scroll próprio via .side-drawer__body (overflow-y: auto).
     Aplicar max-height ao .table-scroll dentro de um drawer criaria
     scroll-dentro-de-scroll em mobile — o browser não consegue determinar
     qual container deve receber o gesto de swipe. */
  .side-drawer .table-scroll {
    max-height: none;
    overflow-y: initial;
  }
  /* O layout de cabeçalho fixo do drawer de associação é de desktop: em
     mobile vale o padrão acima (um scroll só, o do corpo do drawer). */
  [data-product-associate-drawer-body] {
    overflow-y: auto;
  }
  [data-product-associate-suggestions]:not([hidden]),
  [data-product-associate-suggestions] .table-wrapper--sticky-head-inner,
  [data-product-associate-suggestions] .table-scroll {
    flex: none;
    min-height: auto;
  }
  [data-correct-match-drawer-body] {
    overflow-y: auto;
  }
  [data-correct-match-suggestions],
  [data-correct-match-suggestions] .table-wrapper--sticky-head-inner,
  [data-correct-match-suggestions] .table-scroll {
    flex: none;
    min-height: auto;
  }
}

@media (min-width: 600px) and (max-width: 1099px) {
  .form-grid--4 {
    grid-template-columns: repeat(2, 1fr);
  }
  .form-grid__col--span-3,
  .form-grid__col--span-2 {
    grid-column: span 2;
  }
}

/* ============================================================
   Info banner — aviso/contexto no topo de páginas DS
   ============================================================ */
/* `gap`/`padding`/`margin-bottom` eram `var(--space-sm)`/`var(--space-md)` —
   tokens que nunca existiram em `:root` (sem `--space-*` neste arquivo).
   `var()` inválido vira o valor inicial da propriedade (0), então o
   componente sempre renderizou colado, sem respiro — em toda tela que já
   usava `.info-banner`, não só aqui. Valores literais, no mesmo padrão dos
   demais componentes do arquivo (ex.: `.active-filters-bar`). */
.info-banner {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 16px;
  margin-bottom: 14px;
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-info);
  border-radius: var(--radius-md);
  background: var(--color-bg-surface-alt);
  color: var(--color-text-secondary);
  font-size: var(--font-sm);
  line-height: 1.45;
}
.info-banner > i,
.info-banner > svg {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  margin-top: 1px;
  color: var(--color-info);
}
.info-banner--neutral {
  border-left-color: var(--color-text-muted);
}
.info-banner--neutral > i,
.info-banner--neutral > svg {
  color: var(--color-text-muted);
}
.info-banner--warning {
  background: var(--color-warning-light);
  border-color: var(--color-warning);
  border-left: 4px solid var(--color-warning);
  color: var(--color-warning-text);
  font-weight: 500;
}
.info-banner--warning > i,
.info-banner--warning > svg {
  color: var(--color-warning);
}
.info-banner--danger {
  background: var(--color-danger-light);
  border-color: var(--color-danger);
  border-left: 4px solid var(--color-danger);
  color: var(--color-danger-text);
  font-weight: 500;
}
.info-banner--danger > i,
.info-banner--danger > svg {
  color: var(--color-danger);
}

/* ==========================================================================
   15. RE-SKIN — toques específicos da referência MI7 que os tokens não cobrem.
   O grosso do visual vem dos tokens (superfícies, texto, acento lima, raios,
   fontes). Aqui ficam só os ajustes pontuais de componente.
   ========================================================================== */

/* Sidebar: rótulo de seção técnico (mono + hairline à direita). */
.sidebar__section-label {
  font-family: var(--font-mono);
  font-weight: 600;
  letter-spacing: 0.08em;
  display: flex;
  align-items: center;
  gap: 8px;
}
.sidebar__section-label::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--color-border);
}

/* Cabeçalho de tabela e células em DM Mono (leitura técnica). */
.data-table thead th,
.data-table tbody td {
  font-family: var(--font-mono);
}
/* Corpo em mono mais leve: peso 300 e tamanho menor para suavizar
   (DM Mono em 400 tem traço cheio, que parece negrito numa tabela densa). */
.data-table tbody td {
  font-size: 12px;
  font-weight: 300;
  letter-spacing: -0.01em;
}
/* Preço praticado do relatório de política: cor pela mesma faixa do badge
   de Compliance (dentro/acima/abaixo), com peso de destaque. */
.data-table tbody td.cell-price--success {
  color: var(--color-success);
  font-weight: 500;
}
.data-table tbody td.cell-price--warning {
  color: var(--color-warning);
  font-weight: 500;
}
.data-table tbody td.cell-price--danger {
  color: var(--color-danger);
  font-weight: 500;
}

/* ==========================================================================
   DS CHARTS — biblioteca de gráficos (SVG) do Design System.
   Consumida por ``js/components/charts.js`` (``renderBarChart``). Tudo
   temável por tokens; nada de cor literal. Ver COMPONENTS.md.
   ========================================================================== */
.ds-chart {
  display: block;
  max-width: 100%;
  height: auto;
  /* Piso da altura final, reservado desde a primeira pintura (esqueleto ou
     SVG) — evita a página saltar quando o gráfico real substitui o esqueleto. */
  min-height: 120px;
}
.ds-chart__bar {
  fill: var(--color-accent);
  transition: opacity 0.15s ease;
}
.ds-chart__bar:hover {
  opacity: 0.82;
}
/* Segmentos de uma barra empilhada (``datum.segments``): o contorno na cor da
   superfície abre a folga entre segmentos vizinhos, como ``.ds-chart__arc``
   já faz — só nestas classes, para as barras simples não mudarem de
   aparência. */
.ds-chart__bar--success,
.ds-chart__bar--danger,
.ds-chart__bar--warning {
  stroke: var(--color-bg-surface);
  stroke-width: 2;
}
.ds-chart__bar--success {
  fill: var(--color-success);
}
.ds-chart__bar--danger {
  fill: var(--color-danger);
}
.ds-chart__bar--warning {
  fill: var(--color-warning);
}
.ds-chart__grid {
  stroke: var(--color-border);
  stroke-width: 1;
}
.ds-chart__axis {
  stroke: var(--color-border-strong);
  stroke-width: 1;
}
/* Tipografia do gráfico em DM Mono — mesma família das linhas da tabela
   (``.data-table tbody td``), para leitura técnica consistente. */
.ds-chart__label {
  fill: var(--color-text-primary);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 300;
}
.ds-chart__tick {
  fill: var(--color-text-muted);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 300;
  font-variant-numeric: tabular-nums;
}
.ds-chart__value {
  fill: var(--color-text-primary);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}
/* Rótulo de valor acima de cada ponto do gráfico de linha (opt-in via
   `showValueLabels`) — mesma tipografia do `.ds-chart__value` das barras. */
.ds-chart__value-label {
  fill: var(--color-text-primary);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}
.ds-chart__empty {
  fill: var(--color-text-muted);
  font-size: 13px;
}

/* Rosca (``renderDonutChart``): a cor da fatia vem de ``datum.variant``, para
   a página não escrever cor literal. */
/* O contorno na cor da superfície é o que abre a folga entre fatias vizinhas
   (não há espaço morto no anel: cada arco encosta no próximo). */
.ds-chart__arc {
  fill: var(--color-accent);
  stroke: var(--color-bg-surface);
  stroke-width: 2;
  transition: opacity 0.15s ease;
  /* Mãozinha na fatia: junto com o realce e o balão do `data-ui-tooltip`, é o
     que anuncia que ali há informação a mais. */
  cursor: pointer;
}
.ds-chart__arc--success {
  fill: var(--color-success);
}
.ds-chart__arc--danger {
  fill: var(--color-danger);
}
.ds-chart__arc--warning {
  fill: var(--color-warning);
}
.ds-chart__arc--info {
  fill: var(--color-info);
}
.ds-chart__arc--neutral {
  fill: var(--color-text-muted);
}
.ds-chart__arc--accent {
  fill: var(--color-accent);
}
.ds-chart__arc:hover {
  opacity: 0.82;
}
/* Miolo e chip da rosca em DM Sans (e não no mono dos eixos de barra): aqui o
   número é o destaque do painel, e o sans em peso alto é o que lê melhor. */
.ds-chart__center-label {
  fill: var(--color-text-secondary);
  font-size: 11px;
  font-weight: 400;
}
.ds-chart__center-value {
  fill: var(--color-text-primary);
  font-size: 20px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* A rosca tem lado natural fixo (``size``, 220px): num card mais largo ela para
   nesse lado e centraliza; num mais estreito, o ``max-width: 100%`` do
   ``.ds-chart`` encolhe o anel proporcionalmente. */
.ds-chart--donut {
  margin-inline: auto;
}
/* Chip do percentual: o número fica sobre a fatia, e as seis variantes são
   cores saturadas nos dois temas — o fundo próprio é o que garante contraste
   sem depender da cor da fatia. */
/* O chip fica sobre a fatia; sem isto ele engoliria o hover (tooltip e
   destaque da fatia sumiriam justo no meio dela). */
.ds-chart__slice-chip {
  pointer-events: none;
  filter: drop-shadow(0 1px 1px var(--color-border-strong));
}
.ds-chart__slice-chip-box {
  fill: var(--color-bg-surface);
  fill-opacity: 0.9;
}
.ds-chart__slice-label {
  fill: var(--color-text-primary);
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Linha (``renderLineChart``): a cor do ponto vem de ``datum.variant`` (faixa
   de compliance da coleta), a cor do traço da série é sempre neutra — a
   linha em si não representa uma faixa, os pontos que representam. */
.ds-chart__line {
  stroke: var(--color-accent);
  stroke-width: 2;
  fill: none;
}
.ds-chart__point {
  fill: var(--color-accent);
  stroke: var(--color-bg-surface);
  stroke-width: 1.5;
  cursor: pointer;
  transition: r 0.15s ease;
}
.ds-chart__point:hover {
  r: 5.5;
}
.ds-chart__point--success {
  fill: var(--color-success);
}
.ds-chart__point--danger {
  fill: var(--color-danger);
}
.ds-chart__point--warning {
  fill: var(--color-warning);
}
.ds-chart__point--info {
  fill: var(--color-info);
}
.ds-chart__point--neutral {
  fill: var(--color-text-muted);
}
.ds-chart__point--accent {
  fill: var(--color-accent);
}
/* Linha de referência (PPC sem/com variação): tracejada para não competir
   visualmente com a série de dados, que é a linha sólida. */
.ds-chart__refline {
  stroke: var(--color-border-strong);
  stroke-width: 1;
  stroke-dasharray: 4 3;
}
.ds-chart__refline--success {
  stroke: var(--color-success);
}
.ds-chart__refline--danger {
  stroke: var(--color-danger);
}
.ds-chart__refline--warning {
  stroke: var(--color-warning);
}
.ds-chart__refline--info {
  stroke: var(--color-info);
}
.ds-chart__refline--neutral {
  stroke: var(--color-text-muted);
}
.ds-chart__refline--accent {
  stroke: var(--color-accent);
}
.ds-chart__refline-label {
  fill: var(--color-text-secondary);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 400;
}
.ds-chart__refline-label--success {
  fill: var(--color-success);
}
.ds-chart__refline-label--danger {
  fill: var(--color-danger);
}
.ds-chart__refline-label--warning {
  fill: var(--color-warning);
}
.ds-chart__refline-label--info {
  fill: var(--color-info);
}
.ds-chart__refline-label--neutral {
  fill: var(--color-text-muted);
}
.ds-chart__refline-label--accent {
  fill: var(--color-accent);
}

/* Legenda da rosca — marcação da página (o JS do gráfico só desenha o SVG). */
.ds-chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  margin-top: 12px;
}
.ds-chart-legend__item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--font-xs);
  color: var(--color-text-secondary);
}
.ds-chart-legend__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-accent);
  flex-shrink: 0;
}
.ds-chart-legend__dot--success {
  background: var(--color-success);
}
.ds-chart-legend__dot--danger {
  background: var(--color-danger);
}
.ds-chart-legend__dot--warning {
  background: var(--color-warning);
}
.ds-chart-legend__dot--info {
  background: var(--color-info);
}
.ds-chart-legend__dot--neutral {
  background: var(--color-text-muted);
}
.ds-chart-legend__dot--accent {
  background: var(--color-accent);
}

/* Contagens abaixo da legenda ("Dentro da política: 12 (33%)"). Na mesma
   escala da legenda para caber em uma linha na coluna mais estreita da
   ``.chart-grid``. */
.ds-chart-counts {
  margin-top: 10px;
  font-size: var(--font-xs);
  color: var(--color-text-secondary);
  font-variant-numeric: tabular-nums;
}

/* Grade de cards de gráfico — uma rosca por dimensão, lado a lado. Colunas
   iguais que quebram de 3 → 2 → 1 conforme a largura disponível. */
.chart-grid {
  display: grid;
  /* O piso é ``min(260px, 100%)`` e não ``260px``: em container mais estreito
     que a trilha mínima, a coluna acompanha o container em vez de estourar. */
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: 16px;
  margin-bottom: 24px;
}
/* Item de grid não encolhe abaixo do próprio min-content (``min-width: auto``):
   sem isto o card da rosca fica mais largo que a coluna, come o ``gap`` e o
   último passa da borda da grade. Com ``0``, quem manda é a trilha e o anel
   encolhe junto (``max-width: 100%`` do ``.ds-chart``). */
.chart-grid > .card {
  min-width: 0;
}
/* ``.card + .card`` é o empilhamento vertical (um card sob o outro). Aqui o
   espaçamento é o ``gap``: essa margem empurraria do segundo card em diante
   16px para baixo, e a fileira apareceria com o primeiro card mais alto que
   os vizinhos. */
.chart-grid > .card + .card {
  margin-top: 0;
}
/* Folga antes da `.segmented-row--sticky`: a faixa opaca de 16px que ela
   desenha acima de si (ver comentário lá) pinta em cima de quem vier colado
   nela — sem essa margem, o fim do card "Por ocorrência" fica coberto pela
   faixa em vez de aparecer o fechamento arredondado do card. */
.chart-grid + .card {
  margin-bottom: 16px;
}

/* ==========================================================================
   SEGMENTED — controle segmentado (escolha única entre 2–4 opções curtas,
   ex.: "Por seller | Por produto | Por grupo"). Não confundir com
   ``.table-density-control``, que é o controle de densidade do cabeçalho da
   tabela, nem com ``.tabs``, que troca painel de conteúdo.
   ========================================================================== */
.segmented {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg-surface);
  overflow: hidden;
}
.segmented__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: var(--control-height);
  padding: 0 12px;
  border: 0;
  border-left: 1px solid var(--color-border);
  background: transparent;
  color: var(--color-text-secondary);
  font-size: var(--font-xs);
  font-weight: 500;
  white-space: nowrap;
  transition:
    background-color var(--t-fast),
    color var(--t-fast);
}
.segmented__btn:first-child {
  border-left: 0;
}
.segmented__btn:hover {
  background: var(--color-bg-hover);
  color: var(--color-text-primary);
}
.segmented__btn.is-active {
  background: var(--color-accent);
  color: var(--color-text-on-accent);
}
.segmented__btn[disabled],
.segmented__btn[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
}
.segmented__btn[disabled] {
  pointer-events: none;
}
/* Botão desenhado-mas-inativo usa `aria-disabled` para o hover sobreviver e o
   balão do `data-ui-tooltip` ("Recurso em desenvolvimento") aparecer — mesma
   escolha do `.custom-select__trigger.is-locked`. Some só o realce de hover,
   que prometeria um clique que não existe. */
.segmented__btn[aria-disabled="true"]:hover {
  background: transparent;
  color: var(--color-text-secondary);
}
/* Ícone opcional antes do rótulo (ex.: alternar Lista/Quadro). O Lucide
   entrega o SVG em 24px, que estoura a altura do botão. */
.segmented__btn i,
.segmented__btn svg {
  width: 13px;
  height: 13px;
  flex-shrink: 0;
}
/* Variante só-ícone (ex.: alternar Lista/Cards). */
.segmented--icon .segmented__btn {
  width: var(--control-height);
  padding: 0;
}

/* Fileira de segmentados lado a lado (agrupamento + modo de exibição, acima da
   tabela). `align-items: center` porque `.segmented` é `inline-flex` e alinha
   pela baseline: o grupo só-ícone não tem texto, e os dois saíam em degrau. */
.segmented-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 16px;
}
/* Empurra o que vem depois para a ponta direita da fileira (ex.: Exportar
   Excel), alinhado com os segmentados pelo `align-items: center` da fileira. */
.segmented-row__end {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
}
/* Modificador `--sticky`: a fileira gruda no topo enquanto o resto da página
   rola (quem rola é o `.main-content`), para os controles de agrupamento não
   saírem da tela junto com os gráficos.
   O fundo opaco é obrigatório: sem ele o conteúdo aparece por baixo. O
   `z-index` fica acima do `thead` grudado (que usa 2), senão o cabeçalho da
   tabela passaria por cima ao chegar aqui. */
.segmented-row--sticky {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--color-bg-content);
  padding: 8px 0;
  /* Faixa opaca de 16px acima da fileira, na mesma camada dela (`z-index: 3`):
     cobre a área entre o topo da rolagem e os botões, por onde o conteúdo que
     sobe apareceria. Sombra e não `padding` porque não entra no layout — a
     fileira segue com 50px, medida de que o `top` do cabeçalho depende. Tem
     de bater com o `margin-bottom` de `.chart-grid + .card`: menor que ela, a
     faixa cobre só espaço em branco; maior, passaria a cobrir o fim do card. */
  box-shadow: 0 -16px 0 var(--color-bg-content);
  /* Altura tem de ser previsível: é dela que sai o `top` do cabeçalho grudado
     da tabela. Se a fileira quebrasse em duas linhas, ela cresceria e passaria
     a cobrir o cabeçalho. Os dois segmentados juntos dão ~350px, então cabem
     em qualquer largura de desktop (em mobile o modificador se desliga). */
  flex-wrap: nowrap;
}
/* Quando há um `.filter-toolbar--sticky` antes na página (seção 09), a
   fileira soma a altura REAL do toolbar grudado (`--sticky-toolbar-h`,
   publicada por `scroll-collapse.js` — 0 quando não está pinado) menos os
   mesmos 16px do `top: -16px` do toolbar. Por que medir em vez de somar um
   valor fixo: condensado a altura é previsível, mas o toolbar ainda
   expandido-e-pinado (revelado ao subir a rolagem, sem voltar ao topo) tem
   altura variável — sem medir de verdade, a fileira ficaria escondida
   atrás dele nesse estado. */
.filter-toolbar--sticky ~ .segmented-row--sticky {
  top: calc(var(--sticky-toolbar-h, 0px) - 16px);
}

/* O reset de mobile da seção 15 (RESPONSIVIDADE) vem antes desta declaração
   no arquivo: mesma especificidade, e a cascata resolve por ordem — a
   incondicional acima venceria mesmo em telas estreitas. Repete o reset
   aqui, depois dela, pra o sticky realmente desligar em mobile — bug
   pré-existente do `.segmented-row--sticky` que precisa ser corrigido
   aqui por afetar o critério de aceite do toolbar grudado nesta tela.
   Os estados de rolagem (`.is-pinned`, `.is-condensed`) não entram neste
   reset: eles já vivem inteiros dentro de `@media (min-width: 769px)` na
   seção 09 — quem ler `.is-pinned` em regra nova tem que fazer o mesmo,
   porque `scroll-collapse.js` alterna as classes em qualquer viewport. */
@media (max-width: 768px) {
  .segmented-row--sticky,
  .filter-toolbar--sticky {
    position: static;
    box-shadow: none;
  }
  .segmented-row--sticky {
    padding: 0;
  }
  :root {
    --ds-sticky-summary-h: 0px;
  }
}

/* ==========================================================================
   INFO-PANEL — bloco de explicação colapsável sobre ``<details>``/
   ``<summary>`` nativos, sem JavaScript. Não confundir com
   ``.filter-accordion`` (acordeão da barra de filtros, ligado ao
   ``AccordionManager``) nem com ``.info-banner`` (aviso, não colapsável).
   ========================================================================== */
.info-panel {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg-surface);
  /* Folga até o bloco que o painel explica (os cards de gráfico, a tabela) —
     mesma medida do ``gap`` entre os cards, para a página manter um ritmo só.
     Sem isto o painel encosta no bloco de baixo. */
  margin-bottom: 16px;
}
.info-panel__summary {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  cursor: pointer;
  font-size: var(--font-xs);
  font-weight: 600;
  color: var(--color-text-primary);
  list-style: none;
}
.info-panel__summary::-webkit-details-marker {
  display: none;
}
.info-panel__summary .info-panel__chevron {
  margin-left: auto;
  display: inline-flex;
  color: var(--color-text-muted);
  transition: transform var(--t-fast);
}
.info-panel[open] .info-panel__summary .info-panel__chevron {
  transform: rotate(180deg);
}
.info-panel__body {
  padding: 12px 14px;
  border-top: 1px solid var(--color-border);
  font-size: var(--font-xs);
  color: var(--color-text-secondary);
}

/* ==========================================================================
   BACK TO TOP — botão flutuante que leva ao topo da rolagem, criado por
   `back-to-top.js` (`createBackToTop`). Adesão explícita, como o
   `.filter-toolbar--sticky`: a tela liga por conta própria. `.is-visible`
   é estado em tempo real (html_guide.md), não variante — por isso
   `.is-*`. `z-index` em `--z-overlay`: acima do conteúdo e do
   header/sidebar, abaixo de drawer/modal/tooltip — não deve competir com
   eles quando abertos.
   ========================================================================== */
.back-to-top {
  position: fixed;
  right: 24px;
  bottom: 24px;
  z-index: var(--z-overlay);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: var(--color-bg-surface);
  color: var(--color-text-secondary);
  box-shadow: var(--shadow-md);
  opacity: 0;
  pointer-events: none;
  transform: translateY(8px);
  transition:
    opacity var(--t-base),
    transform var(--t-base),
    background var(--t-fast),
    color var(--t-fast);
}
.back-to-top:hover {
  background: var(--color-bg-hover);
  color: var(--color-text-primary);
}
.back-to-top.is-visible {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}
.back-to-top i,
.back-to-top svg {
  width: 18px;
  height: 18px;
}
@media (prefers-reduced-motion: reduce) {
  .back-to-top {
    transition: none;
  }
}

/* ==========================================================================
   KANBAN — quadro de colunas com cartões arrastáveis (a central de
   ocorrências em modo quadro). Não confundir com ``.tabs``, que troca painel
   de conteúdo, nem com ``.data-table``, que mostra o mesmo recorte em linhas.
   A mecânica de arrastar é o ``components/kanban-dnd.js``.
   ========================================================================== */
.kanban {
  display: flex;
  align-items: stretch;
  gap: 12px;
  overflow-x: auto;
  /* Sem rolagem vertical no quadro: quem rola na vertical é o corpo de cada
     coluna. Explícito porque `overflow-x: auto` sozinho faz o eixo Y virar
     `auto` também. */
  overflow-y: hidden;
  padding-bottom: 8px;
  /* Gruda no topo da área de conteúdo: rolando a página, o cabeçalho, os
     filtros e o alternador sobem e o quadro ocupa a tela inteira. O respiro
     acima das colunas é o `padding-top` opaco; a altura sai do `board.js`. */
  position: sticky;
  top: 0;
  height: var(--kanban-h, calc(100dvh - 140px));
  padding-top: 12px;
  background: var(--color-bg-content);
  overscroll-behavior: contain;
}

/* Coluna = bandeja rebaixada, com os cartões como superfície elevada dentro
   dela. As sete dividem a largura em partes iguais e param de encolher em
   `min-width`, quando o quadro passa a rolar na horizontal; o `stretch` as
   estica à altura da mais cheia, então a coluna vazia continua sendo um
   destino de soltar do tamanho das outras. */
.kanban__column {
  display: flex;
  flex: 1 1 0;
  flex-direction: column;
  min-width: 150px;
  min-height: 200px;
  /* A coluna cabe na altura do quadro e rola por dentro: o cabeçalho fica fora
     do que rola, então o rótulo e a contagem não saem da vista. */
  max-height: 100%;
  overflow: hidden;
  background: var(--color-bg-overlay);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  transition:
    background-color var(--t-fast),
    border-color var(--t-fast),
    box-shadow var(--t-fast),
    opacity var(--t-fast);
}

/* Gruda no topo do quadro durante a rolagem dele: com a coluna alta, é o que
   mantém visível de qual coluna é o cartão na tela. Fundo opaco obrigatório —
   sem ele os cartões passam por baixo. */
.kanban__header {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 9px 12px;
  background: var(--color-bg-overlay);
  border-bottom: 1px solid var(--color-border);
  border-radius: var(--radius-md) var(--radius-md) 0 0;
}
/* A faixa do tom deitada sobre o fio do cabeçalho, comprida na proporção que
   a coluna ocupa no recorte (`--kanban-share`, que o `board.js` mede): a cor
   diz qual coluna é e o comprimento diz quanto do recorte está nela. Coluna
   vazia fica só com o fio. */
.kanban__header::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: -1px;
  left: 0;
  height: 2px;
  background: var(--kanban-tone, var(--color-border-strong));
  transform: scaleX(var(--kanban-share, 0));
  transform-origin: left;
  transition: transform var(--t-base);
}
.kanban__title {
  font-size: var(--font-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Total do recorte da coluna, não o número de cartões já carregados. O número
   é onde o tom aparece em texto, então dispensa pílula em volta. */
.kanban__count {
  margin-left: auto;
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-size: var(--font-sm);
  font-weight: 500;
  color: var(--kanban-tone, var(--color-text-secondary));
  font-variant-numeric: tabular-nums;
}

/* Tom de cada etapa nas semânticas do DS: cadastro pendente e seller avisado
   esperam alguém de fora, o prazo vencido é o crítico e a tratativa encerrada
   é a saída. Uma variável por coluna — a faixa, a contagem e o realce de
   destino saem todos dela. */
.kanban__column--new-seller {
  --kanban-tone: var(--color-info);
  --kanban-tone-dim: var(--color-info-light);
}
.kanban__column--notified {
  --kanban-tone: var(--color-info);
  --kanban-tone-dim: var(--color-info-light);
}
.kanban__column--overdue {
  --kanban-tone: var(--color-danger);
  --kanban-tone-dim: var(--color-danger-light);
}
.kanban__column--closed {
  --kanban-tone: var(--color-success);
  --kanban-tone-dim: var(--color-success-light);
}
/* As três colunas de grau numa gradação do aviso ao crítico, misturada das
   duas variáveis semânticas. */
.kanban__column--degree-0 {
  --kanban-tone: var(--color-warning);
  --kanban-tone-dim: var(--color-warning-light);
}
.kanban__column--degree-1 {
  --kanban-tone: color-mix(in srgb, var(--color-warning) 55%, var(--color-danger));
  --kanban-tone-dim: color-mix(in srgb, var(--color-warning-light) 55%, var(--color-danger-light));
}
.kanban__column--degree-2 {
  --kanban-tone: color-mix(in srgb, var(--color-warning) 20%, var(--color-danger));
  --kanban-tone-dim: color-mix(in srgb, var(--color-warning-light) 20%, var(--color-danger-light));
}

.kanban__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 8px;
  padding: 10px;
  /* `min-height: 0` é o que deixa o corpo encolher dentro da coluna e rolar. */
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--color-border) transparent;
}
.kanban__body::-webkit-scrollbar {
  width: 8px;
}
.kanban__body::-webkit-scrollbar-thumb {
  background: var(--color-border);
  border-radius: 4px;
}

/* Sem sombra: o cartão fica no mesmo plano da linha de tabela do resto do
   painel, e é a borda que o separa do fundo afundado da coluna. */
.kanban__card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 9px 11px;
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  transition:
    border-color var(--t-fast),
    opacity var(--t-fast),
    transform var(--t-fast);
  animation: kanban-card-in var(--t-fast) ease-out both;
}
/* Entrada dos cartões que a coluna acabou de receber: a repintura vem de uma
   consulta ou de uma escrita, e o movimento curto é o que mostra que a coluna
   trocou de conteúdo em vez de sempre ter estado assim. */
@keyframes kanban-card-in {
  from {
    opacity: 0;
    transform: translateY(4px);
  }
}
.kanban__card[draggable="true"] {
  cursor: grab;
}
.kanban__card:hover {
  border-color: var(--color-border-strong);
}
/* Cartão em voo: o que fica no lugar é o vão que ele deixou — contorno
   tracejado, sem conteúdo legível e um pouco recuado. A classe entra no
   quadro seguinte ao `dragstart` (ver `kanban-dnd.js`), depois de o navegador
   ter fotografado o cartão para a imagem que acompanha o cursor. */
.kanban__card.is-dragging {
  cursor: grabbing;
  border-style: dashed;
  border-color: var(--color-border-strong);
  transform: scale(0.97);
}
.kanban__card.is-dragging > * {
  opacity: 0.25;
}
/* Cartão a caminho da coluna nova: percorre num movimento o caminho entre a
   posição que tinha e a que o backend lhe deu. Passa por cima dos outros
   cartões e não repete a entrada, que é para cartão que chega, não para
   cartão que se move. */
.kanban__card.is-moving {
  position: relative;
  z-index: 2;
  animation: none;
  transition: transform var(--t-base) ease-out;
}
/* Cartão com escrita em voo: opaco e sem clique até a resposta chegar (mesma
   convenção de ``.data-table tr[aria-busy="true"]``). */
.kanban__card[aria-busy="true"] {
  opacity: 0.5;
  pointer-events: none;
}

/* Quem está sendo tratado vem primeiro, como na primeira coluna da listagem;
   o código e o canal são os qualificadores curtos e dividem a linha seguinte
   quando a coluna estreita não deixa os três caberem lado a lado. */
.kanban__card-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 2px 8px;
  min-width: 0;
}
.kanban__seller {
  flex: 1 1 60%;
  overflow: hidden;
  font-size: var(--font-sm);
  font-weight: 600;
  color: var(--color-text-primary);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.kanban__channel {
  flex: 0 1 auto;
  margin-left: auto;
  overflow: hidden;
  font-size: var(--font-xs);
  color: var(--color-text-muted);
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Duas linhas com reticências: a descrição do produto do vendedor é longa e
   de tamanho variável, e a altura do cartão precisa ser previsível. */
.kanban__card-title {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  font-size: var(--font-xs);
  line-height: 1.4;
  color: var(--color-text-secondary);
}
.kanban__code {
  margin-right: 5px;
  font-family: var(--font-mono);
  color: var(--color-text-primary);
}
/* O número e o que ele significa numa frase, em vez de rótulo e valor nas duas
   pontas da linha: o rótulo em duas palavras não cabe ao lado do valor na
   largura mínima da coluna. */
.kanban__gap {
  font-size: var(--font-xs);
  color: var(--color-text-muted);
}
.kanban__gap-value {
  font-family: var(--font-mono);
  font-weight: 500;
  color: var(--color-danger-text);
}
.kanban__recurrence {
  font-size: var(--font-xs);
  color: var(--color-warning-text);
}
/* O prazo e as ações dividem a linha e passam a duas linhas na coluna
   estreita, onde os dois juntos não caberiam lado a lado. */
.kanban__card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 6px 8px;
  min-width: 0;
  margin-top: 1px;
  padding-top: 7px;
  border-top: 1px solid var(--color-border);
}
.kanban__deadline {
  font-size: var(--font-xs);
  color: var(--color-text-secondary);
}
.kanban__deadline.is-overdue {
  font-weight: 500;
  color: var(--color-danger-text);
}
.kanban__deadline.is-none {
  color: var(--color-text-muted);
}
/* As ações aparecem no cartão apontado, para a coluna em repouso mostrar
   ocorrência e não fileira de botão. Onde não há apontador (toque), ficam
   sempre visíveis — seria a única forma de alcançá-las. */
@media (hover: hover) {
  .kanban__card .table-actions {
    opacity: 0;
    transition: opacity var(--t-fast);
  }
  .kanban__card:hover .table-actions,
  .kanban__card:focus-within .table-actions {
    opacity: 1;
  }
}

/* Escrita de cartão no ar: o quadro inteiro para de aceitar clique e arraste
   até a resposta chegar. */
.kanban.is-busy .kanban__card,
.kanban.is-busy .kanban__more {
  pointer-events: none;
}
.kanban.is-busy .kanban__column {
  opacity: 0.72;
}

/* O que falta no cadastro do seller, no rodapé do cartão da coluna de novo
   seller. */
.kanban__pending {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  font-size: var(--font-xs);
  color: var(--color-warning-text);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Com um cartão em voo o quadro inteiro recua um pouco, para as colunas que
   aceitam o cartão serem o que sobra em evidência. */
.kanban.is-dnd .kanban__column {
  opacity: 0.72;
}
/* Destino que aceita o cartão em voo: o tom da coluna de destino, o mesmo da
   faixa do cabeçalho, num anel interno e num fundo tonal. É o tom que diz
   para onde o cartão vai. */
.kanban.is-dnd .kanban__column.is-drop-target {
  opacity: 1;
  background: var(--kanban-tone-dim);
  border-color: var(--kanban-tone);
  box-shadow: inset 0 0 0 1px var(--kanban-tone);
}
.kanban.is-dnd .kanban__column.is-drop-target .kanban__header {
  background: transparent;
}
/* Destino que recusa: nenhuma operação da central leva o cartão para cá. */
.kanban.is-dnd .kanban__column.is-drop-forbidden {
  border-style: dashed;
  border-color: var(--color-border-strong);
}
.kanban.is-dnd .kanban__column.is-drop-forbidden .kanban__body {
  opacity: 0.45;
}
/* A coluna de onde o cartão saiu não é destino, mas também não é recusa: fica
   como estava, para o vão tracejado do cartão continuar legível. */
.kanban.is-dnd .kanban__column:has(.kanban__card.is-dragging) {
  opacity: 1;
}

.kanban__empty,
.kanban__error {
  padding: 18px 12px;
  text-align: center;
  font-size: var(--font-xs);
  color: var(--color-text-muted);
}
.kanban__error {
  color: var(--color-danger-text);
}
.kanban__more {
  width: 100%;
  padding: 6px;
  font-size: var(--font-xs);
  font-weight: 500;
  color: var(--color-text-secondary);
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  transition:
    background-color var(--t-fast),
    color var(--t-fast);
}
.kanban__more:hover {
  background: var(--color-bg-hover);
  color: var(--color-text-primary);
}
/* Altura do esqueleto = a de um cartão montado, para a coluna não pular de
   tamanho quando os cartões chegam. */
.kanban__skeleton {
  height: 108px;
  border-radius: var(--radius-sm);
}

@media (prefers-reduced-motion: reduce) {
  .kanban__card,
  .kanban__card.is-moving,
  .kanban__column,
  .kanban__header::after {
    transition: none;
  }
  .kanban__card {
    animation: none;
  }
  .kanban__card.is-dragging {
    transform: none;
  }
}
