/* ===== TOKENS ===== */
/* ==========================================================================
   Four Cloud Design System — TOKENS (scale + palette).
   The provider-neutral foundation: one --density knob scales type+spacing
   together; one slate accent carries structure; colour is rationed to meaning
   (red = money leaving, green = small positive deltas). Ported from the tested
   statement mockup (bi/static/bi/demo/statement.{scale,tokens}.css).

   This is the TOKENS section — first in custom.css, everything below depends on it.
   ========================================================================== */

:root{
  /* ── scale (no colour) ─────────────────────────────────────────────── */
  --density:1;                 /* THE knob — >1 comfortable, <1 compact */
  --metric-hero:calc(40px*var(--density));
  --metric-kpi: calc(22px*var(--density));
  --metric-sig: calc(24px*var(--density));
  --hero-unit:  calc(17px*var(--density));
  /* Batch6 note: --card-pad-* / --tile-pad-* are SUPERSEDED by the unified card
     contract (header 8/16/8, body 8/16/16 — docs/planos/batch6-card-contract.md §1).
     They are NOT re-pointed to --bi-space-* here because they are density-scaled px
     and re-pointing would strip the --density knob (kept per Batch5 §3) and risk
     reflow on the FCDS faturamento components. The unified padding is applied at the
     component layer (custom.css, owned by Impl-3); these remain the px base
     the --density knob multiplies until that layer re-points them. */
  --card-pad-y:calc(14px*var(--density));  --card-pad-x:calc(18px*var(--density));
  --tile-pad-y:calc(12px*var(--density));  --tile-pad-x:calc(14px*var(--density));  --tile-pad-b:calc(10px*var(--density));
  --gap:calc(0.5rem*var(--density));
  --content-pad-y:calc(16px*var(--density)); --content-pad-x:calc(20px*var(--density));
  --content-pad-b:calc(36px*var(--density));
  --card-hd-mb:calc(10px*var(--density));
  /* component pixel dims — static (NOT density-scaled, to avoid chart reflow) */
  --doughnut:168px; --ring-size:80px; --spark-h:40px; --flow-min:248px;
  --r:var(--bs-border-radius-lg); --r-sm:var(--bs-border-radius); --r-xs:var(--bs-border-radius-sm); --r-full:var(--bs-border-radius-pill);

  /* ── palette ───────────────────────────────────────────────────────── */
  --surface-app:#edf0f4;       /* the canvas — matches shell body gradient base
                                  (custom.css:22); --bi-bg-base re-points here
                                  (Batch 8, single source for #edf0f4 vs #F4F6F8) */
  --bg:#f6f7f9;
  --surf:#ffffff; --surf-2:#f3f4f7; --surf-3:#eceef2;
  --line:#e6e8ec; --line-2:#eef0f3; --line-3:#d8dbe1;
  --ink:#191c22; --ink-2:#5a6171; --ink-3:#6b7280; --ink-4:#aab0bb;  /* ink-3 #8b93a1→#6b7280: was 3.09:1 (fail AA), now ~4.7:1 */
  /* ACENTO DE COMPONENTE — o azul DE FÁBRICA do Bootstrap, sem cor autoral
     nenhuma: os degraus APONTAM para as variáveis do próprio Bootstrap. Quem
     pinta seleção, foco, chip ligado, dia/mês escolhido e página ativa da
     paginação lê daqui. Se um dia o tema do Bootstrap mudar, isto muda junto —
     é esse o objetivo. Cinza só no SHELL, em --shell-acc-* logo abaixo. */
  --acc:var(--bs-primary); --acc-d:var(--bs-link-hover-color); --acc-ink:var(--bs-link-hover-color);
  /* únicos hex: a dupla *-bg-subtle/*-border-subtle nasceu no 5.3 e o bundle é
     5.2.3 — valores de fábrica do upstream, não cor autoral. */
  --acc-soft:#cfe2ff; --acc-line:#9ec5fe;
  /* ACENTO DO SHELL — o cinza DO BOOTSTRAP (secondary + escada gray), a única
     exceção ao azul, por diretiva do usuário. Consumido SÓ pela sidebar e pela
     topbar (§2/§3): item de menu ativo, trilho da esquerda, avatar e botão de
     menu. Não usar em conteúdo de página. */
  --shell-acc:var(--bs-secondary); --shell-acc-ink:var(--bs-gray-700);
  --shell-acc-soft:var(--bs-gray-200); --shell-acc-line:var(--bs-gray-300);

  /* Escada de tinta do Bootstrap com os VALORES DE FÁBRICA do 5.3 (rgba do corpo a
     75% e a 50%), e não com a tinta FCDS: por diretiva do usuário, nenhuma paleta
     de cor de texto é repontada aqui. Os dois tokens continuam declarados só porque
     o bundle vendorizado é 5.2.3 e não os traz — os utilitários que os consomem
     estão portados mais abaixo. NÃO apontar para --ink-*. */
  --bs-secondary-color: rgba(33, 37, 41, 0.75);
  --bs-tertiary-color: rgba(33, 37, 41, 0.5);
  /* Os utilitários que consomem estes dois tokens só nasceram no Bootstrap 5.3 e o
     build vendorizado é 5.2.3 — por isso eles estão portados logo abaixo de
     .num--* neste arquivo. Quando o Bootstrap subir para 5.3, apagar o port: os
     tokens acima já alimentam a versão upstream, sem tocar em nenhum consumidor. */

  /* CANONICAL COLOR SYSTEM — single source of truth for color meaning.
     Reuse everywhere; never hardcode hex. Ref: docs/planos/batch2-semantic-color-contract.md
     Structure tokens (text/surface/border) are above: --ink/--surf/--line/--acc.
     PRIMARY = brand slate for non-semantic UI emphasis. */
  /* AÇÃO — era o azul Four #006BB5. Passa a apontar para o acento de componente,
     ou seja, o azul de fábrica do Bootstrap: os botões sólidos desta família
     (Buscar, .tb-btn--solid, .gcx-seg ligado) vivem lado a lado com a paginação e
     com os .btn-primary do Bootstrap, e dois azuis quase iguais na mesma tela
     leem como defeito. Um azul só. Os quatro nomes ficam porque 35 regras os
     consomem — repontar aqui alinha todas de uma vez. */
  --brand: var(--acc);
  --brand-strong: var(--acc-d);
  --brand-soft: var(--acc-soft);
  --brand-ink: var(--acc-ink);
  --command: #2b3038;        /* near-black ink for DATA magnitude where charcoal is wanted (sparklines). NOT an action color. */

  /* ── DIRECTION (value valence) ────────────────────────────────────────────
     Two tiers + a bg tint, per direction:
       --x        vivid FILL  — bars, chart datasets, icons, rules, dots.
       --x-text   AA-safe     — small text / numbers on white (≥4.5:1)…
                                …EXCEPT --warning-text (#f59e0b ~2.1:1): kept
                                vivid by product decision (saturation > AA).
       --x-subtle BACKGROUND-ONLY tint — badges/chips; never text.
     Color encodes DIRECTION only — never category/type/entity (use --cat-* for that). */
  --positive:#22c55e;  --positive-text:#15803d;  --positive-subtle:color-mix(in srgb, var(--positive-text) 10%, var(--surf));
  --negative:#ef4444;  --negative-text:#ca2a26;  --negative-subtle:#fcecea;
  /* --warning-text era #f59e0b (o próprio fill): 2,15:1 sobre branco, reprova
     WCAG até em texto grande. Agora é o passo escuro do mesmo âmbar (5,93:1). */
  /* --warning-text aponta para a MESMA laranja do sistema de gráficos: era
     #8a5a00 (mostarda), uma terceira família para dizer "atenção". Regra do
     projeto: indicador de UI e área de gráfico marcam a mesma coisa com a mesma
     família, mudando só o degrau (ver docs/globais/componentes.md). Alimenta
     .badge--warning e .alert-warning — o app inteiro. --warning (o FILL vivo)
     não muda: só o degrau de TEXTO foi unificado. */
  --warning:#f59e0b;   --warning-text:var(--chart-alerta-text);   --warning-subtle:color-mix(in srgb, var(--warning) 14%, var(--surf));
  --neutral:#94a3b8;   --neutral-subtle:color-mix(in srgb, var(--ink-2) 9%, var(--surf));
  --info:#1f9bcf;      --info-text:#15709c;      --info-subtle:color-mix(in srgb, var(--info) 12%, var(--surf));

  /* ── INDICATOR ALIASES (semantic, AA-safe small text) ─────────────────────
     cores.md prescribes these names for inline notices. --warning-text is kept
     vivid (#f59e0b, fails AA at small sizes) so this alias supplies a deeper tone
     for small WARNING note/label text.
     Agora aponta para --chart-alerta-text: o mostarda #8a6d1f que morava aqui era
     uma TERCEIRA laranja, sem parentesco com a do sistema de gráficos. Indicador e
     gráfico marcam a mesma coisa ("faixa de atenção") e passam a marcar com a mesma
     família. Alias mantido porque 8 chamadas o consomem — repontar aqui alinha todas. */
  --color-indicator-warning-text: var(--chart-alerta-text);

  /* ── RANGE (ordered scale, good→bad) ──────────────────────────────────────
     For 3-stop ramps / conditional thresholds. *-normal-1 = best (green),
     *-inverted reverses valence (when high = bad, e.g. cost/aging). */
  --range-normal-1:var(--positive);   --range-normal-2:var(--warning);   --range-normal-3:var(--negative);
  --range-inverted-1:var(--negative); --range-inverted-2:var(--warning); --range-inverted-3:var(--positive);

  /* ── CATEGORY (qualitative identity — NO valence) ─────────────────────────
     Full-hue-wheel, evenly spaced & lightness-harmonised so each series is
     instantly distinguishable. Charts read these via getComputedStyle. */
  --cat-1:#2563eb; --cat-2:#f97316; --cat-3:#16a34a; --cat-4:#9333ea;
  --cat-5:#db2777; --cat-6:#0e7490; --cat-7:#ca8a04; --cat-8:#dc2626;

  /* ── PALETA DE GRÁFICOS ───────────────────────────────────────────────────
     Regras completas em docs/globais/componentes.md §Gráficos e no design
     aprovado em docs/superpowers/specs/2026-07-27-sistema-cor-graficos-design.md.

     São QUATRO cores, e só. Cada uma responde a uma pergunta:
       --chart-azul    QUANTO      magnitude sem sinal (receita, volume, saldo, contagem)
       --positive      POSITIVO    entrada, ganho, acima da meta
       --negative      NEGATIVO    saída, perda, abaixo do mínimo
       --chart-alerta  ATENÇÃO     a faixa antes do vermelho, onde existe limiar

     CATEGORIZAR = opacidade do azul, em quantos passos a série pedir (não há
     teto e não há agregação em "Outros"): biChartConfig.rampaAzul(n). Dois tons
     vizinhos de uma rampa longa são perceptualmente iguais — quem devolve a
     leitura é o SEPARADOR na cor da superfície (3px em fatia de donut, 1,5px
     entre segmentos empilhados) somado ao rótulo. Sem separador, rampa longa é
     ilegível: ele é requisito, não enfeite.

     CINZA não é cor de dado. Sobrevive só em tick, rótulo e borda (--ink-*).

     --chart-alerta #e3660e dá 3,40:1 sobre o card: passa o piso de 3:1 de
     elemento gráfico, mas fica abaixo dos 4,5:1 de texto pequeno — por isso só
     pinta ÁREA (arco, barra, ponto), nunca número. */
  --chart-azul:#2563eb;
  --chart-alerta:#e3660e;
  /* Degrau de TEXTO da mesma laranja (85% de #e3660e): 5,41:1 sobre a superfície,
     em linha com --positive-text (5,02) e --negative-text (5,43). Existe porque
     --chart-alerta é 3,40:1 — passa como ÁREA de gráfico, reprova como texto.
     REGRA: indicador de UI (número, badge, dot) usa o degrau `-text` da família;
     área de gráfico (arco, barra, ponto) usa o degrau base. Mesma família nos
     dois casos — a faixa de atenção da tela é a MESMA laranja da faixa de
     atenção do gráfico, não um mostarda paralelo. */
  --chart-alerta-text:#b04c0a;

  /* Fonte ÚNICA do projeto: Roboto. --mono existe só p/ os números tabulares
     (mesma Roboto + font-variant-numeric:tabular-nums nos usos) — não há 2ª fonte. */
  --sans:'Roboto',ui-sans-serif,'Helvetica Neue',Arial,sans-serif;
  --mono: var(--sans);
  /* --bs-font-monospace REMAPEADO para o Roboto por diretiva do usuário: Roboto
     é a única fonte do projeto. Sem este remap a primitiva do Bootstrap ficava de
     fábrica e a utility `.font-monospace`, <code> e <pre> caíam no stack
     SFMono/Menlo/Consolas — uma 2ª fonte, viva em 9 arquivos (importar-of,
     matriz-acesso, faturamento-fcds, diagnostico-preenchimento, pedidos,
     dre-steel, forecast-comex, catalogo). Como TODO o vazamento passava por esta
     variável, o remap resolve os 9 de uma vez; não há font-family mono
     hardcoded em lugar nenhum deste arquivo. */
  --bs-font-monospace: var(--sans);
  /* all resting shadows removed app-wide (user directive). Only --ring (keyboard
     focus, a11y) survives. Every surface is flat: hairline border + surface ladder. */
  --sh1:none;
  --sh2:none;
  /* anel de foco do Bootstrap (rgba do --bs-primary a 25%) — era o cinza
     rgba(100,107,120,.22), do tempo em que o acento era o slate da marca. */
  --ring:0 0 0 3px rgba(13,110,253,.25);
  /* glass — now OPAQUE. backdrop-filter was removed from card/topbar surfaces
     (per-frame blur was the scroll-jank source); opaque fills preserve the look
     without compositing cost. Over the --bg (#f6f7f9) page the old translucent
     whites already read as near-white, so this is visually ~identical. */
  --glass:#ffffff;                 /* was rgba(255,255,255,.64) */
  --glass-2:#f6f7fa;               /* was rgba(255,255,255,.54) — keeps the lower tier */
  --glass-bd:var(--line);          /* white edge only read against blur; neutral hairline now */
  --blur:saturate(150%) blur(18px);/* retained for any remaining frosted accent; off the scroll path */
  /* fully flat: glass sheen AND drop shadow removed. The soft drop lift read as a
     grey halo around every card — stacked, those halos looked like a "visual effect
     between each component." Cards are now delineated by their 1px hairline border
     and the surface ladder alone (no shadow, no glass). */
  --sh-glass:none;

  /* ═══════════════════════════════════════════════════════════════════════════
     APP (bi/) TOKENS — merged here so EVERY token lives in one file.
     Scale/typography/surface/border/shadow + grayscale ramp. No color *meaning*
     here (that's the canonical block above); these are structure + chart chrome.
     ═══════════════════════════════════════════════════════════════════════════ */

  /* grayscale ramp (neutral structure, no valence) */
  --bi-color-white: #ffffff;

  /* typography — single family: Roboto via --sans (loaded in base_fcds.html). */
  --bi-font-display:   var(--sans);
  --bi-font-mono:      var(--mono);
  --bi-fs-hero:    3rem;
  --bi-fs-display: 2rem;
  --bi-fs-metric:  1.5rem;
  --bi-fs-heading: 1rem;
  --bi-fs-body:    0.875rem;
  --bi-fs-label:   0.875rem;
  --bi-fs-caption: 0.875rem;
  /* Dois degraus abaixo do corpo. Não existiam, e a ausência custou caro: 84
     declarações espalhadas por ~20 telas inventaram 19 tamanhos diferentes
     entre 8,96px e 13,76px, cada uma resolvendo sozinha o mesmo problema.
     A escala não estava sendo desrespeitada — estava incompleta.
       compact — célula de matriz/tabela densa, onde 14px estoura a grade.
       micro   — badge, contador, etiqueta de passo. PISO ABSOLUTO do app:
                 nada abaixo de 12px, e só para texto que acompanha outro
                 elemento, nunca para o dado principal de uma tela. */
  --bi-fs-compact: 0.8125rem;
  --bi-fs-micro:   0.75rem;

  --bi-fw-regular:  400;
  --bi-fw-medium:   500;
  --bi-fw-semibold: 600;
  --bi-fw-bold:     700;
  --bi-lh-tight:  1.15;
  --bi-lh-normal: 1.5;
  --bi-lh-loose:  1.7;

  /* spacing */
  --bi-space-3xs: 0.25rem;
  --bi-space-2xs: 0.25rem;
  --bi-space-xs2: 0.5rem;
  --bi-space-xs:  0.25rem;
  --bi-space-sm:  0.5rem;
  --bi-space-md:  1rem;
  --bi-space-lg:  1.5rem;
  --bi-space-xl:  1.5rem;
  --bi-space-2xl: 3rem;
  --bi-space-3xl: 3rem;

  /* radius, borders, shadows — alias dos primitivos --r* (fonte única) */
  --bi-radius-sm:   var(--r-xs);
  --bi-radius-md:   var(--r-sm);
  --bi-radius-lg:   var(--r);
  --bi-radius-full: var(--r-full);

  /* scroll cap — standard max-height for in-card scroll bodies (ranked lists,
     analysis tables) so side-by-side cards read at one height instead of one
     stretching the page. Responsive: floor 320px, ~46vh, ceiling 460px.
     Applied via the .card-scroll utility (custom.css). */
  --bi-scroll-cap: clamp(320px, 46vh, 460px);
  /* table tier (.tbl-scroll, sticky-header tables) and datatable tier
     (.datatable-scroll, full DataTables grids) — larger caps, distinct from the
     compact card-list tier above. Per-instance override stays via
     --bi-table-scroll-max / --bi-dt-scroll-max. */
  --bi-table-scroll-cap: clamp(360px, 48vh, 520px);
  /* dvh-bounded so a short landscape phone caps the grid to the screen (keeping
     the sticky header + internal scroll usable) instead of overflowing it; tall
     desktop screens still get the full 560px. */
  --bi-dt-scroll-cap: min(560px, 82dvh);
  --bi-border-color:        #e6e8ec;
  --bi-border-color-subtle: #eef0f3;
  --bi-border-color-heavy:  #d8dbe1;
  --bi-border:        1px solid var(--bi-border-color);
  --bi-border-subtle: 1px solid var(--bi-border-color-subtle);
  --bi-border-heavy:  1px solid var(--bi-border-color-heavy);
  --bi-shadow-xs: none;
  --bi-shadow-sm: none;
  --bi-shadow-md: none;
  --bi-shadow-lg: none;

  /* surfaces + text */
  --bi-bg-surface: #ffffff;
  --bi-bg-command: #ffffff;
  --bi-bg-elevated: #ffffff;
  --bi-bg-hover:   #f3f4f7;
  --bi-bg-active:  #eceef2;
  --bi-text-primary:   #191c22;
  --bi-text-secondary: #5a6171;
  --bi-text-muted:     #6b7280;
  --bi-text-on-dark:   #F9FAFB;
  --bi-text-on-accent: #FFFFFF;

  /* transitions + z-index */
  --bi-transition-fast:   150ms ease;
  --bi-transition-normal: 250ms ease;
  --bi-transition-slow:   400ms ease;
  --bi-z-dropdown: 100;
  --bi-z-sticky:   200;
  --bi-z-fixed:    300;
  --bi-z-overlay:  400;
  --bi-z-modal:    500;

  /* ===== ESCALA CANÔNICA DE CAMADAS (chrome + modais do app) =====
     A escala --bi-z-* acima é LEGADA/interna (usada por dropdowns e overlays de
     página); não repointar em massa. A escala --z-* abaixo é a canônica de CHROME
     e MODAL, interleavada com as bandas de VENDOR que NÃO dá pra mover:
       Leaflet:   panes 200–700, controls 1000
       Bootstrap: dropdown 1000 · sticky-top 1020 · fixed-top 1030 · offcanvas 1040/1045
                  · modal-backdrop 1050 · modal 1055 · popover 1070 · tooltip 1080 · toast 1090
     Regra: conteúdo de página < 1000; chrome do app (topbar) acima do conteúdo e
     abaixo do band de modais BS; modais do app >= 1100 (acima do BS modal 1055). */
  --z-scrim:       800;    /* backdrop do drawer mobile — dim do conteúdo, não da topbar */
  --z-topbar:      900;    /* topbar sticky + seus popovers (.pop 60 é ordem interna) */
  --z-drawer:      950;    /* .side mobile aberto — cobre a topbar por design */
  --z-modal:      1100;    /* modalboxes / drawers app / mapa fullscreen (acima do BS modal 1055) */
  --z-modal-inner:1150;    /* select2 / controle aninhado DENTRO de um modal app */
  --z-boot:      13000;    /* splash / #page-loading-overlay — acima de tudo, incl. vendor */

  /* skeleton + loader */
  --bi-skeleton-base:  #E5E7EB;
  --bi-skeleton-shine: #F3F4F6;
  --bi-loader-base: #BFC3C8;
  --bi-loader-bg:   transparent;

  /* chart overlays (read by JS via getComputedStyle) */
  --bi-tooltip-bg:        #191c22;
  --bi-tooltip-fg-title:  #E2E8F0;
  --bi-tooltip-fg-body:   #CBD5E1;
  --bi-chart-datalabel:   #5a6171;
  --bi-chart-axis-tick:   #6b7280;
  --bi-chart-bar-border:  #FFFFFF;
  --bi-chart-axis-border: rgba(0, 0, 0, 0.08);

  /* ─────────────────────────────────────────────────────────────────────────
     PAGE PALETTES — per-page design languages kept distinct from the canonical
     system on purpose (warm Comex theme; metas editor). Defined here so EVERY
     token lives in one file; only consumed by their own pages.
     ───────────────────────────────────────────────────────────────────────── */

  /* Comex — Forecast (same warm language, fuller ramp) */
  /* RE-SKINNED to slate FCDS (Batch F): colours/fonts/shadow repointed to the
     canonical palette; the dense forecast radii/transition kept (tight grid). */
  --fc-page-bg:       var(--surface-app);
  --fc-border:        var(--line);
  --fc-urgent-fg:     var(--negative-text);
  --fc-urgent-border: color-mix(in srgb, var(--negative) 18%, var(--surf));
  --fc-soon-border:   color-mix(in srgb, var(--warning) 18%, var(--surf));
  --fc-ok-border:     color-mix(in srgb, var(--positive) 18%, var(--surf));
  --fc-neutral-bg:    var(--surf-2);
  --fc-radius-sm:     2px;
  --fc-radius:        4px;
  --fc-radius-md:     6px;
  --fc-transition:    0.15s ease;
}

/* ==========================================================================
   BOOTSTRAP PALETTE — REMOVIDA (diretiva do usuário)
   Aqui morava o remap da paleta do Bootstrap para o FCDS: --bs-primary,
   --bs-secondary, --bs-success, --bs-info, --bs-warning, --bs-danger (com os
   pares -rgb), --bs-body-color, --bs-body-bg e --bs-border-color, mais o
   .text-bg-primary. Tudo removido: botão, link, fonte, borda e utilitário de cor
   passam a usar os valores DE FÁBRICA do Bootstrap. O visual de marca sobrevive
   só no SHELL (.stm-shell/.app/.topbar/sidebar) e nos componentes FCDS, que têm
   cor própria e não dependem desta paleta. NÃO reintroduzir nenhum destes.

   O único token --bs-* de cor que resta aqui é o `-bg-subtle` de warning, e não
   por causa da marca: o bundle vendorizado é 5.2.3 e não tem a família *-subtle
   do 5.3. Fica com o VALOR DE FÁBRICA do 5.3, para o utilitário portado logo
   abaixo continuar existindo.
   ========================================================================== */
:root{ --bs-warning-bg-subtle:#fff3cd; }
/* Utility do Bootstrap 5.3 que falta no bundle vendorizado (só a de warning é
   usada hoje; as demais entram quando alguém precisar). */
.bg-warning-subtle{ background-color:var(--bs-warning-bg-subtle)!important; }

/* ===== SHELL ===== */
/* ==========================================================================
   Four Cloud Design System — SHELL.
   The app frame only: gradient body · slim glass topbar · hover-expand glass
   sidebar · content surface · mobile drawer + scrim. Ported 1:1 from the tested
   statement mockup (bi/static/bi/demo/statement.css, shell sections).

   Requires custom.css loaded first. Does NOT style filters or page content
   (page-owned) nor the .stm-* components (custom.css).

     §1 reset + display primitives   §2 app frame + sidebar
     §3 topbar   §4 content surface   §5 scrim + responsive
   ========================================================================== */

/* ── §1 RESET + display primitives ───────────────────────────────────────── */
.stm-shell *{box-sizing:border-box}
html,body{margin:0;height:100%;overflow-x:clip}
body.stm-shell{color:var(--ink);font-family:var(--sans);-webkit-font-smoothing:antialiased;font-size:1rem;
  /* plain flat page bg — the three radial glows were the "effect" on the
     background; removed for a flat surface (user directive). */
  background:var(--surface-app)}
.stm-shell .tnum{font-family:var(--mono);font-variant-numeric:tabular-nums;font-feature-settings:'tnum' 1}
/* Button baseline reset — wrapped in :where() so it carries ZERO specificity and
   any component class (.buscar, .fdrop, .filtbtn, .fcds-help, .pill…) overrides
   it. Without :where() this selector (0,2,1) silently clobbered the background of
   every toolbar button, leaving chips/Buscar transparent. */
:where(.stm-shell .app button){font:inherit;color:inherit;background:none;border:none;cursor:pointer}
/* Botões de ação Bootstrap (btn-primary / btn-outline-*) injetados no topbar
   (Salvar, Atualizar…) adotam o formato PÍLULA do FCDS — mesma altura e raio dos
   controles .fdrop/.tb-btn — para o topbar ler como UMA linha consistente.
   .btn-link (ícone de ajuda) fica de fora. Só FORMATO — a cor é a do Bootstrap de
   fábrica (o remap de cor de botão foi removido; ver a seção acima). */
.stm-shell .topbar .btn:not(.btn-link){
  height: 2rem;border-radius:var(--bs-border-radius-pill);padding:0 1rem;
  display:inline-flex;align-items:center;gap:0.25rem;
  font-size:0.875rem;font-weight:500;line-height:1}
.stm-shell .metric{font-weight:700;font-variant-numeric:tabular-nums}
.stm-shell .metric--sig{font-size:var(--metric-sig);letter-spacing:-.03em;margin:0.5rem 0 0.25rem}

/* ── §2 APP FRAME + SIDEBAR ──────────────────────────────────────────────── */
.app{min-height:100vh}
/* near-opaque so animating width stays smooth (backdrop-filter + width = jank) */
.side{position:fixed;top:52px;left:0;height:calc(100vh - 52px);width: 4rem;z-index:30;overflow:hidden; /* < --z-topbar: sidebar desktop fica sob a topbar */
  display:flex;flex-direction:column;border-right:1px solid var(--line);
  background:var(--surf);will-change:width;
  transition:width .26s cubic-bezier(.22,1,.36,1),box-shadow .26s cubic-bezier(.22,1,.36,1)}
.side:hover,.side:focus-within{width: 14.75rem}
.main{margin-left:3rem;min-width:0;min-height:calc(100vh - 52px);
  will-change:margin-left;transition:margin-left .26s cubic-bezier(.22,1,.36,1)}
body.pinned .side{width: 14.75rem;box-shadow:none}
body.pinned .main{margin-left:3rem}
/* collapsed rail (desktop ≥761): true icon-only — labels/headers/chevrons/subs
   LEAVE the layout so nothing is left half-cropped. */
.side .user b,.side .nav a span,.side .navgrp span,.side .nav__g,.side .user div{white-space:nowrap}
@media(min-width:768px){
  body:not(.pinned) .side:not(:hover):not(:focus-within) .nav a,
  body:not(.pinned) .side:not(:hover):not(:focus-within) .navgrp{justify-content:center;gap:0;padding-left:0;padding-right:0}
  body:not(.pinned) .side:not(:hover):not(:focus-within) .nav a span,
  body:not(.pinned) .side:not(:hover):not(:focus-within) .navgrp span,
  body:not(.pinned) .side:not(:hover):not(:focus-within) .nav a .cnt,
  body:not(.pinned) .side:not(:hover):not(:focus-within) .navgrp .chev,
  body:not(.pinned) .side:not(:hover):not(:focus-within) .nav__g,
  body:not(.pinned) .side:not(:hover):not(:focus-within) .user div{display:none}
  /* Recolhida, a barra tem 64px: o Sair espremia o avatar contra a borda e o
     deixava oval. Sai o Sair (ele volta assim que a barra abre) e o avatar
     fica redondo, sozinho e centrado — é ele que abre "Minha conta". */
  body:not(.pinned) .side:not(:hover):not(:focus-within) .user form{display:none}
  body:not(.pinned) .side:not(:hover):not(:focus-within) .user__eu{
    flex:0 0 auto;justify-content:center}
  body:not(.pinned) .side:not(:hover):not(:focus-within) .user .av{flex:0 0 auto}
  body:not(.pinned) .side:not(:hover):not(:focus-within) .user .av__ini{display:block}
  body:not(.pinned) .side:not(:hover):not(:focus-within) .user .av__cfg{display:none}
  body:not(.pinned) .side:not(:hover):not(:focus-within) .subnav{max-height:0!important}
  body:not(.pinned) .side:not(:hover):not(:focus-within) .side__foot .user{justify-content:center;padding:0.25rem 0}
}
/* display:flex+column is explicit so it wins over the legacy styles.css `.nav`
   (SB-Admin/Bootstrap) rule `display:flex;flex-wrap:wrap`, which otherwise lays
   the items out as a wrapping row (collapsed rail → two icons per line). */
/* display:block neutralises the legacy styles.css `.nav` (SB-Admin/Bootstrap)
   `display:flex;flex-wrap:wrap`, which otherwise lays the items out as a wrapping
   row (collapsed rail → two icons per line). Block flow keeps them stacked AND
   lets the nav scroll naturally — a flex column would instead shrink the items to
   fit and clip the lower groups. min-height:0 lets this flex child (of .side)
   shrink below its content so overflow-y:auto can scroll. */
/* Scoped to the sidebar (#nav) — a bare `.nav{display:block}` leaked to every
   Bootstrap `.nav-tabs` (modals), overriding `.nav{display:flex}` and stacking
   tabs vertically. Sidebar keeps block flow; modal tabs get Bootstrap's row. */
#nav{flex:1;min-height:0;display:block;overflow-y:auto;overflow-x:hidden;padding:1rem 0.5rem 0.5rem}
.nav__g{font-size:0.875rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3);
  padding:1rem 0.5rem 0.25rem}
.nav a{display:flex;align-items:center;gap:0.5rem;padding:0.5rem 0.5rem;border-radius:var(--r-sm);color:var(--ink-2);
  font-weight:500;text-decoration:none;font-size:0.875rem;margin-bottom:0;transition:background .12s,color .12s}
.nav a svg{width: 1.0625rem;height: 1.0625rem;color:var(--ink-3);flex:0 0 auto}
.nav a i{width: 1.0625rem;font-size:1rem;color:var(--ink-3);flex:0 0 auto;text-align:center}
.nav a:hover{background:var(--surf-2);color:var(--ink)}
.nav a.on,.nav a.active{background:var(--shell-acc-soft);color:var(--shell-acc-ink);font-weight:600;position:relative}
.nav a.on svg,.nav a.active svg,.nav a.on i,.nav a.active i{color:var(--shell-acc)}
.nav a.on::before,.nav a.active::before{content:"";position:absolute;left:-12px;top:7px;bottom:7px;width: 0.1875rem;border-radius: 0 var(--bs-border-radius-sm) var(--bs-border-radius-sm) 0;background:var(--shell-acc)}
.nav a .cnt{margin-left:auto;font-family:var(--mono);font-size:0.875rem;color:var(--ink-3);background:var(--surf-2);
  border-radius:var(--bs-border-radius-pill);padding:0 0.5rem}
.nav a.on .cnt{background:var(--surf);color:var(--shell-acc-ink)}
.navgrp{display:flex;align-items:center;gap:0.5rem;width:100%;padding:0.5rem 0.5rem;border-radius:var(--r-sm);
  color:var(--ink-2);font-weight:500;font-size:0.875rem;text-align:left;margin-bottom:0;transition:background .12s,color .12s}
.navgrp svg.gi,.navgrp i.gi{width: 1.0625rem;height: 1.0625rem;font-size:1rem;color:var(--ink-3);flex:0 0 auto;text-align:center}
.navgrp:hover{background:var(--surf-2);color:var(--ink)}
.navgrp.has-on{color:var(--ink)} .navgrp.has-on svg.gi,.navgrp.has-on i.gi{color:var(--shell-acc)}
.navgrp .chev{width: 0.8125rem;height: 0.8125rem;font-size:0.875rem;color:var(--ink-3);margin-left:auto;transition:transform .18s}
.navgrp.open .chev{transform:rotate(180deg)}
.subnav{overflow:hidden;max-height:0;transition:max-height .24s ease}
.subnav a{padding-left:1.5rem;font-size:0.875rem;color:var(--ink-3)}
.subnav a i{width: 1rem;font-size:0.875rem;color:var(--ink-4);flex:0 0 auto;text-align:center}
.subnav a:hover i{color:var(--ink-3)}
.subnav a.on,.subnav a.active{color:var(--shell-acc-ink);font-weight:600}
.subnav a.on i,.subnav a.active i{color:var(--shell-acc)}
.subnav a.on::before,.subnav a.active::before{display:none}
.side__foot{border-top:1px solid var(--line-2);padding:0.5rem}
.user{display:flex;align-items:center;gap:0.5rem;padding:0.25rem;border-radius:var(--r-sm)}
.user:hover{background:var(--surf-2)}
.user .av{width: 1.875rem;height: 1.875rem;border-radius:50%;background:var(--shell-acc-soft);color:var(--shell-acc-ink);
  display:grid;place-items:center;font-size:0.875rem;font-weight:600;border:var(--bs-border-width) solid var(--shell-acc-line)}
.user b{font-size:0.875rem;font-weight:600;display:block}.user small{color:var(--ink-3);font-size:0.875rem}
/* O bloco do usuário virou BOTÃO (abre "Minha conta"): mesma aparência de
   antes, com o alvo e o foco que um botão precisa ter. Com a barra recolhida
   sobra só o avatar — a regra do rail esconde o `div` do nome. */
.user__eu{display:flex;align-items:center;gap:0.5rem;flex:1 1 auto;min-width:0;
  background:none;border:0;padding:0;text-align:left;color:inherit;cursor:pointer}
.user__eu:focus-visible{outline:2px solid var(--shell-acc-ink);outline-offset:2px;border-radius:var(--r-sm)}
.user__id{min-width:0}
/* Aberta a barra, o círculo vira engrenagem: o nome já está escrito ao lado,
   então o ícone pode dizer o que o clique faz (abrir a conta) em vez de
   repetir as iniciais. Recolhida, volta a ser o avatar. */
.user .av__ini{display:none}
.user .av__cfg{font-size: var(--bi-fs-compact)}
.user__id b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Rótulo miúdo do painel da conta — o mesmo tom dos rótulos do shell. */
.conta-rotulo{font-size: var(--bi-fs-compact);font-weight:600;letter-spacing:.08em;
  text-transform:uppercase;color:var(--ink-3)}
.user form{margin:0;margin-left:auto;flex:0 0 auto}
.user .logout{color:var(--ink-3);display:grid;place-items:center;width: 1.75rem;height: 1.75rem;
  border-radius:var(--r-xs);transition:background .12s,color .12s}
.user .logout:hover{background:var(--negative-subtle);color:var(--negative-text)}
.user .logout i,.user .logout svg{width: 0.9375rem;height: 0.9375rem;font-size:1rem}

/* ── §3 TOPBAR (slim glass, sticky) ──────────────────────────────────────── */
/* opaque (was rgba(.7)+backdrop-filter): a sticky element re-blurs its backdrop
   on every scroll frame as content passes behind it — opaque kills that cost. */
.topbar{height: 3.25rem;display:flex;align-items:center;gap:0.5rem;padding:0 1rem;
  background:var(--surf);
  border-bottom:1px solid var(--line);position:sticky;top:0;z-index:var(--z-topbar)}
.topbar .logo{flex:0 0 auto;display:flex;color:var(--ink)}
.topbar .logo svg{width: 1.4375rem;height: 1.4375rem;display:block}
.topbar .menu{display:grid;place-items:center;width: 2.125rem;height: 2.125rem;margin-left:-0.25rem;border-radius:var(--r-sm);
  color:var(--ink-2);flex:0 0 auto;transition:background .14s,color .14s}
.topbar .menu svg,.topbar .menu i{width: 1.125rem;height: 1.125rem;font-size:1rem}
.topbar .menu:hover{background:rgba(255,255,255,.55);color:var(--ink)}
.topbar .menu[aria-pressed="true"]{color:var(--shell-acc-ink);background:var(--shell-acc-soft)}
.crumb{display:flex;align-items:baseline;gap:0.5rem}
.crumb b{font-size:1rem;font-weight:600;letter-spacing:-.01em}
.crumb span{font-size:0.875rem;color:var(--ink-3)}
.topbar .sp{flex:1}

/* ── §4 CONTENT SURFACE ──────────────────────────────────────────────────── */
.content{padding:var(--content-pad-y) var(--content-pad-x) var(--content-pad-b);min-width:0}
/* Grade única esticada (`biUtils.esticarGradeUnica`): o recuo de baixo do
   `.content` (36px) e o do `.page` (24px) caem ABAIXO da paginação, onde não
   separam nada de nada — viram 60px de faixa cinza entre o card e o fim da
   janela, e saem da altura que a lista poderia ocupar. Enquanto a classe está
   posta, quem dá o respiro do rodapé é o próprio cálculo da grade. O
   `!important` só empata com o `!important` de `.page`. */
.content.grade-esticada{padding-bottom:0}
.content.grade-esticada > .page{padding-bottom:0 !important}

/* ── §5 SCRIM + RESPONSIVE ───────────────────────────────────────────────── */
.scrim{position:fixed;inset:52px 0 0 0;background:rgba(22,24,32,.42);opacity:0;pointer-events:none;
  transition:opacity .22s;z-index:var(--z-scrim)}
body.navopen .scrim,body.filtopen .scrim{opacity:1;pointer-events:auto}

/* Mobile chrome: narrow portrait (≤760px) OR short landscape (≤540px tall — a
   landscape phone is ~844px wide so it would otherwise miss the width breakpoint and
   render the desktop rail). Both get the off-canvas drawer + full-width content. */
@media(max-width:767.98px),(max-height:540px){
  .side{transform:translateX(-100%);width: 15rem;z-index:var(--z-drawer);border-right:1px solid var(--line);
    transition:transform .26s cubic-bezier(.22,1,.36,1)}
  .side:hover,.side:focus-within{width: 15rem}
  body.navopen .side{transform:none}
  .main,body.pinned .main{margin-left:0}
  .side .nav a span,.side .nav a .cnt,.side .nav__g,.side .user div,.side .navgrp span{opacity:1!important;display:initial}
  /* iOS notch / home-indicator (landscape especially): viewport-fit=cover lets content
     use the whole screen, env() insets keep it off the camera + home bar. max() so a
     non-notched device (env=0) keeps the normal value. */
  /* Goteira lateral própria da superfície: o card não sai mais da caixa por conta
     própria (a antiga quebra de 100vw foi removida), então é o .content que dá o
     respiro das bordas — e o env() mantém tudo fora do notch em paisagem. */
  .content{padding-block:0.5rem max(1.5rem, env(safe-area-inset-bottom));
    padding-inline:max(0.5rem, env(safe-area-inset-left)) max(0.5rem, env(safe-area-inset-right))}
  .side{padding-left:env(safe-area-inset-left)}
  /* topbar: reclaim width at 390px — the breadcrumb carries identity AND is the sole
     drawer trigger on mobile, so drop the redundant logo and remove the hamburger;
     let the breadcrumb ellipsize instead of shoving the filter button */
  .topbar{padding-left:max(0.5rem, env(safe-area-inset-left));padding-right:max(0.5rem, env(safe-area-inset-right));gap:0.5rem}
  .topbar .logo{display:none}
  .topbar .menu{display:none}
  .crumb{min-width:0;cursor:pointer;display:flex;align-items:center;gap:0.5rem;
    margin-left:-0.25rem;padding:0.25rem 0.5rem;border-radius:var(--bs-border-radius-lg);-webkit-tap-highlight-color:transparent}
  .crumb::before{content:"\2630";font-size:1.125rem;line-height:1;color:var(--ink-2);flex:0 0 auto}
  .crumb:active{background:rgba(20,24,32,.06)}
  .crumb b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:42vw;font-size:1rem}
}

/* ===== COMPONENTS ===== */
/* ==========================================================================
   Four Cloud Design System — COMPONENTS.
   The composable card/metric library. Ported 1:1 from the design source
   (bi/static/bi/demo/statement.css component sections). Pages compose FROM
   these — never restyle ad hoc. Depends on the TOKENS + SHELL sections above
   (.metric primitives).

     §1 grid + card/glass   §2 hero+ring   §3 kpi spark tiles
     §4 margin flow cascade  §5 cost doughnut   §6 signals   §7 units ABC table
   ========================================================================== */

/* ── §1 GRID + CARD/GLASS ────────────────────────────────────────────────── */
.grid{display:grid;grid-template-columns:repeat(12,1fr);gap:var(--gap)}
/* Grade FLUIDA — o nº de colunas segue a largura, sem breakpoint escrito à mão.
   A `.grid` de 12 colunas exige que cada filho declare seu span, então o layout
   fica congelado: 2 cartões lado a lado continuam 2 num monitor de 27", só mais
   largos. Aqui os cartões vão encaixando conforme cabem — 4 numa tela larga, 3
   ao estreitar, 2 no notebook, 1 no celular — e cada um tem uma largura MÍNIMA
   digna em vez de uma fração fixa da tela.
   O `--min-card` é o botão de calibragem: é ele que decide em que largura o
   layout troca de nº de colunas. Uma tela pode sobrescrevê-lo inline. */
.grid-fluido{
  display:grid;
  grid-template-columns:repeat(auto-fit, minmax(min(var(--min-card, 34rem), 100%), 1fr));
  gap:var(--gap);
  align-items:stretch;
}
/* Cada cartão tem a altura que o SEU conteúdo pede — não a do vizinho mais alto.
   Com `stretch` (o padrão), um cartão de gráfico numa faixa de três forçava os
   dois de texto, de ~120px de conteúdo, a herdarem a caixa dele: era exatamente
   o vão morto que motivou o redesenho. `start` desiste do rodapé alinhado e
   entrega a altura de volta. */
.grid-fluido{ align-items:start; }
/* Faixa em que os cartões DEVEM alinhar rodapé — quando uma das colunas é uma
   pilha de cartões, `stretch` é o que faz a pilha ocupar a altura da coluna e o
   `flex-fill` de cada cartão dividir esse espaço. Sem isto a pilha encolhe para
   o conteúdo e a coluna fica curta ao lado dos gráficos. */
.grid-fluido.align-items-stretch{ align-items:stretch; }

/* Ranking como cartão de faixa: acompanha a altura do gráfico ao lado e rola por
   dentro. A lista é posicionada em ABSOLUTO de propósito — assim ela não
   contribui altura nenhuma para o grid, e quem dita a altura da faixa passa a
   ser o cartão do gráfico. Sem isto, os 14 portadores ditavam a altura e sobrava
   ~650px de vão embaixo do gráfico; capar com `max-height` em rem resolveria
   pela metade, porque o número seria um chute desacoplado da altura real do
   gráfico (que o JS deriva do nº de categorias). */
#cr-board{ position:relative; overflow:hidden; }
#cr-board > .cr-board{ position:absolute; inset:0; overflow-y:auto; }
/* surface recipe — shared by every .card, .tile, and any .glass element.
   backdrop-filter removed: it forced a per-frame blur pass behind every one of
   ~39 cards during scroll (the dominant scroll-jank source). --glass is opaque
   now, so the frosted look is preserved without the compositing cost. */
.glass{
  border:var(--bs-border-width) solid var(--line);border-radius:var(--r);box-shadow:var(--sh-glass)}
/* STANDARDIZED CARD (FCDS canonical) — solid surface, neutral hairline, no shadow.
   Glass is retired: this references the semantic tokens directly (--surf/--line) instead
   of the legacy --glass* aliases (same resolved values, no "glass" naming). Layout props
   (flex column / position) are declared here so the card no longer silently borrows them
   from Bootstrap's .card — load order is now irrelevant. Body pad 8/16/16; header→body
   rhythm via .card-hd margin-bottom (8px). .cardbox (main.css) shares this visual standard. */
.card{
  display:flex;flex-direction:column;position:relative;
  background:var(--surf);border:var(--bs-border-width) solid var(--line);border-radius:var(--r);box-shadow:none;
  padding:var(--bi-space-sm,0.5rem) var(--bi-space-md,1rem) var(--bi-space-md,1rem)}
/* Cartão no modelo estruturado do Bootstrap (.card > .card-header/.card-body): quem
   dá o padding é o filho, então o .card zera o seu — senão o conteúdo recebe o
   padding duas vezes (16px do .card + 16px do .card-body = 32px de recuo). */
.card:has(> .card-body), .card:has(> .card-header){ padding:0; }
.lab{font-size:0.875rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
.card-hd{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:var(--bi-space-sm,0.5rem)}
.card-hd .n{font-size:0.875rem;color:var(--ink-3)}
.card.empty{display:grid;place-items:center;min-height: 7.5rem;color:var(--ink-3);font-size:0.875rem}
/* scroll-capped card body: ranked lists / analysis tables scroll inside the card
   at a shared max-height (--bi-scroll-cap) so neighboring cards stay equal-height
   instead of one growing unbounded. min-height:0 lets it shrink inside flex/grid. */
.card-scroll{max-height:var(--bi-scroll-cap);overflow-y:auto;min-height:0}
/* Left-accent stripe, dynamic per-instance color (drill-panel elements
   set --kpi-tile-accent inline, same convention as .kpi-tile). Not the
   Bootstrap .border-start.border-<cor> pair: the accent hue is chosen at
   runtime by JS (warning/positive per drill level), and Bootstrap ships no
   static border-color utility that maps to a CSS variable — a utility combo
   can't express it, so a one-prop helper reads the same --kpi-tile-accent. */
.card-accent-start{border-left:3px solid var(--kpi-tile-accent, var(--acc))}

/* skeleton loading */
/* .skb mirrors the canonical .skeleton recipe (B9) — same base/shine tokens, radius
   and timing — but stays self-contained (own keyframes) so it works on pages that load
   fcds.* without bi/main.css (e.g. tracking-comex). */
/* .skb + @keyframes shimmer removidos — skeleton unificado no Bootstrap .placeholder (utils.js). */

/* ── §2 HERO + RING ──────────────────────────────────────────────────────── */
.delta{display:inline-flex;align-items:center;gap:0.25rem;height: 1.625rem;padding:0 0.5rem;border-radius:var(--bs-border-radius-lg);
  font-family:var(--mono);font-size:0.875rem;font-weight:600}
.delta.pos{background:rgba(22,121,74,.10);color:var(--positive-text)}
.delta.neg{background:var(--negative-subtle);color:var(--negative-text)}
.ring{flex:0 0 auto;width:var(--ring-size);height:var(--ring-size);position:relative}
.ring canvas{position:absolute;inset:0}
.ring__lbl{position:absolute;inset:0;display:grid;place-items:center;text-align:center}
.ring__v{font-size:1.125rem;font-weight:700;color:var(--ink)}
/* chart-internal: <12px justified (ring overflow) — batch5 */
.ring__c{font-size:0.875rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);font-weight:600}

/* ── §3 KPI SPARK TILES ──────────────────────────────────────────────────── */
.kpi{grid-column:span 7;display:grid;grid-template-columns:repeat(3,1fr);gap:var(--gap)}
/* unified card padding (Batch6 Agent B): tile body pad 8/16/16 (was 12/14/10) */
.tile{background:var(--glass-2);padding:var(--bi-space-sm,0.5rem) var(--bi-space-md,1rem) var(--bi-space-md,1rem);
  display:flex;flex-direction:column;position:relative;overflow:hidden}
.tile .lab{font-size:0.875rem}
.md{font-family:var(--mono);font-size:0.875rem;font-weight:600;white-space:nowrap}.md.pos{color:var(--positive-text)}.md.neg{color:var(--negative-text)}
/* margin-left, não um espaço no markup: os dois spans são irmãos colados na
   string de HTML (saía "−37,1%vs mês ant.") e um espaço solto ali se perde na
   primeira reformatação do template. */
.md__ref{font-family:var(--sans);font-size:0.875rem;font-weight:500;color:var(--ink-3);white-space:nowrap;
  margin-left:0.25rem}
/* full-bleed area band at the card's bottom edge (negative margins cancel the tile's x/bottom pad) */
.spark{display:block;position:relative;width:auto;height:var(--spark-h);
  margin:var(--bi-space-sm,0.5rem) calc(-1*var(--bi-space-md,1rem)) calc(-1*var(--bi-space-md,1rem))}
.spark canvas{display:block}

/* ── §4 MARGIN FLOW CASCADE ──────────────────────────────────────────────── */
.flow{grid-column:span 8;display:flex;flex-direction:column}
.flow-cv{position:relative;flex:1;min-height:var(--flow-min);margin-top:var(--bi-space-xs2,0.25rem)}

/* ── §6 OPERATIONAL SIGNALS ──────────────────────────────────────────────── */
/* No left-stripe accent (banned >1px colored border): the cards use the standard
   .card hairline. Direction on Inadimplência is carried by the red value + label,
   not a decorative rule. The signals stack in a span-4 column beside the cascade. */
.sigcol{grid-column:span 4;display:flex;flex-direction:column;gap:var(--gap)}
.sigcol .sig{flex:1;display:flex;flex-direction:column}
.sig__v .u{font-size:1rem;color:var(--ink-3);font-weight:500;margin-left:0.25rem}
.sig.neg .sig__v{color:var(--negative-text)}
/* warning glyph = non-colour backup for the negative (inadimplência) card */
.sig__mark{font-size:.62em;vertical-align:.12em;margin-right:0}
.sig__s{font-size:0.875rem;color:var(--ink-2);margin-top:auto}
/* pin the detail link flush-left across all three signal cards (consistency) */
.sigcol .sig .fcds-siglink{align-self:flex-start}

/* ── §8 FILTERS — topbar chips · glass popovers · month picker · sheet ─────── */
/* Reusable FCDS filter primitives (ported from the statement mockup). A page
   houses its live filter controls inside these; chip labels reflect state. */
.filters{display:flex;align-items:center;gap:var(--bi-space-sm,0.5rem);min-width:0}
.vr{width:1px;height: 1.25rem;background:var(--line);flex:0 0 auto}
.fdwrap{position:relative;flex:0 0 auto}
.fdrop{display:inline-flex;align-items:center;gap:0.5rem;height: 2rem;padding:0 0.5rem;border:var(--bs-border-width) solid var(--line);
  border-radius:var(--bs-border-radius-pill);background:var(--surf-2);font-size:0.875rem;font-weight:500;color:var(--ink-2);transition:all .12s;white-space:nowrap}
.fdrop:hover,.fdrop.open{background:var(--surf);border-color:var(--line-3)}
.fdrop.on{background:var(--acc-soft);border-color:var(--acc-line);color:var(--acc-ink)}
.fdrop b{color:var(--ink);font-weight:600;max-width: 7.75rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fdrop.on b{color:var(--acc-ink)}
.fdrop svg,.fdrop i{width: 0.8125rem;height: 0.8125rem;font-size:0.875rem;color:var(--ink-3);transition:transform .16s}
.fdrop.open .chev{transform:rotate(180deg)}
/* período/date control — unificado ao formato pílula do .fdrop (mesma altura,
   padding, gap e raio 999px) para o topbar ler como UMA linha consistente. */
.tb-btn{display:flex;align-items:center;gap:0.5rem;height: 2rem;padding:0 0.5rem;border:var(--bs-border-width) solid var(--line);
  border-radius:var(--bs-border-radius-pill);background:var(--surf-2);font-size:0.875rem;font-weight:500;color:var(--ink-2);transition:all .14s;
  white-space:nowrap;flex:0 0 auto}
.tb-btn:hover,.tb-btn.open{background:var(--surf);border-color:var(--line-3)}
.tb-btn svg,.tb-btn i{width: 0.8125rem;height: 0.8125rem;font-size:0.875rem;color:var(--ink-3)}
.tb-btn .chev{transition:transform .16s}
.tb-btn.open .chev{transform:rotate(180deg)}
.tb-btn b{color:var(--ink);font-weight:600}
/* glass popover */
.pop{position:absolute;top:calc(100% + 8px);left:0;z-index:60;min-width: 14.75rem;max-height:min(70vh,520px);overflow:auto;
  background:var(--surf);border:var(--bs-border-width) solid var(--line);border-radius:var(--r-sm);box-shadow:var(--sh2);padding:0.25rem}
.pop[hidden]{display:none}
.pop--right{left:auto;right:0}
.pop__hd{display:flex;align-items:center;justify-content:space-between;padding:var(--bi-space-2xs,0.25rem) var(--bi-space-sm,0.5rem) var(--bi-space-sm,0.5rem);
  font-size:0.875rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3)}
.pop__hd button{font-size:0.875rem;font-weight:500;color:var(--ink-2);text-transform:none;letter-spacing:0;
  text-decoration:underline;text-underline-offset:2px;text-decoration-color:var(--line-3);background:none;border:0;cursor:pointer}
.pop__hd button:hover{color:var(--negative-text);text-decoration-color:currentColor}
/* Cabeçalho com DUAS ações (todos | limpar): o rótulo empurra as duas para a
   direita e elas ficam lado a lado. Só com `space-between` cada ação ia para uma
   ponta e "todos" lia como se pertencesse ao rótulo. */
.pop__hd{gap:var(--bi-space-sm,0.5rem)}
.pop__hd > span:first-child{margin-right:auto}
/* Vermelho no hover é de destruição — fica só no "limpar". "todos" é aditivo. */
.pop__hd button[data-allpop]:hover{color:var(--ink)}
.short{padding:0.25rem 0.5rem;border-radius:var(--bs-border-radius-pill);border:var(--bs-border-width) solid var(--line);background:var(--surf-2);
  font-size:0.875rem;font-weight:600;color:var(--ink-2);cursor:pointer}
.short:hover{background:var(--surf-3);color:var(--ink)}
.mcell{padding:0.5rem 0;border-radius:var(--r-xs);border:var(--bs-border-width) solid var(--line);background:var(--surf);
  font-size:0.875rem;font-weight:500;color:var(--ink-2);text-align:center;cursor:pointer}
.mcell:hover{background:var(--surf-2);border-color:var(--acc-line)}
.mcell.on{background:var(--acc);border-color:var(--acc);color:var(--bi-text-on-accent);font-weight:600}
.popftog{border-top:var(--bs-border-width) solid var(--line-2);margin-top:0.25rem;padding:0.5rem 0.5rem 0}
/* option rows (used for segmento/sub/empresa lists) */
.optrow{display:flex;align-items:center;gap:0.5rem;width:100%;padding:0.5rem 0.5rem;border-radius:var(--r-xs);
  font-size:0.875rem;color:var(--ink-2);text-align:left;cursor:pointer;background:none;border:0}
.optrow:hover{background:var(--surf-2)}
.optrow .ck{width: 1.0625rem;height: 1.0625rem;border-radius:var(--bs-border-radius);border:1.5px solid var(--line-3);flex:0 0 auto;
  display:grid;place-items:center;color:var(--bi-text-on-accent);transition:all .12s}
.optrow .ck svg,.optrow .ck i{width: 0.6875rem;height: 0.6875rem;font-size:0.875rem;opacity:0}
.optrow.on .ck{background:var(--acc);border-color:var(--acc)}
.optrow.on .ck svg,.optrow.on .ck i{opacity:1}
.optrow .nm{flex:1;font-weight:500;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* buscar + funnel */
/* stale-results indicator — appears only when a filter change is staged
   (body.fcds-pending). Pairs with the dimmed results region so "os números na
   tela não refletem mais os filtros; clique em Buscar" is unambiguous. Âmbar de
   atenção (warning channel): os dados na tela estão desatualizados — par com o
   verde de ação do botão Buscar. Texto usa --warning-text (#f59e0b) — âmbar vivo,
   saturação priorizada sobre AA (~2.1:1 em texto pequeno). */
.fcds-stale{display:none;align-items:center;gap:0.25rem;flex:0 0 auto;height: 2rem;padding:0 0.5rem;
  border-radius:var(--bs-border-radius-pill);background:var(--warning-subtle);
  border:var(--bs-border-width) solid color-mix(in srgb, var(--warning) 38%, var(--surf));
  color:var(--warning-text);font-size:0.875rem;font-weight:600;white-space:nowrap}
.fcds-stale svg,.fcds-stale i{width: 0.875rem;height: 0.875rem;font-size:0.875rem;flex:0 0 auto}
body.fcds-pending .fcds-stale{display:inline-flex}
/* tight topbars: drop to icon-only (tooltip carries the text) so it never
   crowds the período picker / Buscar */
@media(max-width:1399.98px){.fcds-stale{padding:0 0.5rem}.fcds-stale__t{display:none}}
/* dim the (now-stale) results while a change is staged; topbar/filters stay live */
body.fcds-pending main .grid{opacity:.5;pointer-events:none;transition:opacity .18s ease-out}
@media(prefers-reduced-motion:reduce){body.fcds-pending main .grid{transition:none}}

.buscar{display:none;align-items:center;gap:0.25rem;height: 2rem;padding:0 1rem;border:var(--bs-border-width) solid var(--brand);
  border-radius:var(--bs-border-radius-pill);background:var(--brand);color:var(--bi-text-on-accent);font-size:0.875rem;font-weight:600;flex:0 0 auto;box-shadow:var(--sh1);cursor:pointer}
.buscar svg,.buscar i{width: 0.875rem;height: 0.875rem;font-size:0.875rem}
.buscar:hover{background:var(--brand-strong);border-color:var(--brand-strong)}
/* pending = uma mudança de filtro backend espera aplicar (período/empresa). O slate
   de comando não chamava atenção (lia como botão desabilitado), então o CTA de
   atualização ganha verde de ação ("clique para atualizar") + pulso, contrastando
   com o pill âmbar/neutro "Data alterada". Pulsa até o clique. */
.buscar.pending{display:inline-flex;background:var(--positive-text);border-color:var(--positive-text);animation:buscarpulse 1.8s ease-in-out infinite}
.buscar.pending:hover{background:color-mix(in srgb, var(--positive-text) 86%, var(--ink));border-color:color-mix(in srgb, var(--positive-text) 86%, var(--ink))}
@keyframes buscarpulse{0%,100%{box-shadow:0 0 0 0 rgba(21,128,61,0)}50%{box-shadow:0 0 0 4px rgba(21,128,61,.30)}}
/* mobile sheet Buscar segue a mesma semântica (verde de ação) quando há pendência */
body.fcds-pending .fbuscar{background:var(--positive-text);border-color:var(--positive-text)}
body.fcds-pending .fbuscar:hover{background:color-mix(in srgb, var(--positive-text) 86%, var(--ink));border-color:color-mix(in srgb, var(--positive-text) 86%, var(--ink))}
.fbuscar{display:inline-flex;align-items:center;justify-content:center;gap:0.5rem;height: 2.125rem;padding:0 1rem;
  border-radius:var(--bs-border-radius-pill);background:var(--brand);color:var(--bi-text-on-accent);font-size:0.875rem;font-weight:600;border:var(--bs-border-width) solid var(--brand);cursor:pointer}
.fbuscar:hover{background:var(--brand-strong);border-color:var(--brand-strong)}
.filtbtn{display:none;align-items:center;gap:0.5rem;height: 2.125rem;padding:0 1rem;border:var(--bs-border-width) solid var(--line);
  border-radius:var(--bs-border-radius-pill);background:var(--surf);font-size:0.875rem;font-weight:500;color:var(--ink-2);flex:0 0 auto;cursor:pointer}
.filtbtn:hover{background:var(--surf-2)} .filtbtn svg,.filtbtn i{width: 0.9375rem;height: 0.9375rem;font-size:1rem;color:var(--ink-3)}
.filtbtn__n{font-family:var(--mono);font-size:0.875rem;font-weight:600;color:var(--bi-text-on-accent);background:var(--acc);border-radius:var(--bs-border-radius-pill);padding:0 0.25rem}
.sheet-only{display:none}
/* Modo backend-instantâneo (opt-in, ex.: faturamento): período/empresa aplicam
   sozinhos, então os gatilhos de Buscar não existem para o usuário. */
body.bi-backend-instant .btn-buscar-trigger,
body.bi-backend-instant #fcds-buscar,
body.bi-backend-instant .sheet-only .fbuscar{display:none!important}

/* ≤1340: collapse inline filters into a sheet behind the Filtros button */
@media(max-width:1200px){
  .topbar>.vr{display:none}
  .filtbtn{display:inline-flex}
  .filters{position:absolute;top:54px;right:14px;width: 18.75rem;flex-direction:column;align-items:stretch;gap:0.5rem;
    padding:0.5rem;background:var(--surf);border:var(--bs-border-width) solid var(--line);border-radius:var(--r-sm);box-shadow:var(--sh2);
    z-index:60;display:none}
  body.filtopen .filters{display:flex}
  .filters .fdwrap{width:100%}
  .filters .fdrop,.filters .tb-btn{width:100%;justify-content:space-between;border:var(--bs-border-width) solid var(--line);background:var(--surf-2)}
  .filters .sheet-only{display:flex;gap:0.5rem;margin-top:0}
  .filters .sheet-only .fbuscar{flex:1}
  .filters .pop{position:static;box-shadow:none;border:none;padding:0.25rem 0 0;min-width:0;max-height:none;background:transparent}
}
@media(max-width:768px){
  .buscar{display:none!important}
  /* collapse the Filtros pill to icon-only (count badge still shows) + keep the
     sheet inside the viewport on narrow phones */
  .filtbtn{padding:0 0.5rem}
  .filtbtn span:not(.filtbtn__n){display:none}
  .filters{left:8px;right:8px;width:auto}
}

/* ── §9 KPI BAND — compact, data-rich (Receita · ritmo gauge · metrics · breakdown) ── */
/* The KPI band is ONE white card — the same surface recipe as every .card/.glass:
   white background, hairline border, rounded corners (from .glass). Cells are
   sections WITHIN that card, divided by inset hairlines (below), NOT tiles floating
   on a grey backing shown through 1px gaps. The old grey backing was the band's only
   deviation from the component vocabulary and the sole reason a third colour appeared
   at the rounded corners; converging to white makes the band consistent with all
   components and removes the corner artifact by construction (white-on-white clips
   cleanly, exactly like a normal card). */

/* Fixed-count variants for scalar bands (ported from legacy .kpi-band--Ncol):
   hero cell wide, the rest equal. Declared BEFORE the responsive @media blocks at
   the end of §9 so small-viewport stacking still overrides them. */

/* movimentacao drops the "Em Trânsito" cell outside the current month → 6 cols */

/* EXCEPTION (Batch6 Agent B): the unified KPI pad is 8/16/4, but these FCDS kpiband cells
   are tightly tuned to the faturamento fixed-height band — 8/16/4 shortens cell height ~8px
   and would force re-deriving the spark bleed below. Tuned 11/13/9 kept as justified exception. */

/* Cell dividers: FLAT 1px borders on each cell's top + left edge (shared edges →
   one crisp line). box-shadow:inset reads as a soft shadow groove between cells —
   a border is a flat hairline with no shadow. --line matches the band border, so
   the coincident line at the band's own top/left edge reads as the border. */

/* wraps to a 2nd line instead of truncating — "Custos sobre Receita" / "Margem
   Contrib." don't fit the narrow cells on one line, and the band is natural-height
   now (no fixed cap), so a 2-line label is free vertical space, not an overflow. */

/* metric cells (Receita/Líquido/Devoluções/MB/MC) carry a single number → the
   value block CENTERS in the height the band borrows from the breakdown/gauge
   cells, so the number fills the card instead of leaving dead space below. The
   label stays top-aligned across every cell for one clean header row. */

/* every metric cell drops its delta to its own line UNDER the big value (hero
   included) and gives it real presence — the chip reads as a second data point,
   not a footnote crammed beside the number. */

/* caution valences ported from legacy --warning/--previsao: amber value, mirroring
   the pos/neg value-colour mechanism instead of the old 4px coloured bottom-rule */

/* value line: big R$ number + its month-over-month delta chip, baseline-aligned,
   wrapping as a unit on narrow cells (kc__v keeps its top margin as a flex item) */

/* ritmo gauge cell */

/* dois gauges lado a lado (Atingido · Ritmo). Número e subtítulo são desenhados
   DENTRO do canvas por `biChartConfig.gauge` — aqui só se dá a caixa, então não
   há mais overlay de rótulo para manter alinhado. Meio-arco → caixa 2:1. */
/* align-items:flex-start é obrigatório: como item de flex esticado, a caixa
   herdaria a altura da linha e o aspect-ratio seria ignorado (o canvas cresce,
   a linha cresce junto). */
.krings{display:flex;gap:0.75rem;justify-content:center;align-items:flex-start;margin:0.25rem 0 0}
/* altura explícita, não aspect-ratio: o canvas é conteúdo em fluxo e o
   Chart.js escreve style.height nele — com altura automática o box cresceria
   junto e o ratio seria ignorado. */
.kgauge{flex:1 1 0;min-width:0;max-width:11rem;height:6.5rem}
.kgauge--empty{display:grid;place-items:center;width: 6rem;height: 6rem;margin:0.25rem auto 0;
  border-radius:50%;border:2px dashed var(--line-3);color:var(--ink-4);font-family:var(--mono)}

/* R$/dia útil: realizado vs necessário — leitura concreta do Ritmo */

/* scope note — shown only when the selection mixes meta and non-meta segments */

/* A lista de componentes do "Custos sobre Receita" é d-flex/justify-content-between
   do Bootstrap na própria célula — sem componente .kbd próprio. */

/* ── CÉLULA DE KPI (canônica) ───────────────────────────────────────────────
   Rótulo (`.lab`, o mesmo do cabeçalho de card) + valor + apoio. A célula É o
   card: sem `.card-body` no meio, porque `.card` já é flex-column com o padding
   canônico — o corpo extra só zerava um padding para redeclarar outro.

   O tamanho do valor acompanha a LARGURA DA CÉLULA (`cqi`), não a da viewport.
   Uma declaração cobre a faixa inteira sem breakpoint: 8-por-linha em 1440 a
   célula tem ~125px úteis e o número fica nos 20px de hoje (piso do clamp); num
   monitor de 1920 sobe para 28px; empilhada no celular a célula tem ~326px e o
   número também vai ao teto. Fonte fixa não faz isso — ou é pequena no monitor
   ou quebra em duas linhas na faixa estreita (medido).

   Distribuição vertical: como todas as células esticam até a altura da mais alta
   (a do gauge), sobra vão nas curtas. As três âncoras deixam esse vão distribuído
   de propósito em vez de virar um buraco no rodapé — rótulo no topo (uma linha de
   cabeçalho alinhada em toda a faixa), número centrado no vão (`margin-block:auto`)
   e apoio na base. */
.kpic{container-type:inline-size}
/* O `.lab` canônico tem tracking de .1em, que numa célula de ~125px úteis custa
   uma linha inteira ("MARGEM CONTRIB." e "CUSTOS SOBRE RECEITA" quebravam em 2 e
   3 linhas). Na banda ele fica no tracking curto — mesma peça, mesma cor, mesmo
   caixa-alta; só o espaçamento cede à largura da célula. */
.kpic > .lab{letter-spacing:.03em}
.kpic__v{font-size:clamp(1.25rem,16cqi,1.75rem);font-weight:700;line-height:1.05;
  white-space:nowrap;margin-block:auto;padding-block:0.25rem}
.kpi8 .krings{margin-block:auto}
.kpic__s{margin-top:auto;padding-top:0.5rem;font-size:0.875rem;line-height:1.3;color:var(--ink-3)}
/* Celular (célula empilhada, largura de tela inteira): o número sobe para a
   linha do rótulo, encostado à direita. Empilhado na vertical, o cartão gastava
   ~110px de altura com metade da largura vazia; lado a lado ele cai para ~75px e
   a faixa inteira deixa de ser duas telas e meia de rolagem. */
@media(max-width:575.98px){
  .kpic{display:grid;grid-template-columns:1fr auto;align-items:center;column-gap:0.75rem}
  .kpic__v{grid-column:2;grid-row:1;margin-block:0;padding-block:0;text-align:right}
  .kpic__s{grid-column:1/-1;margin-top:0;padding-top:0.25rem}
  .kpi8 .krings{grid-column:1/-1;margin-block:0}
}

/* Banda de KPI do faturamento: as 8 células numa linha só. `row-cols-*` do
   Bootstrap para em 6, então a faixa larga é grid explícito. Cai para 4, 2 e —
   no celular — empilha, que é onde o número ganha a largura toda da tela. */
.kpi8{display:grid;gap:0.75rem;grid-template-columns:minmax(0,1fr)}
@media(min-width:576px){.kpi8{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(min-width:768px){.kpi8{grid-template-columns:repeat(4,minmax(0,1fr))}}
@media(min-width:1400px){.kpi8{grid-template-columns:repeat(8,minmax(0,1fr))}}
/* Numa faixa de 8 colunas a caixa do gauge é o que dita a altura da linha
   inteira — encolhe para não abrir vazio nas outras sete. */
.kpi8 .kgauge{max-width:8rem;height:4.75rem}
/* responsive: wrap the 8 cells */
/* Phone density (narrow portrait OR short landscape): the band was ~669px tall in
   portrait and ~83% of a landscape screen, owning the viewport before any chart or
   table. Shrink the values + padding so content reaches above the fold. The
   max-height clause catches landscape phones (~844px wide, missed by max-width). */
@media(max-width:575.98px), (max-height:540px){

  /* shrink the tallest driver so short tiles stop stretching into dead space:
     o gauge é quem dita a altura da faixa. */

  .krings{gap:0.5rem;margin-top:0}
}

/* ── responsive grid spans ───────────────────────────────────────────────── */
@media(max-width:992px){.hero,.kpi,.flow,.sigcol{grid-column:span 12}.sigcol{flex-direction:row;flex-wrap:wrap}.sigcol .sig{flex:1 1 30%}}
@media(max-width:768px){
  .kpi{grid-template-columns:1fr}.sigcol .sig{flex:1 1 100%}
}

/* ── §9 PARAMETRIC TOOLBAR: relocated biFiltros controls inside topbar chips ──
   Shared by every page whose filters are relocated into the FCDS topbar by
   fcds-filterbar.js. The chip/popover/button PRIMITIVES live in §8 above; here we
   restyle the RELOCATED biFiltros pills + the period inline calendar to the FCDS
   look. Selectors only match relocated-chip DOM, so pages without the toolbar are
   unaffected. Moved here from faturamento-fcds.css so all pages share one source. */
.fcds-filters-host{position:absolute!important;width:1px;height:1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;padding:0;margin:-0}

/* segmento / sub-segmento / empresa / centro de custo pills inside a popover →
   checkable rows, LEFT-aligned (align-items:stretch overrides the base
   .filter-group__pills{align-items:center}; justify-content:flex-start keeps the
   checkbox+label at the left edge like the original mockup). */
.pop:not(.pop--period) .filter-group__pills{display:flex;flex-direction:column;align-items:stretch;gap:0}

/* === CHECKROW — linha de seleção do popover de filtro ========================
   NÃO é um `.pill`. Pill é chip: pequeno, redondo, alternável. Isto é uma linha
   de checkbox — largura total, alinhada à esquerda, caixa em `::before`, sem
   borda e sem fundo. Vestia `.pill` e passava a vida desfazendo o que pill é;
   como a base `.pill` ganhou `!important` (bloco "statement pill look"), o
   desfazer parou de funcionar e a linha virou chip cinza redondo à revelia.
   Componente próprio → sem escopo defensivo, sem nada para vencer.
   Fábricas: filtros.js `_criarLinhaCheck`, inadimplencia.js (#pills-cc). */
.checkrow{display:flex;align-items:center;justify-content:flex-start;gap:0.5rem;width:100%;height:auto;padding:0.5rem;border:0;
  border-radius:var(--r-xs);background:none;font-size:0.875rem;font-weight:500;color:var(--ink);
  text-align:left;white-space:nowrap;cursor:pointer}
.checkrow::before{content:"";width: 1.0625rem;height: 1.0625rem;border-radius:var(--bs-border-radius);border:1.5px solid var(--line-3);
  flex:0 0 auto;background:no-repeat center/11px 11px;transition:all .12s}
.checkrow:hover{background:var(--surf-2)}
.checkrow:focus-visible{outline:2px solid var(--acc);outline-offset:-2px}
/* Caixa marcada sem preenchimento de acento: some o quadrado quase-preto, fica
   o contorno um degrau mais escuro e o check em ardósia. Preenchimento suave é
   `background-color:var(--acc-d);color:var(--bi-text-on-accent)`. */
.checkrow--on::before{border-color:var(--ink-3);
  content:"\f00c";font-family:"Font Awesome 6 Free";font-weight:900;font-size:0.875rem;color:var(--acc-d);display:flex;align-items:center;justify-content:center}
/* Sem dados no período. A regra antiga (`.pill--oculto`) estava escopada a
   `:is(.command-bar,.secondary-bar)` e o elemento vive em `.pop` — nunca casou,
   nunca renderizou. O tracejado migra para a caixa, já que a linha não tem borda. */
.checkrow--empty{opacity:0.45;font-style:italic}
.checkrow--empty::before{border-style:dashed}
.checkrow--empty:hover{opacity:0.75}

/* período popover: ONE inline flatpickr calendar (.periodo-cal) + presets. */
.pop--period{min-width: 14.75rem}
.pop--period .periodo-cal{display:flex;flex-direction:column;gap:0.5rem}
.pop--period .filter-group__label{font-size:0.875rem;font-weight:600;letter-spacing:.04em;
  text-transform:uppercase;color:var(--ink-3)}
.pop--period .periodo-cal__presets{display:flex;gap:0.25rem;flex-wrap:wrap}
/* Só o que é variante do preset: ocupar a linha, centralizar, peso maior.
   `border`/`background`/`border-radius`/`font-size` saíram — redeclaravam o que a
   base já dá (`--surf-2` é o mesmo #f3f4f7 de `--bi-bg-hover`, `--line` o mesmo
   #e6e8ec de `--bi-border-color`) e só existiam para tentar vencer o `!important`
   que não existe mais. O `:hover` local também saiu: `--surf-3` (#eceef2) diverge
   do hover da base (#ffffff), e o efetivo hoje é o da base. */
.pop--period .periodo-cal__presets .pill{flex:1 1 auto;padding:0.25rem 0.5rem;font-weight:600;
  text-align:center}
/* ATENÇÃO — delta esperado: hoje o preset SELECIONADO renderiza cinza, porque
   esta regra era morta sob o `!important` da base. Com a cascata restaurada ela
   passa a valer e a seleção de período fica visível. É correção, não regressão,
   mas é o único ponto da fase 2 que muda pixel. Verificar ao vivo. */
.pop--period .periodo-cal__presets .pill.pill--active,
.pop--period .periodo-cal__presets .pill.active{background:var(--acc-soft);border-color:var(--acc-line);color:var(--acc-ink)}
.pop--period .periodo-cal__input{display:none}
.pop--period .flatpickr-calendar.inline{margin:0 auto;box-shadow:none;border-color:var(--line-2)}

/* flatpickr calendar → FCDS glass surface + accent (month + day cells). */
.flatpickr-calendar{background:var(--surf);border:1px solid var(--line);border-radius:var(--r-md);
  font-family:var(--sans)}
.flatpickr-calendar:before,.flatpickr-calendar:after{display:none}
.flatpickr-months .flatpickr-month,.flatpickr-current-year,.flatpickr-calendar .numInputWrapper input{color:var(--ink)}
.flatpickr-current-year,.flatpickr-calendar .cur-year{font-family:var(--mono);font-weight:600}
.flatpickr-months .flatpickr-prev-month svg,.flatpickr-months .flatpickr-next-month svg{fill:var(--ink-2)}
.flatpickr-months .flatpickr-prev-month:hover svg,.flatpickr-months .flatpickr-next-month:hover svg{fill:var(--acc)}
.flatpickr-monthSelect-month{color:var(--ink-2);font-weight:500;border-radius:var(--r-xs)}
.flatpickr-monthSelect-month:hover{background:var(--surf-2);color:var(--ink)}
.flatpickr-monthSelect-month.inRange{background:var(--acc-soft);color:var(--acc-ink)}
.flatpickr-monthSelect-month.selected,.flatpickr-monthSelect-month.startRange,
.flatpickr-monthSelect-month.endRange{background:var(--acc);color:var(--bi-text-on-accent);border-color:var(--acc)}
.flatpickr-monthSelect-month.flatpickr-disabled,
.flatpickr-monthSelect-month.flatpickr-disabled:hover{color:var(--ink-4);opacity:.5;background:transparent}
.flatpickr-day{color:var(--ink-2);border-radius:var(--r-xs)}
.flatpickr-day:hover{background:var(--surf-2);color:var(--ink)}
.flatpickr-day.inRange,.flatpickr-day.today.inRange,.flatpickr-day.prevMonthDay.inRange,
.flatpickr-day.nextMonthDay.inRange{background:var(--acc-soft);border-color:var(--acc-soft);
  box-shadow:-5px 0 0 var(--acc-soft),5px 0 0 var(--acc-soft);color:var(--acc-ink)}
.flatpickr-day.selected,.flatpickr-day.startRange,.flatpickr-day.endRange,
.flatpickr-day.selected:hover,.flatpickr-day.startRange:hover,.flatpickr-day.endRange:hover{
  background:var(--acc);border-color:var(--acc);color:var(--bi-text-on-accent)}
.flatpickr-day.today{border-color:var(--acc-line)}
.flatpickr-day.flatpickr-disabled{color:var(--ink-4);opacity:.5}

/* ghost icon help button in the topbar, matching the other topbar controls */
.fcds-help{display:inline-flex;align-items:center;justify-content:center;width: 2rem;height: 2rem;padding:0;
  border:var(--bs-border-width) solid var(--line);border-radius:var(--bs-border-radius-lg);background:var(--surf);color:var(--ink-3);cursor:pointer}
.fcds-help svg,.fcds-help i{width: 1rem;height: 1rem;font-size:1rem}
.fcds-help:hover{background:var(--surf-2);color:var(--acc-ink)}
/* a page that declares no help slug ({% block ajuda_doc %}) gets no button */
.fcds-help[data-ajuda-doc=""]{display:none}

/* GATING — the default topbar filter markup ships on every FCDS page (base_fcds.html)
   but stays dormant until fcds-filterbar.js relocates a #bi-filtros host and sets
   body.fcds-toolbar-on. Until then, hide the empty cluster + its separator so
   non-migrated pages keep a clean topbar. Scoped via :not() so when the toolbar IS
   on, the §8 rules above apply unchanged (no specificity fight). */
body:not(.fcds-toolbar-on) .topbar>.vr,
body:not(.fcds-toolbar-on) .topbar .filters,
body:not(.fcds-toolbar-on) .topbar .filtbtn,
body:not(.fcds-toolbar-on) .topbar .buscar{display:none!important}
/* Ajuda (?) fica visível se a página declara {% block ajuda_doc %} — ex.: telas de
   topbar dormante intencional como comex-kpi-financeiro. Some só quando não há doc. */
body:not(.fcds-toolbar-on) .topbar .fcds-help[data-ajuda-doc=""]{display:none!important}

/* ── TABS ──────────────────────────────────────────────────────────────────
   O skin do tablist NÃO mora aqui. Este bloco declarava-se canônico mas estava
   inteiro dentro de um comentário mal fechado (o `!important{...}` da prosa
   abria chave e o parser só reencontrava o fecho 20 linhas abaixo), então nunca
   foi aplicado. Removido em vez de revivido: reviver mudaria o render, e o vivo
   já é o de .fcds-tabs mais adiante neste arquivo (a declaração com !important
   vence as demais). O anel de foco de teclado também está lá, não se perdeu.
   Consolidar as declarações duplicadas de .fcds-tabs é trabalho do lote 3.   */

/* count badge inside a tab button (e.g. "Notas Fiscais 1.234") */

/* keyboard focus for the filter cluster + popover rows + sheet controls that had
   no visible focus ring (WCAG 2.4.7). Slate accent, matching the FCDS namespace. */
.fdrop:focus-visible,.tb-btn:focus-visible,.buscar:focus-visible,.fbuscar:focus-visible,
.filtbtn:focus-visible,.fcds-help:focus-visible,
.optrow:focus-visible,.short:focus-visible,.mcell:focus-visible{
  outline:2px solid var(--acc);outline-offset:2px;
}

/* ── §10 SHARED PAGE HELPERS ────────────────────────────────────────────────
   Generic compositional helpers promoted here from faturamento-fcds.css so EVERY
   migrated page composes the faturamento card grid without copy-pasting. The JS
   statement cluster (.hero/.kpi/.flow/.sigcol) hardcodes its own spans above;
   these explicit spans drive every OTHER section a page lays out. */
/* explicit grid spans (used with .grid) */
.fcds-span-3{grid-column:span 3}
.fcds-span-4{grid-column:span 4}
.fcds-span-5{grid-column:span 5}
.fcds-span-6{grid-column:span 6}
.fcds-span-7{grid-column:span 7}
.fcds-span-8{grid-column:span 8}
.fcds-span-9{grid-column:span 9}
.fcds-span-12{grid-column:span 12}
.fcds-row-eq{align-items:stretch}   /* equal-height row */
@media(max-width:992px){
  .fcds-span-3,.fcds-span-4,.fcds-span-5,.fcds-span-6,.fcds-span-7,.fcds-span-8,.fcds-span-9{grid-column:span 12}
}

/* segmented in-card toggle (Gráfico/Sazonalidade · Top20/ABC · Cliente/Interm.) */
.fcds-seg{display:inline-flex;gap:var(--bi-space-3xs);padding:var(--bi-space-3xs);
  background:var(--surf-3);border-radius:var(--r-sm)}
.fcds-seg__btn{padding:var(--bi-space-xs) 0.5rem;border:0;border-radius:var(--r-xs);background:none;
  font-size:0.875rem;font-weight:500;color:var(--ink-2);cursor:pointer;transition:background .12s,color .12s}
.fcds-seg__btn:hover{color:var(--ink)}
.fcds-seg__btn.active{background:var(--surf);color:var(--acc-ink);font-weight:600}
.fcds-seg__btn:focus-visible{outline:2px solid var(--acc);outline-offset:2px}

/* mini uppercase label for a chart/sub-block inside a card */
.fcds-mini-lab{font-size:0.875rem;font-weight:600;color:var(--ink-3);text-transform:uppercase;
  letter-spacing:.06em;margin-bottom:var(--bi-space-xs)}

/* quiet text link inside an operational signal (.sig) / card footer */
.fcds-siglink{display:inline-block;margin-top:var(--bi-space-sm);padding:0;border:0;background:none;
  cursor:pointer;font-size:0.875rem;font-weight:600;color:var(--ink-2);
  text-decoration:underline;text-underline-offset:2px}
.fcds-siglink:hover{color:var(--acc-ink)}
.fcds-siglink:focus-visible{outline:2px solid var(--acc);outline-offset:2px;border-radius:var(--bs-border-radius-sm)}

/* generic utility */
.is-hidden{display:none!important}
/* Algarismos tabulares. Numa coluna de 204 pesos, dígito alinhado com dígito é
   o que deixa comparar 1.748 e 1.579 de relance; com a figura proporcional a
   coluna serrilha e a comparação vira leitura. Utilitário do design system, não
   regra de uma página: vale para peso, código, data e qualquer célula numérica. */
.num-tab{font-variant-numeric:tabular-nums}
/* `.font-monospace` herda o mesmo tratamento. Enquanto a primitiva do Bootstrap
   apontava para SFMono/Consolas, a utility alinhava dígito com dígito de graça —
   é fonte de largura fixa. Com `--bs-font-monospace` remapeado para o Roboto ela
   passa a ser proporcional, e as colunas numéricas que a usam (faturamento,
   importar-of, matriz-acesso, diagnóstico) serrilhariam. Os 23 usos da utility
   neste código são todos numéricos, então ela carrega tabular-nums em vez de
   trocarmos 23 chamadas por `.num-tab`. Em <code>/<pre> é inócuo. */
.font-monospace{font-variant-numeric:tabular-nums}

/* ── BOOTSTRAP BUTTON RECONCILIATION — REMOVIDA ─────────────────────────────
   Aqui moravam os remaps de `.btn-primary`, `.btn-outline-primary` e `.btn-link`
   para a marca FCDS. Removidos por diretiva do usuário: botão é Bootstrap
   canônico, com o azul de fábrica (#0d6efd). O segundo remap, gêmeo deste, ficava
   na seção "BOOTSTRAP PALETTE to FCDS" e saiu junto — eram dois, e apagar só um
   não mudaria nada. NÃO reintroduzir nenhum dos dois. */

/* ── ALERT / NOTICE PALETTE — REMOVIDA (diretiva do usuário) ────────────────
   As variantes .alert-success/-info/-warning/-danger voltam às cores de fábrica
   do Bootstrap. Só o RAIO continua vindo do FCDS (geometria, não paleta). */
.alert{--bs-alert-border-radius:var(--r-sm)}

/* ── SHELL FREEZE (shell is untouchable) ────────────────────────────────────
   The shell topbar HOSTS injected Bootstrap action buttons and relies on the
   global --bs-* remap. Now that remap is brand-blue (content actions). Pin the
   topbar's injected buttons back to the slate command tone so the shell rail +
   topbar look is unchanged. custom.css itself stays literally untouched.
   Specificity (0,3,0) beats the global .btn-primary (0,1,0). */
/* B2: topbar-injected buttons now inherit the global brand-blue .btn-primary/-outline
   remap (slate pin removed) — all primary CTAs unified to brand-blue #006BB5. */

/* ── Zero all resting shadows (user directive) ──────────────────────────────
   Bootstrap overlay components read component-scoped --bs-*-box-shadow vars, so
   neutralise the vars AND hard-override the property to win regardless of load
   order. Focus rings (:focus-visible / --bs-*-focus-box-shadow) are untouched =
   a11y preserved; the inset 9999px table-fill trick is not a box-shadow target
   here so zebra/sticky-column backgrounds stay intact. */
:root{
  --bs-box-shadow:none;--bs-box-shadow-sm:none;--bs-box-shadow-lg:none;--bs-box-shadow-inset:none;
  --bs-dropdown-box-shadow:none;--bs-modal-box-shadow:none;--bs-toast-box-shadow:none;
  --bs-popover-box-shadow:none;--bs-offcanvas-box-shadow:none;--bs-card-box-shadow:none;
  --bs-btn-box-shadow:none;--bs-btn-active-shadow:none;
  /* B5/A3: só a GEOMETRIA de modal/dropdown segue o padrão FCDS. As cores de borda
     (--bs-*-border-color) e o tom do backdrop foram removidos por diretiva do
     usuário — ficam os valores de fábrica do Bootstrap. */
  --bs-modal-border-radius:var(--r);
  --bs-dropdown-border-radius:var(--bi-radius-md)}
/* A varredura `box-shadow:none!important` sobre dropdown/modal/toast/popover/
   offcanvas/card/tooltip saiu: cada um lê a sombra do seu `--bs-*-box-shadow`, e
   todos já estão em `none` no bloco de tokens acima — era uma segunda tranca na
   mesma porta. Medido componente a componente depois de tirar: seis dos sete
   continuam em `none`. O sétimo é o `.toast`, que redeclara
   `--bs-toast-box-shadow` no próprio seletor e por isso nunca enxergou o valor do
   `:root`; a sombra volta pelo mesmo canal, sem `!important`. */
.toast{--bs-toast-box-shadow:none}

/* ==========================================================================
   MERGED FROM bi/static/bi/css/main.css (P6 — two-layer collapse). Loads here
   (after the original FCDS rules) exactly where it loaded per-page before.
   ========================================================================== */

/* ==========================================================================
   main.css — "Editorial Finance" component system for bi/ app
   Uses ONLY tokens from tokens.css. ZERO literal color values.
   ZERO !important (except clearly marked DataTables overrides).

   Sections:
    1.  Reset / Base
    2.  Command Bar (dark filter strip)
    3.  KPI Band (top metric strip)
    4.  Section Anchor (editorial dividers)
    5.  Layout helpers
    6.  Card
    7.  KPI (operational cards)
    8.  Badge
    9.  Variation
   10.  Table + DataTables overrides
   11.  Chart
   12.  Waterfall
   13.  Heatmap
   14.  Gauge
   15.  Pills / Filters
   16.  Risco de Caixa
   17.  Toggle Devoluções
   18.  Progress Margin
   19.  Modal
   20.  Accordion
   21.  Skeleton
   22.  Error + Empty
   23.  Accessibility
   24.  Animations
   25.  Responsive
   ========================================================================== */

/* ==========================================================================
   1. RESET / BASE
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

.page {
  font-family: var(--sans);
  font-size: var(--bi-fs-body);
  font-weight: var(--bi-fw-regular);
  line-height: var(--bi-lh-normal);
  color: var(--bi-text-primary);
  background-color: var(--surface-app);
  /* SEM min-height:100vh. A .page vive DENTRO do .content, que já está abaixo da
     topbar (52px) e tem padding — forçar 100vh aqui garantia 52px + 100vh + padding
     > viewport, ou seja, uma barra de rolagem fantasma na PÁGINA, em toda tela do
     app, com tabela ou sem. Encher a tela já é papel do `.main`
     (min-height: calc(100dvh - 52px), custom.css). */
  /* padding movido p/ a def global com !important (5373, mesmo valor) — morto aqui */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ==========================================================================
   2. COMMAND BAR
   Fundo claro, borda inferior — filtros compactos e modernos
   ========================================================================== */

/* (.command-bar container removido — não renderizado; a raiz é .command-bar__filters.) */

/* Linha de filtros — coluna com 3 rows */
.command-bar__filters {
  display: flex;
  flex-direction: column;
  gap:var(--bi-space-2xs);
}
.command-bar__row {
  display: flex;
  align-items: center;
  gap:var(--bi-space-sm);
  flex-wrap: wrap;
}

.filter-group {
  display: flex;
  align-items: center;
  gap:var(--bi-space-xs);
}

.filter-group__label {
  font-size: 0.875rem;
  font-weight: var(--bi-fw-semibold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bi-text-muted);
  line-height: 1;
  white-space: nowrap;
}

.filter-group__pills {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap:0.25rem;
}

/* Pills no command bar */
/* Só o que diverge da base: família, tamanho e a transição por propriedade.
   `border-radius`/`border`/`color`/`background` saíram — eram mortos (a base
   `!important` os vencia) e reintroduzi-los agora MUDARIA o visual da barra,
   que hoje é o da base. O `:hover` local saiu pelo mesmo motivo. */
:is(.command-bar, .secondary-bar) .pill {
  font-family: var(--sans);
  font-size: 0.875rem;
  font-weight: var(--bi-fw-medium);
  padding:var(--bi-space-3xs) 0.5rem;
  cursor: pointer;
  transition:
    background var(--bi-transition-fast),
    color var(--bi-transition-fast),
    border-color var(--bi-transition-fast);
  white-space: nowrap;
  user-select: none;
  line-height: 1.4;
}

/* (`.pill--disabled` removido — zero usos em JS/template, código morto.
   `.pill--oculto` removido — migrou para `.checkrow--empty` §CHECKROW; a regra
   aqui nunca casou, o elemento vive em `.pop`, fora destas barras.) */

/* "pending search" state — unified onto the FCDS green-pulse standard
   (.buscar.pending, custom.css:256) so the same logical state reads
   identically across both filterbars. */
/* NOTE: NOT scoped under .command-bar — the live filterbar root is
   .command-bar__filters (no bare .command-bar element exists in the DOM),
   so an ancestor scope here would never match. !important to beat the base
   .btn-buscar-trigger{background:--brand!important} at ~L5772. */
.btn-buscar-trigger.btn-buscar--pending {
  color: var(--bi-text-on-accent);
  background: var(--positive-text) !important;
  border-color: var(--positive-text) !important;
  font-weight: var(--bi-fw-semibold);
}

.btn-buscar-trigger.btn-buscar--pending:hover {
  background: color-mix(in srgb, var(--positive-text) 86%, var(--ink)) !important;
  border-color: color-mix(in srgb, var(--positive-text) 86%, var(--ink)) !important;
  color: var(--bi-text-on-accent);
}

/* ==========================================================================
   3. KPI BAND
   Faixa horizontal de 5 métricas sem cards individuais
   ========================================================================== */

.kpi-band {
  display: grid;
  grid-template-columns: 1.2fr 1.4fr 1fr 1fr 1fr 1fr 1fr;
  background: var(--bi-bg-surface);
  border: var(--bi-border);
  border-radius: var(--bi-radius-md);
  box-shadow: var(--bi-shadow-sm);
  overflow: hidden;
  /* No horizontal margin:the band aligns flush to its section/card width like
     every .cardbox. .page already supplies the page side padding, so a
     horizontal margin here double-inset the band (was 3rem narrower than cards
     across all pages). Standardized 2026-06 — see docs/planos/pilot-page-refactor.md.
     KPI band → content gap promoted to --bi-space-md (Batch 6 §2, Agent C). */
  margin: 0 0 var(--bi-space-md);
  animation: bi-fadeIn var(--bi-transition-normal) ease both;
}

/* Aging table — pct bar overlay */
.faixa-dot {
  display: inline-block;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--bi-dot-cor, var(--ink-4));
  margin-right:var(--bi-space-xs2);
  vertical-align: middle;
}

/* Shared, page-agnostic KPI accent modifiers — every KPI page tags cells by
   value DIRECTION via these (no inline category accents). Bottom-rule only. */

/* Legacy alias (despesas_comex used --previsao) → same as warning. */

.kpi-band__label {
  font-size: var(--bi-fs-label);
  font-weight: var(--bi-fw-semibold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bi-text-muted);
  margin-bottom:var(--bi-space-xs);
  line-height: 1;
}

.kpi-band__value {
  /* Shared (Step 3 contract): KPI numbers are tabular on every page — the number
     is the data, dark, no colour fill. Use --mono (Roboto, loaded in
     base_fcds.html) to MATCH faturamento's .kc__v numerals; Roboto
     (official numeral font, --mono) is the canonical numeral family — the old
     --bi-font-mono fell back to a system mono that diverged from the reference.
     Roboto is also narrower → less mobile clipping. */
  font-family: var(--mono); /* --mono always resolves; dead --bi-font-mono fallback dropped */
  font-weight: var(--bi-fw-bold);
  color: var(--bi-text-primary);
  line-height: var(--bi-lh-tight);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

.kpi-band__secondary {
  font-family: var(--bi-font-display);
  font-size: var(--bi-fs-body);
  font-weight: var(--bi-fw-medium);
  color: var(--bi-text-secondary);
  margin-top:var(--bi-space-3xs);
  font-variant-numeric: tabular-nums;
}

/* Trend badge — variação vs mês anterior */
.kpi-band__trend {
  display: flex;
  align-items: center;
  gap:0.25rem;
  font-family: var(--sans);
  font-size: var(--bi-fs-caption);
  font-weight: var(--bi-fw-semibold);
  margin-top:var(--bi-space-xs);
  min-height: 0.875rem;
}

/* ==========================================================================
   4. SECTION ANCHOR
   Separador editorial horizontal com label centralizado
   ========================================================================== */

.section-anchor {
  display: flex;
  align-items: center;
  gap:var(--bi-space-sm);
  margin:var(--bi-space-sm) var(--bi-space-lg) var(--bi-space-xs);
}

.section-anchor::before,
.section-anchor::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--bi-border-color);
}

.section-anchor__label {
  font-family: var(--bi-font-display);
  font-size: 0.875rem;
  font-weight: var(--bi-fw-semibold);
  letter-spacing: 0.12em;
  color: var(--bi-text-muted);
  white-space: nowrap;
  text-transform: uppercase;
}

/* KPI strip para cards operacionais (ritmo, PMP, PMR). O seletor desta regra foi
   perdido: a linha abria comentário e nunca fechava, engolindo a declaração
   `padding:0 var(--bi-space-lg)` e o banner da seção 6. Como o nome do seletor
   foi truncado junto, não há o que restaurar — a declaração órfã foi removida. */

/* ==========================================================================
   6. CARD
   ========================================================================== */

/* Accent na borda superior do card */

/* Accent na borda esquerda */

/* 0.5rem floor for Bootstrap badges + inline code (batch5 type contract).
   Bootstrap's .badge ships font-size:0.75em (em-relative → renders 8-0.5rem on
   small parents); force the 12px absolute floor. Chart-internal ring labels
   (.ring__c/.kring__sub) are the only justified sub-12px exception. */
.badge {
  font-size: 0.875rem;   /* 12px */
}
code {
  font-size: 0.875rem;   /* 12px floor */
}

/* Badge de contagem no header do card */

/* ==========================================================================
   7. KPI (operational cards — Ritmo, PMP, PMR, etc.)
   ========================================================================== */

.kpi-tile {
  display: flex;
  align-items: flex-start;
  gap:var(--bi-space-sm);
  padding:var(--bi-space-md);
  position: relative;
  min-height: 5rem;
  background: var(--bi-bg-surface);
  border: var(--bi-border);
  border-radius: var(--bi-radius-md);
  border-left: 3px solid var(--kpi-tile-accent, var(--positive));
  box-shadow: var(--bi-shadow-xs);
}

/* ==========================================================================
   8. BADGE
   ========================================================================== */

.badge {
  display: inline-flex;
  align-items: center;
  gap:var(--bi-space-3xs);
  font-size: var(--bi-fs-caption);
  font-weight: var(--bi-fw-semibold);
  padding:var(--bi-space-3xs) var(--bi-space-sm);
  border-radius: var(--bs-border-radius-pill); /* B6: canonical soft-pill (the one badge shape) */
  line-height: var(--bi-lh-tight);
  white-space: nowrap;
  background: var(--bi-bg-elevated);
  color: var(--bi-text-secondary);
  border: var(--bi-border);
}

/* Direction badges → canonical indicator tokens (text) + *-subtle (bg). */
.badge--success  { background: var(--positive-subtle); color: var(--positive-text);      border-color: var(--positive-text); }
.badge--danger   { background: var(--negative-subtle); color: var(--negative-text);      border-color: var(--negative-text); }
.badge--warning  { background: var(--warning-subtle);  color: var(--warning-text);  border-color: var(--warning); }
/* --info is categorical (not a value direction) → neutral, no direction hue. */
.badge--info     { background: var(--neutral-subtle);  color: var(--ink-2);       border-color: var(--ink-2); }
/* --neutro: o estado TERMINADO, que não pede nada de ninguém. Existe porque
   "concluído" não é "sucesso": pintar de verde tudo o que já foi faturado põe a
   cor mais forte da paleta no que ninguém pode mais mexer, e deixa a única linha
   viva como a mais apagada da lista. Sem cor de direção, sem borda forte. */
.badge--neutro   { background: var(--surf-2);          color: var(--ink-3);               border-color: var(--line-3); }
/* --primary is categorical accent (in-flight / active) → slate accent, no direction hue. */
.badge--primary  { background: var(--acc-soft);        color: var(--acc-ink);             border-color: var(--acc-line); }
/* --brand is the Four heritage blue identity (masthead codes, not a value direction). */
.badge--brand    { background: var(--brand-soft);      color: var(--brand-ink);           border-color: var(--brand); }

/* Densidade — modificador compartilhado p/ grids densos (ex.: despesas_comex). */
.badge--sm { font-size: 0.875rem; padding:var(--bi-space-3xs) var(--bi-space-xs2); }

/* Dot modifier — categorical identity whose hue varies per data value (grupo/segmento),
   supplied at runtime via --dot on the element. Label stays fixed --ink-2 for legibility;
   only the leading dot carries the category hue (cat tokens aren't AA-safe as text). */
.badge--dot { color: var(--ink-2); }
.badge--dot::before {
  content: "";
  width: 0.4375rem;
  height: 0.4375rem;
  border-radius: 50%;
  background: var(--dot, var(--ink-3));
  flex: 0 0 auto;
}

/* ==========================================================================
   9. VARIATION (inline up/down indicator)
   ========================================================================== */

/* ==========================================================================
   10. TABLE (tbl wrapper + DataTables overrides)
   ========================================================================== */

.tbl-wrapper {
  border-radius: var(--bi-radius-md);
  /* Sem borda própria: o .tbl-wrapper sempre mora dentro de um .card (convenção
     FCDS: section.card > .tbl-wrapper), e o card já desenha o contorno do
     componente. Uma borda aqui virava linha dupla em todas as telas de tabela. */
  /* MOBILE: wide ERP tables must scroll inside the card, not clip at its edge.
     (datatable adds .datatable-scroll for DataTables; this covers bare/non-DT
     wrappers — e.g. contas_a_pagar + fluxo-bancario TD tables.) */
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.tbl {
  width: 100%;
  font-size: var(--bi-fs-body);
  color: var(--bi-text-primary);
  margin-bottom:0;
  border-collapse: collapse;
}

.tbl thead th {
  background-color: var(--surf-2);
  border-bottom: 2px solid var(--bi-border-color);
  font-size: var(--bi-fs-label);
  font-weight: var(--bi-fw-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bi-text-secondary);
  white-space: nowrap;
  padding:var(--bi-space-sm) var(--bi-space-md);
}

.tbl tbody td {
  padding:var(--bi-space-sm) var(--bi-space-md);
  border-bottom: var(--bi-border-subtle);
  vertical-align: middle;
}

/* Estado de linha usa o motor do Bootstrap (overlay translúcido `--bs-table-accent-bg`,
   styles.css:2047), não um hex opaco. Hex opaco colide com qualquer faixa que use o
   mesmo valor — `--bi-bg-hover` e `--surf-2` são ambos #f3f4f7, e o hover sumia em
   cima da faixa. O overlay compõe sobre a base, então o hover é sempre mais escuro
   que a linha, seja ela branca ou faixada. */
.tbl tbody tr:hover td {
  --bs-table-accent-bg: var(--bs-table-hover-bg);
}

.tbl__numeric {
  font-family: var(--bi-font-mono);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

/* (removed `.tbl--sticky-first` — superseded by the unified `.stickcols`
   system; pedidos + fluxo-bancário migrated.) */

/* Total row */
.tbl .tbl__total-row td {
  font-weight: var(--bi-fw-bold);
  border-top: 2px solid var(--bi-border-color-heavy);
  background-color: var(--surf-2);
}

/* Densidade — modificador compartilhado p/ tabelas de muitas colunas (ex.: as 27
   colunas do despesas_comex). Reduz padding/line-height das células e encolhe o
   checkbox de linha. Aplique `.tbl--compact` no <table>. */
.tbl--compact thead th,
.tbl--compact tbody td {
  padding:var(--bi-space-xs) var(--bi-space-sm);
  line-height: 1.25;
}
.tbl--compact thead th {
  white-space: normal;
  line-height: 1.2;
}
.tbl--compact .form-check-input {
  width: 0.875rem;
  height: 0.875rem;
}

/* --- DataTables padrão BI — opt-in via .datatable no wrapper --- */

/* Toolbar: B (buttons) à esquerda, l (length) + f (filter) à direita */
.datatable .datatable-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap:var(--bi-space-md);
  flex-wrap: wrap;
  padding:var(--bi-space-sm) var(--bi-space-md);
  border-bottom: 1px solid var(--bi-border-color);
}
.datatable .datatable-toolbar__left,
.datatable .datatable-toolbar__right {
  display: inline-flex;
  align-items: center;
  gap:var(--bi-space-sm);
}

/* Copiar e Colunas são ações independentes — não devem parecer um segmented
   control. Gap real entre os botões + neutraliza o margin-left:-0 que o
   .btn-group (Colunas) herda do bootstrap (border-collapse de grupo). */
.datatable .dt-buttons {
  display: inline-flex;
  gap:var(--bi-space-sm);
}
.datatable .dt-buttons > .btn-group {
  margin-left:0;
}
/* Neutraliza btn/btn-secondary herdado de buttons.bootstrap5 */
.datatable .dt-buttons .btn {
  all: unset;
}
/* Suprime outline de foco sem destruir layout (all:unset no :focus teria espec. 0,4,0 > .pill 0,3,0) */
.datatable .dt-buttons .pill:focus {
  outline: none !important;
  box-shadow: none !important;
}
/* a11y: restaura anel de foco visível por teclado (espelha §23 .pill:focus-visible) */
.datatable .dt-buttons .pill:focus-visible {
  outline: 2px solid var(--positive) !important;
  outline-offset: 2px;
  box-shadow: none !important;
}
.datatable .dt-buttons .pill {
  display: inline-flex !important;
  align-items: center;
  gap:0.25rem;
  padding:var(--bi-space-2xs) 0.5rem;
  font-size: var(--bi-fs-label);
  font-weight: var(--bi-fw-medium);
  /* Estes quatro NÃO são redundantes com a base, apesar de a base dar os mesmos
     valores: o elemento é `btn btn-secondary pill` (DataTables/bootstrap5), e o
     `.btn`/`.btn-secondary` do Bootstrap disputa fundo, borda e raio com a base
     `.pill` (0,1,0). Enquanto a base tinha `!important` isso não aparecia; sem
     ele, o botão caía para o visual do Bootstrap (fundo transparente, raio 0).
     Repetidos aqui em (0,3,0) com os MESMOS valores da base — preserva o
     computado que a tela sempre teve. Medido, não deduzido. */
  background: var(--bi-bg-hover);
  border: var(--bs-border-width) solid var(--bi-border-color);
  border-radius: var(--bs-border-radius-pill);
  color: var(--bi-text-secondary);
  cursor: pointer;
  line-height: 1.4;
  height: 1.75rem;
  box-sizing: border-box !important;
  overflow: hidden;
  transition:
    background var(--bi-transition-fast),
    color var(--bi-transition-fast),
    border-color var(--bi-transition-fast);
}
/* O botão vive num `.btn-group`, e o Bootstrap zera os cantos internos com
   `.btn-group > .btn:not(:last-child):not(.dropdown-toggle)` — (0,4,0), que vence
   o bloco acima (0,3,0) e devolvia `800px 0 0 800px`. Empate em (0,4,0) resolvido
   pela ordem: custom.css carrega depois de styles.css. Sem `!important`. */
.datatable .dt-buttons .pill.btn { border-radius: var(--bs-border-radius-pill); }
.datatable .dt-buttons .pill:hover {
  background: var(--bi-bg-hover) !important;
  color: var(--bi-text-primary) !important;
  border-color: var(--line-3) !important;
  box-shadow: none !important;
  transform: none !important;
}
.datatable .dt-buttons .pill:active {
  background: var(--bi-bg-hover) !important;
  color: var(--bi-text-primary) !important;
  border-color: var(--line-3) !important;
  box-shadow: none !important;
  transform: none !important;
  filter: brightness(0.92);
}
/* Spans injetados por buttons.bootstrap5 — sem herdar font-size de nenhum estado */
.datatable .dt-buttons .pill span {
  font-size: inherit !important;
  line-height: inherit !important;
  font-weight: inherit !important;
  padding:0 !important;
  margin:0 !important;
  transform: none !important;
  display: inline !important;
}
.datatable .dt-buttons .pill i {
  font-size: 0.875rem;
  opacity: 0.7;
}
.datatable .dt-buttons .dropdown-toggle::after {
  margin-left:var(--bi-space-2xs);
  border-top-color: currentColor;
}

/* ColVis dropdown */
.datatable .dt-button-collection {
  background: var(--bi-bg-surface);
  border: var(--bi-border);
  border-radius: var(--bi-radius-sm);
  box-shadow: var(--bi-shadow-md);
  padding:var(--bi-space-2xs) 0;
  font-size: var(--bi-fs-label);
}
.datatable .dt-button-collection .dt-button {
  padding:0.25rem 1rem;
  color: var(--bi-text-primary);
  background: transparent;
  border: 0;
  width: 100%;
  text-align: left;
  cursor: pointer;
}
.datatable .dt-button-collection .dt-button:hover {
  background: var(--bi-bg-hover);
}
.datatable .dt-button-collection .dt-button.active {
  color: var(--positive);
  font-weight: var(--bi-fw-semibold);
}

/* Length + Search inputs alinhados com pills (28px) */
.datatable .dataTables_length,
.datatable .dataTables_filter {
  margin:0;
}
.datatable .dataTables_length label,
.datatable .dataTables_filter label {
  display: inline-flex;
  align-items: center;
  gap:var(--bi-space-xs2);
  margin:0;
  font-size: var(--bi-fs-label);
  color: var(--bi-text-secondary);
  font-weight: var(--bi-fw-medium);
  white-space: nowrap;
}
.datatable .dataTables_length select,
.datatable .dataTables_filter input {
  height: 1.75rem !important;
  min-height: unset !important;
  padding:0 0.5rem !important;
  font-size: var(--bi-fs-label) !important;
  background: var(--bi-bg-hover) !important; /* align to the .dataTables_wrapper filter rule (was --bi-bg-surface) — removes the white-vs-grey conflict */
  border: var(--bi-border) !important;
  border-radius: var(--bi-radius-sm) !important;
  color: var(--bi-text-primary) !important;
  transition: border-color var(--bi-transition-fast);
  box-sizing: border-box;
}
.datatable .dataTables_filter input {
  min-width: 11.25rem;
}
.datatable .dataTables_length select:focus,
.datatable .dataTables_filter input:focus {
  outline: none;
  border-color: var(--acc-line); /* was --positive (green) — neutral controls focus slate, not green */
  box-shadow: var(--ring);
}

/* Scroll horizontal isolado: só conteúdo + thead, não a toolbar nem bottom bar */
.datatable .datatable-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.datatable table.dataTable {
  min-width: 100%;
}

/* Bottom bar: info + paginate */
.datatable .datatable-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding:var(--bi-space-sm) var(--bi-space-md);
  border-top: 1px solid var(--bi-border-color);
}
.datatable .datatable-bottom .dataTables_info,
.datatable .datatable-bottom .dataTables_paginate {
  padding-top:0;
  margin:0;
  font-size: var(--bi-fs-label);
  color: var(--bi-text-secondary);
}

/* Paginação: nenhuma regra. Ver o bloco "PAGINAÇÃO: sem regra nenhuma" mais
   abaixo — o .pagination do Bootstrap responde por cor, borda, raio e solda. */

/* Filtros de coluna multi-seleção (Pedidos): trigger + painel flutuante.
   Antes só existia em demo/components-v2.css (não carregado em produção), então
   o controle vinha sem estilo. Portado para o FCDS: acento slate (não brand-blue),
   raio igual aos controles da toolbar (--bi-radius-sm). O painel é position:fixed
   (posicionado no abrir por pedidos-colfilter.js) para escapar do overflow do
   .datatable-scroll, que recortava a lista quando havia scroll horizontal. */
.colfilter-multi { position: relative; }
.colfilter-multi__trigger {
  display: inline-flex; align-items: center; justify-content: space-between;
  gap:var(--bi-space-xs2); width: 100%;
  font-size: var(--bi-fs-label); font-weight: var(--bi-fw-regular);
  color: var(--bi-text-primary); background: var(--bi-bg-surface);
  /* Borda e raio do PRÓPRIO Bootstrap (--bs-border-color / --bs-border-radius-sm),
     não os tokens FCDS: este gatilho vive lado a lado com `.form-control-sm` numa
     linha de filtros, e os dois cinzas (#e6e8ec do FCDS × #dee2e6 do Bootstrap)
     ficaram visivelmente diferentes quando o remap de --bs-border-color foi
     removido. Amarrado ao token do Bootstrap, o contorno acompanha os campos
     vizinhos aconteça o que acontecer com o tema. */
  border: var(--bs-border-width) solid var(--bs-border-color);
  border-radius: var(--bs-border-radius-sm);
  padding:var(--bi-space-3xs) var(--bi-space-xs2); cursor: pointer; white-space: nowrap;
  transition: border-color var(--bi-transition-fast), color var(--bi-transition-fast);
}
.colfilter-multi__trigger:hover { border-color: var(--bi-border-color-heavy); }
/* Foco e "tem seleção" no MESMO azul dos demais controles (o --bs-primary de
   fábrica do Bootstrap), e não no quase-preto --acc: o contorno escuro lia como um
   controle de outra família ao lado dos campos e botões da linha de filtros. */
.colfilter-multi__trigger:focus-visible { outline: none; border-color: var(--bs-primary); }
.colfilter-multi__trigger > i { font-size: 0.7em; opacity: 0.6; }
.colfilter-multi__ico { font-size: 0.72em; color: var(--bi-text-secondary); flex-shrink: 0; }
.colfilter-multi--ativo .colfilter-multi__trigger {
  border-color: var(--bs-primary); color: var(--bs-primary); font-weight: var(--bi-fw-medium);
}
.colfilter-multi__panel {
  position: fixed; z-index: var(--bi-z-dropdown, 100);
  min-width: 11.5rem; width: max-content; max-height: 18.75rem; overflow-y: auto;
  background: var(--bi-bg-surface);
  border: var(--bs-border-width) solid var(--bi-border-color);
  border-radius: var(--bi-radius-md);
  /* Elevação real: um menu flutuante precisa se separar do conteúdo abaixo
     (exceção de popover ao depth-flat do FCDS). Sombra suave, sem dureza. */
  box-shadow: 0 10px 28px -10px rgba(25, 28, 34, 0.22), 0 2px 8px -3px rgba(25, 28, 34, 0.12);
  padding:var(--bi-space-3xs);
  animation: biColfilterIn 0.13s cubic-bezier(0.16, 1, 0.3, 1);
}

/* Picker "Tipo de Documento" do modal de anexos (_modais_titulo.html): o painel
   é o .colfilter-multi__panel com busca fixa no topo e lista rolando embaixo.
   Vinha de um <style> inline no template — CSS autoral só mora aqui. */
.df-anexo-tipo-picker__panel { display: flex; flex-direction: column; max-height: 20rem; padding:0; }
.df-anexo-tipo-picker__panel .input-group { flex: 0 0 auto; }
#df-anexo-tipo-opcoes { flex: 1 1 auto; overflow-y: auto; }
@keyframes biColfilterIn {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .colfilter-multi__panel { animation: none; }
}
.colfilter-multi__opt {
  display: flex; align-items: center; gap:var(--bi-space-xs);
  padding:var(--bi-space-xs2) var(--bi-space-sm); margin:0;
  border-radius: var(--bi-radius-sm);
  font-size: var(--bi-fs-label); font-weight: var(--bi-fw-regular); color: var(--bi-text-primary);
  white-space: nowrap; cursor: pointer; text-transform: none; letter-spacing: 0;
  transition: background var(--bi-transition-fast);
}
.colfilter-multi__opt:hover { background: var(--bi-bg-hover); }
.colfilter-multi__opt input {
  cursor: pointer; accent-color: var(--acc);
  width: 0.875rem; height: 0.875rem; flex-shrink: 0;
}
/* Painel de INTERVALO (biUtils.colfilterRange): dois inputs de/até empilhados.
   Reusa a casca .colfilter-multi__panel; só arruma o layout dos campos. */
.colfilter-range__panel {
  min-width: 11.25rem; padding:var(--bi-space-xs);
  display: flex; flex-direction: column; gap:var(--bi-space-xs2);
}
.colfilter-range__field {
  display: flex; align-items: center; gap:var(--bi-space-xs); margin:0;
  font-size: var(--bi-fs-label); font-weight: var(--bi-fw-regular);
  color: var(--bi-text-secondary); text-transform: none; letter-spacing: 0;
}
.colfilter-range__field > span { width: 2.2em; flex-shrink: 0; }
.colfilter-range__field input {
  flex: 1; min-width: 0;
  font-size: var(--bi-fs-label); color: var(--bi-text-primary);
  background: var(--bi-bg-surface); border: var(--bs-border-width) solid var(--bi-border-color);
  border-radius: var(--bi-radius-sm); padding:var(--bi-space-3xs) var(--bi-space-xs2);
}
.colfilter-range__field input:focus-visible { outline: none; border-color: var(--acc); }

.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding:0;
  border: none;
  background: transparent;
  border-radius: var(--bi-radius-sm);
  color: var(--bi-text-secondary);
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.btn-icon:hover {
  background: var(--bi-bg-hover);
  color: var(--bi-text-primary);
}
.chart canvas{
  width: 100%;
}

/* Degrau extra da escada, para gráfico de DOIS PAINÉIS empilhados (histórico de
   preços: preço em cima, volume embaixo). Em 25rem os dois painéis somados, menos
   a faixa dos rótulos de mês inclinados, deixavam ~11rem para o preço — apertado
   demais para uma linha com rótulo em cada ponto. */
.chart--xl     { height: 34rem; }
.chart--tall   { height: 25rem; }
.chart--medium { height: 18.75rem; }
.chart--short  { height: 17.5rem; }

/* ==========================================================================
   12. WATERFALL
   ========================================================================== */

/* Mapa UF — card e corpo preenchem a altura definida pelo align-items-stretch da row */
[data-bi-section="mapa-uf"] .card {
  display: flex;
  flex-direction: column;
}
[data-bi-section="mapa-uf"] .card-body {
  flex: 1;
  min-height: 0;
}
[data-bi-section="mapa-uf"] .mapa {
  height: 100%;
}

/* Cascata de Margens — estica para igualar altura da tabela UN */

[data-bi-section="cascata"] .card {
  display: flex;
  flex-direction: column;
}
[data-bi-section="cascata"] .card-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 17.5rem;
}

/* (`.pill--empresa` removido — bloco 100% morto. Declarava fundo preenchido
   `--command` e ativo `--positive`; media-se cinza da base em produção, porque a
   base `.pill` do bloco "statement pill look" tinha `!important` (removido na
   fase 2 do saneamento). O "visual
   diferenciado" nunca chegou à tela. As linhas de empresa são `.checkrow` como
   as demais. Decisão do Elyan em 2026-07-29: apagar, não ressuscitar. */

/* ==========================================================================
   13. HEATMAP
   ========================================================================== */

.heatmap-grid {
  overflow-x: auto;
}

.heatmap-table {
  border-collapse: separate;
  border-spacing: 3px;
  font-size: var(--bi-fs-caption);
  min-width: 100%;
}

.heatmap-table th {
  padding:var(--bi-space-2xs) var(--bi-space-sm);
  font-weight: var(--bi-fw-semibold);
  color: var(--bi-text-secondary);
  white-space: nowrap;
  text-align: center;
}

.heatmap-table th:first-child {
  text-align: left;
}

.heatmap-table td {
  padding:var(--bi-space-xs2) var(--bi-space-sm);
  border-radius: var(--bi-radius-sm);
  text-align: center;
  white-space: nowrap;
  font-family: var(--bi-font-mono);
  font-variant-numeric: tabular-nums;
  transition: filter 0.15s;
}

.heatmap-table td:first-child {
  font-family: var(--sans);
  font-weight: var(--bi-fw-semibold);
  color: var(--bi-text-secondary);
  background: transparent !important;
  text-align: left;
}

.heatmap-table td:hover {
  filter: brightness(0.88);
}

/* Célula do Ritmo: padding reduzido para acomodar o gauge */

/* ==========================================================================
   15. PILLS / FILTERS (light background variants)
   ========================================================================== */

/* Versão padrão (fundo claro) — usada fora do command bar */

/* === PILL — base única =======================================================
   Chip de filtro/ação. Cor, fundo, borda e raio moravam num bloco `!important`
   lá embaixo ("filter chips → statement pill look"), o que invertia a cascata:
   `!important` num seletor (0,1,0) vencia TODA regra mais específica, e cada
   contexto que precisava divergir tinha de empilhar o seu próprio `!important`
   depois. Voltaram para cá, sem `!important` — contexto (0,2,0)/(0,3,0) e estado
   voltam a vencer por especificidade, como o CSS já faria sozinho.
   As linhas de seleção do popover NÃO são pill: ver §CHECKROW. */
.pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding:var(--bi-space-3xs) 0.5rem;
  font-size: var(--bi-fs-label);
  font-weight: var(--bi-fw-medium);
  border: var(--bs-border-width) solid var(--bi-border-color);
  background: var(--bi-bg-hover);
  color: var(--bi-text-secondary);
  border-radius: var(--bs-border-radius-pill);
  cursor: pointer;
  transition: all .12s;
  white-space: nowrap;
  user-select: none;
  line-height: 1.4;
}

.pill:hover {
  background: var(--bi-bg-surface);
  border-color: var(--bi-border-color-heavy);
  color: var(--bi-text-primary);
}

/* (`.pill--active` base removido: era 100% morto — declarava fundo `--command`
   e perdia para o `!important` da base. Ressuscitá-lo como regra global pintaria
   de ativo contextos que hoje NÃO pintam, mudando pixel. O estado ativo continua
   escopado aos três contextos que realmente o usam, mais abaixo.) */

/* ==========================================================================
   16. RISCO DE CAIXA — caixas coloridas por threshold
   ========================================================================== */

/* ==========================================================================
   17. TOGGLE DEVOLUÇÕES
   ========================================================================== */

/* Os switches "Considerar devoluções" e "Formatar número?" vivem no MESMO grupo,
   à direita do topbar (#fcds-toggles, montado por fcds-filterbar.js). São
   .form-check.form-switch do Bootstrap puros, agrupados por utilitários
   (d-flex/gap-3/ms-auto) — nenhuma regra própria aqui. */

.mov-toggle-caption {
  font-size: var(--bi-fs-caption);
  color: var(--bi-text-secondary);
  margin-left:var(--bi-space-xs);
  font-family: var(--bi-font-mono);
}

/* ==========================================================================
   18. PROGRESS MARGIN — colunas MB% e MC% na tabela de NFs
   ========================================================================== */

/* (variantes --sucesso/--aviso/--perigo removidas — o JS só emite
   progress-margin--neutral; nunca as coloridas.) */

/* neutral: MB/MC % carry no value direction — pct in ink, bar in the slate accent */

/* Desktop: tuck the MB/MC margin cell into the right-aligned numeric rhythm (its cell is
   text-align:right) and tighten it for the denser desktop table — keeps the magnitude bar.
   Mobile keeps the centered, roomier layout above. */
@media (min-width:768px){

}

/* ==========================================================================
   19. MODAL — Detalhes da Nota Fiscal
   ========================================================================== */

/* Chrome de `.modalbox` removido — todos os modais usam o shell Bootstrap
   (biUtils.abrirModal). Sobrevive só a classe de CONTEÚDO `.modalbox__subtitulo`
   (subtítulo no header, usada por NF/dre-steel). */
.modalbox__subtitulo {
  font-size: var(--bi-fs-body);
  color: var(--bi-text-secondary);
  margin-top:var(--bi-space-3xs);
  font-family: var(--bi-font-mono);
}

/* ==========================================================================
   20. ACCORDION — removido (colapse de seções não é necessário)
   ========================================================================== */

/* (accordion removed) */

/* ==========================================================================
   21. SKELETON (loading placeholders)
   ========================================================================== */

/* .skeleton / .skeleton--chart / .skeleton--text removidos — skeleton unificado no
   Bootstrap .placeholder (utils.js SKELETON_HTML + carregando/carregandoSecao). */

/* ==========================================================================
   21b. LOGO LOADER (Four Group signature loading state — used em F.BI)
   ========================================================================== */

/*
 * Loader em modo overlay: o container alvo recebe data-bi-loading="<size>",
 * que aplica position:relative + min-height. O loader em si fica sobreposto
 * com inset:0, deixando o conteúdo embaixo intacto (apenas escondido pelo bg).
 *
 * Estrutura HTML (injetada via biUtils.aplicarLoaderEm):
 *   <div class="logo-loader" role="status" aria-busy="true" aria-live="polite">
 *     <div class="logo-loader__base"></div>
 *     <div class="logo-loader__mask"><div class="logo-loader__fill"></div></div>
 *   </div>
 */

[data-bi-loading]            { position: relative; }
[data-bi-loading="banda"]    { /* KPI band: altura natural das células, sem reserva */ }
[data-bi-loading="tape"]     { min-height: 11.75rem; }
[data-bi-loading="chart"]    { min-height: 22.5rem; }
[data-bi-loading="board"]    { min-height: 30rem; }

.logo-loader {
  position: absolute;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;   /* clipa o logo em containers baixos (faixa KPI, modo banda) */
  background: var(--bi-bg-surface);
  border-radius: var(--bi-radius-md);
}

/* Logo "4" dimensionado pela ALTURA do container (não largura fixa): escala
   sozinho em todo modo — proeminente em board/chart, encolhe e cabe na faixa
   KPI (banda). aspect-ratio casa o logo.svg real (1311×1316). O wrapper próprio
   do despesas_comex sobrescreve width/height (100%) com specificity maior. */
.logo-loader__base,
.logo-loader__mask {
  position: absolute;
  width: auto;
  height: min(46%, 150px);
  aspect-ratio: 1311 / 1316;
  -webkit-mask-image: url("../img/logo.e911c70f8d2a.svg");
          mask-image: url("../img/logo.e911c70f8d2a.svg");
  -webkit-mask-size: contain;
          mask-size: contain;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: center;
          mask-position: center;
}

.logo-loader__base {
  background: var(--bi-loader-base);
}

.logo-loader__mask {
  overflow: hidden;
}

.logo-loader__fill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 0%;
  /* PRETO, e dito aqui: a logo do carregamento é a marca, não um acento nem um
     dado — não segue a cor de ação do app. Lia --command (tinta de magnitude de
     DADO), que por sua vez estava aliasado ao acento; era esse encadeamento que
     fazia a logo mudar de cor junto com botão e paginação. */
  background: var(--ink);
  animation: logo-loader-trickle 2.2s ease-in-out 0.15s infinite alternate;
}

@keyframes logo-loader-trickle {
  0%   { width: 8%; }
  100% { width: 88%; }
}

@media (prefers-reduced-motion: reduce) {
  .logo-loader__fill {
    animation: none;
    width: 50%;
  }
}

/* ==========================================================================
   22. ERROR + EMPTY STATE
   ========================================================================== */

.state-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap:var(--bi-space-sm);
  padding:var(--bi-space-lg);
  text-align: center;
  color: var(--bi-text-secondary);
}

.state-error[role="alert"] {
  border: var(--bi-border);
  border-left: 4px solid var(--negative-text);
  border-radius: var(--bi-radius-md);
  background: var(--negative-subtle);
}

.state-error__mensagem {
  font-size: var(--bi-fs-body);
  color: var(--bi-text-secondary);
}

.state-error__botao-retry {
  display: inline-flex;
  align-items: center;
  gap:0.25rem;
  padding:var(--bi-space-xs) var(--bi-space-md);
  font-size: var(--bi-fs-label);
  font-weight: var(--bi-fw-semibold);
  color: var(--positive);
  background: transparent;
  border: var(--bs-border-width) solid var(--positive);
  border-radius: var(--bi-radius-sm);
  cursor: pointer;
  transition: background var(--bi-transition-fast), color var(--bi-transition-fast);
}

.state-error__botao-retry:hover {
  background: var(--positive);
  color: var(--bi-text-on-accent);
}

.state-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap:var(--bi-space-sm);
  padding:var(--bi-space-2xl) var(--bi-space-md);
  text-align: center;
  color: var(--bi-text-muted);
  font-size: var(--bi-fs-body);
}

/* Canonical empty state inside a table body — see biUtils.mostrarEmptyLinha */
.state-empty-row {
  text-align: center;
  color: var(--bi-text-muted);
  font-size: var(--bi-fs-body);
  padding:var(--bi-space-lg) var(--bi-space-md);
}
/* ── Badge de frescor ("atualizado em X") — dot + texto ──────────────────────
   Compartilhado; substitui .gc-fresh/.mi-fresh page-scoped. */
.fresh { display: inline-flex; align-items: center; gap:0.25rem; font-size: var(--bi-fs-caption); color: var(--bi-text-secondary); }
.fresh[hidden] { display: none; }
.fresh__dot { width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--positive-text); flex-shrink: 0; }

/* ── Mercado de Importação — específico da tela ──────────────────────────────
   Rebranding como "briefing competitivo" (inspiração: o deck de preços Logcomex
   FOUR×AWA×South Service): masthead do relatório → veredito de preço (a tese) →
/* ── Masthead: identidade do relatório (produto em display condensado) + faixa
   de tamanho do mercado como antetítulo. Substitui a antiga banda de 6 KPIs que
   "parecia planilha": aqui os totais são contexto editorial.
   O seletor desta regra foi perdido — a linha acima abria comentário sem fechar
   e engolia tanto o nome do seletor quanto as declarações (display/flex-wrap/
   padding-bottom/border-bottom), que nunca foram parseadas. Órfãs, removidas. */

/* Rótulos de banda: agrupam a estrutura do mercado abaixo do veredito competitivo
   (Quem importa → De onde vem). Espaçamento generoso no topo cria a hierarquia
   (sem régua/borda — a linha dura é o tell do ERP legado que rejeitamos). Mesma
   convenção page-scoped do simulador (.simx-secao__titulo). */

/* ==========================================================================
   23. ACCESSIBILITY
   ========================================================================== */

.pill:focus-visible,
.state-error__botao-retry:focus-visible,
:is(.command-bar,
.secondary-bar) .pill:focus-visible{
  outline: 2px solid var(--positive);
  outline-offset: 2px;
}

/* drill-down rows are now keyboard-operable (role=button + tabindex via JS);
   give them the same focus ring instead of the black UA default. */
.seg-row:focus-visible,
[data-canal]:focus-visible {
  outline: 2px solid var(--positive);
  outline-offset: -2px;
  border-radius: var(--bs-border-radius-lg);
}

/* controls that previously had no visible keyboard focus (WCAG 2.4.7):
   icon buttons, modal close, map sort toggles, keyboard-operable map ranking rows. */
.btn-icon:focus-visible,
#mapa-sort-desc:focus-visible,
#mapa-sort-asc:focus-visible {
  outline: 2px solid var(--positive);
  outline-offset: 2px;
}
.mapa-ranking__item:focus-visible {
  outline: 2px solid var(--positive);
  outline-offset: -2px;
  border-radius: var(--bs-border-radius);
}

/* visually-hidden, screen-reader-only (table captions, etc.) */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding:0; margin:-0;
  overflow: hidden; clip: rect(0, 0, 0, 0);
  white-space: nowrap; border: 0;
}

/* ==========================================================================
   24. ANIMATIONS
   ========================================================================== */

@keyframes bi-fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

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

/* @keyframes bi-shimmer removido — sem consumidores (skeleton unificado no Bootstrap). */

/* ==========================================================================
   26. DRE TOGGLE RESUMIDO/DETALHADO
   ========================================================================== */

/* ==========================================================================
   27. MAPA DE FATURAMENTO POR ESTADO
   ========================================================================== */

.mapa {
  display: grid;
  grid-template-columns: 3fr 2fr;
  gap:var(--bi-space-lg);
  align-items: stretch;
}

/* map column fills the card height so the choropleth is tall (not a wide-short
   strip) at full width; the legend is docked over the map's bottom-left as a
   compact chip (não mais uma barra solta de largura total abaixo do mapa). */
.mapa__map-col {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.mapa__map-wrap {
  flex: 1 1 auto;
  min-height: 17.5rem;
  border-radius: var(--bi-radius-md);
  overflow: hidden;
  /* Cria CONTEXTO DE EMPILHAMENTO. Sem ele, os panes do Leaflet (z-index 400) e
     seus controles (1000) são resolvidos contra a raiz da página e cobrem a
     topbar: dropdowns de filtro e o calendário do flatpickr abrem por baixo do
     mapa. `overflow:hidden` NÃO cria contexto — `position` + `z-index`
     numérico criam. Corrige /faturamento/ pelo mesmo caminho. */
  position: relative;
  /* z-index:0 + position:relative = SC deliberado: confina panes Leaflet (400) e
     controls (1000) abaixo do conteúdo. NÃO remover position/z — reabre o vazamento. */
  z-index: 0;
  /* Confina as panes do Leaflet (overlayPane z-index 400) num stacking context
     próprio, abaixo do command-bar sticky (z-index 200). Sem isto o choropleth
     pinta sobre os filtros ao rolar a página. */
  isolation: isolate;
}

#mapa-map-wrap.leaflet-container,
#mapa-map-wrap {
  background: var(--bi-bg-surface) !important;
  border-radius: var(--bi-radius-md);
  font-family: var(--bi-font-sans);
}

/* Fullscreen map — class-driven (.is-fullscreen), set by faturamento.js. The
   class (not :fullscreen) carries the layout so it works on every device incl.
   iOS Safari, where the Fullscreen API can't target a <div>. #card-mapa IS the
   FCDS .card (no descendant .cardbox / .cardbox__body); it holds .card-hd + .mapa. */
#card-mapa.is-fullscreen {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  margin:0;
  width: auto;
  height: auto;
  max-width: none;
  border-radius: 0;
  display: flex;
  flex-direction: column;
  background: var(--bi-bg-surface);
  padding:var(--bi-space-md);
  overflow: hidden;
}

#card-mapa.is-fullscreen .mapa {
  flex: 1;
  min-height: 0;
  align-items: stretch;
}

#card-mapa.is-fullscreen .mapa__map-wrap {
  height: 100%;
}

#card-mapa.is-fullscreen .mapa__ranking {
  height: 100%;
  overflow-y: auto;
}

.mapa__tooltip {
  font-size: var(--bi-fs-caption);
  min-width: 10rem;
  line-height: 1.5;
}

.mapa__tooltip-uf {
  font-weight: var(--bi-fw-bold);
  font-size: var(--bi-fs-body);
  margin-bottom:var(--bi-space-3xs);
}

.mapa__pills {
  display: flex;
  gap:var(--bi-space-xs);
  margin-bottom:var(--bi-space-md);
}

.mapa__ranking {
  display: flex;
  flex-direction: column;
  gap:var(--bi-space-2xs);
  overflow-y: auto;
}

.mapa-ranking__item {
  display: flex;
  align-items: center;
  gap:var(--bi-space-xs2);
  min-width: 0;
}

.mapa-ranking__uf {
  width: 1.5rem;
  flex-shrink: 0;
  font-weight: var(--bi-fw-semibold);
  font-size: var(--bi-fs-caption);
  color: var(--bi-text-primary);
  text-align: right;
}

/* ── Barra de proporção ──────────────────────────────────────────────────────
   Trilho + preenchimento com largura em %. Componente compartilhado: três telas
   (contas-a-receber, inadimplência, mapa) escreviam a sua com os MESMOS tokens
   (--line-2, radius -sm) divergindo só em altura, cor e duração da transição —
   divergências que ninguém decidiu, resultado de terem sido escritas em dias
   diferentes por quem não sabia da outra.

   NÃO cobre `.mx-h2h__track` nem `.mb-cell__bar`: essas duas montam sobre o
   `.progress` do Bootstrap e só o tematizam. Já são reuso; trocá-las por CSS
   próprio andaria para trás.

   Calibragem por custom property, não por classe modificadora — a altura e a
   cor variam por chamador, e criar `.barra--fina`/`.barra--verde` só moveria o
   problema para o nome. */
.barra {
  height: var(--barra-altura, 0.25rem);
  background: var(--line-2);
  border-radius: var(--bs-border-radius-sm);
  position: relative;
  min-width: 0;
}
.barra__fill {
  height: 100%;
  max-width: 100%;
  border-radius: inherit;
  background: var(--barra-cor, var(--command));
  /* 0,4s: as três divergiam (0,5s / 300ms / nenhuma). Um valor só, no meio. */
  transition: width 0.4s ease;
}

.mapa-ranking__bar-wrap { --barra-altura: 0.5rem; flex: 1; overflow: hidden; }

/* ranking rows are now a keyboard-operable proxy for the choropleth */
.mapa-ranking__item {
  cursor: pointer;
  padding:0 0.25rem;
  border-radius: var(--bs-border-radius);
  transition: background .12s;
}
.mapa-ranking__item:hover { background: var(--bi-bg-hover); }
.mapa-ranking__rank {
  width: 1.625rem; flex-shrink: 0; text-align: right; white-space: nowrap;
  font-family: var(--bi-font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--bi-fs-caption); color: var(--bi-text-muted);
}
.mapa-ranking__share {
  width: 2.625rem; flex-shrink: 0; text-align: right;
  font-family: var(--bi-font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--bi-fs-caption); color: var(--bi-text-muted);
}

/* metric colour legend for the choropleth (added for WCAG 1.4.1) */
/* map loading / empty / error overlay — covers the map area only (sibling of the
   map-wrap inside the position:relative map-col). Map-shaped, not a generic block. */
.mapa__state {
  position: absolute; inset: 0; z-index: 520;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap:var(--bi-space-sm); padding:var(--bi-space-lg);
  background: var(--bi-bg-surface);
  border-radius: var(--bi-radius-md);
  text-align: center;
}
.mapa__state[hidden] { display: none; }
/* Forma orgânica do loader do mapa; a pulsação vem do Bootstrap .placeholder-glow
   (mapa.js adiciona .placeholder a este elemento) — sem @keyframes mapa-shimmer. */
.mapa__state-skel {
  width: min(62%, 300px); aspect-ratio: 1 / 1; border-radius: 50% 46% 48% 52% / 44% 50% 50% 56%;
  background: var(--line-2);
}
.mapa__state-cap { font-size: var(--bi-fs-caption); color: var(--bi-text-muted); display: flex; align-items: center; gap:0.25rem; }
.mapa__state-msg { display: flex; flex-direction: column; align-items: center; gap:0.5rem; color: var(--bi-text-secondary); font-size: var(--bi-fs-body); max-width: 18.75rem; }
.mapa__state-msg i { font-size: 1.6rem; color: var(--bi-text-muted); }

.mapa__state-retry {
  margin-top:0.25rem; padding:0.25rem 0.5rem; border: var(--bs-border-width) solid var(--bi-border-color);
  border-radius: var(--bi-radius-sm); background: var(--bi-bg-surface);
  font-size: var(--bi-fs-caption); font-weight: var(--bi-fw-semibold); color: var(--bi-text-secondary); cursor: pointer;
}
.mapa__state-retry:hover { background: var(--bi-bg-hover); }

/* docked over the map (bottom-left), compact chip — not a full-width orphan bar */
/* Docked as a slim horizontal strip BELOW the map (in flow), not an absolute overlay:
   the overlay covered the populated south (SP/RS/SC/PR) and clipped the max value.
   Row layout wraps gracefully and gives the mono numbers room. */
.mapa__legend {
  display: flex; flex-flow: row wrap; align-items: center;
  gap:0.25rem var(--bi-space-md);
  margin-top:var(--bi-space-xs2);
  padding:0;
  font-size: var(--bi-fs-caption);
}
.mapa__legend[hidden] { display: none; }
.mapa__legend-title { font-weight: var(--bi-fw-semibold); color: var(--bi-text-secondary); }
.mapa__legend-scale { display: flex; align-items: center; gap:0.25rem; }
.mapa__legend-ramp { flex: 1; min-width: 6rem; height: 0.5rem; border-radius: var(--bs-border-radius-sm); border: var(--bs-border-width) solid var(--bi-border-color); }
.mapa__legend-min, .mapa__legend-max { font-family: var(--bi-font-mono); color: var(--bi-text-muted); white-space: nowrap; }
.mapa__legend-nodata { display: inline-flex; align-items: center; gap:0.25rem; color: var(--bi-text-muted); }
.mapa__legend-swatch { width: 0.75rem; height: 0.75rem; border-radius: var(--bs-border-radius-sm); border: var(--bs-border-width) solid var(--bi-border-color); display: inline-block; flex-shrink: 0; }

.mapa-ranking__valor {
  flex-shrink: 0;
  font-size: 0.875rem;
  font-family: var(--bi-font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--bi-text-secondary);
  text-align: right;
  min-width: 3rem;
}

/* ==========================================================================
   29. TABELA FATURAMENTO POR SEGMENTO (Visão Operacional)
   ========================================================================== */

/* .table.table-sm do Bootstrap; sobra o corpo tipográfico da tela. */
.seg-table { font-size: var(--bi-fs-caption); }

.seg-table thead th {
  padding:var(--bi-space-xs2) 0.5rem;
  font-family: var(--bi-font-display);
  font-size: var(--bi-fs-label);
  font-weight: var(--bi-fw-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--bi-text-secondary);
  border-bottom: 2px solid var(--line);
  white-space: nowrap;
  background: var(--bi-surface-card);
}

.seg-row td {
  padding:var(--bi-space-sm) 0.5rem;
  border-bottom: var(--bs-border-width) solid var(--line);
  vertical-align: middle;
}

.seg-row:last-child td {
  border-bottom: none;
}

.seg-row:hover td {
  background: var(--surf-2);
}

.seg-name {
  font-family: var(--bi-font-display);
  font-weight: var(--bi-fw-semibold);
  font-size: var(--bi-fs-body);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--bi-text-primary);
  white-space: nowrap;
}

/* .progress do Bootstrap; só a geometria (altura fina, largura máx, raio) fica
   aqui — width e cor da barra (.progress-bar) são data-driven por linha (JS). */
.seg-progress {
  height: 0.1875rem;
  max-width: 6.25rem;
  --bs-progress-bg: var(--line-2);
  --bs-progress-border-radius: var(--bs-border-radius-sm);
}

/* Linha TODOS */
.seg-todos .seg-name {
  font-weight: 700;
}

.seg-todos td {
  border-bottom: 2px solid var(--line);
  background: var(--surf-2);
}

/* ==========================================================================
   30. TABELA UN — SELEÇÃO PARA CASCATA DE MARGENS
   ========================================================================== */

.seg-row {
  cursor: pointer;
}

.seg-row:hover td {
  background: var(--surf-2);
}

/* Hint no cabeçalho da tabela UN */

/* ==========================================================================
   31. RESPONSIVE
   ========================================================================== */

/* ── Mobile: command bar não é sticky + Row 1 não quebra linha ────────────
   Breakpoint 767.98px = Bootstrap md − 0.02 (alinha com d-md-none/d-md-flex).
   Estender position:static até aqui evita o bloco sticky em landscape phone. */
@media (max-width: 767.98px) {
  /* Row 1 (título + período + buscar + filtros) não pode quebrar linha:
     6 colunas sticky + elementos de controle já consomem toda a tela.
     overflow-x:auto garante acesso sem layout quebrado. */
  .command-bar__filters > .command-bar__row:not(.command-bar__row--colapsavel) {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .command-bar__filters > .command-bar__row:not(.command-bar__row--colapsavel)::-webkit-scrollbar {
    display: none;
  }

  /* Título pode encolher para caber ao lado dos controles */

  /* Rows 2–3 (UN + Sub-seg): ocultas por padrão, abertas pelo botão "Filtros" */
  .command-bar__row--colapsavel {
    display: none;
  }
  .command-bar__row--colapsavel.is-show {
    display: flex;
  }
}

/* ── Viewport baixo (landscape phone): barra de filtros não pode comer a tela ─
   Celular deitado é largo (>768px → layout desktop) mas baixo (~390px). A barra
   desktop (grade multi-ano + UN + sub-segmento) chega a 92% da altura e, sticky,
   nunca sai de cena. Aqui tiramos o sticky e damos teto + scroll interno, sem
   tocar markup nem as classes d-md-* (que são por largura). */

@media (max-width: 576px) {
  .command-bar__filters {
    gap:var(--bi-space-xs);
  }

  /* Esconder labels de filtro — pills são autoexplicativas */
  .filter-group__label {
    display: none;
  }

  /* Título redundante em portrait phone — aba do browser já identifica a página */

  /* ── DataTables toolbar: stack vertical, search ocupa largura total ─────── */
  .datatable .datatable-toolbar {
    flex-direction: column;
    align-items: stretch;
    gap:var(--bi-space-xs);
  }
  .datatable .datatable-toolbar__right {
    display: flex;
    gap:var(--bi-space-xs);
  }
  /* Length select ("Mostrar N entradas") irrelevante em mobile — esconder */
  .datatable .dataTables_length {
    display: none;
  }
  .datatable .dataTables_filter {
    flex: 1;
  }
  .datatable .dataTables_filter label {
    display: flex;
    width: 100%;
    white-space: normal;
  }
  .datatable .dataTables_filter input {
    flex: 1;
    min-width: 0 !important;
    width: 100% !important;
  }
  /* Bottom bar: info + paginação empilhados */
  .datatable .datatable-bottom {
    flex-direction: column;
    align-items: flex-start;
    gap:var(--bi-space-xs);
    padding:var(--bi-space-xs) var(--bi-space-sm);
  }
  /* ─────────────────────────────────────────────────────────────────────── */

  .kpi-band {
    grid-template-columns: 1fr 1fr;
    margin:0 0 var(--bi-space-md);
  }

  .section-anchor {
    margin:var(--bi-space-lg) var(--bi-space-sm) var(--bi-space-sm);
  }
}

/* ==========================================================================
   26. ESTOQUE — Drill panels, badges, treemap interativo
   ========================================================================== */

/* Badge entrada/saída (movimentos) — Entrada/Saída is a record TYPE, not a value
   direction, so these carry no direction hue (neutral, per Step 3 contract). */

/* Badges de cobertura (risco visual): canonical .badge--success/danger/warning/info
   already defined above (~L725) with identical tokens — duplicate block removed. */

/* Drill panels — slide-in, agora .card (bg/border/radius/sombra do primitivo +
   .card-accent-start p/ a faixa dinâmica; .card-header/.card-body no template
   cobrem o cabeçalho/corpo, ver movimentacao.js). Residual: a animação de
   entrada e a margem entre painéis (sem primitiva Bootstrap p/ nenhum dos 2). */
.drill-panel {
  animation: biDrillSlideIn 300ms ease-out both;
  margin:var(--bi-space-sm) var(--bi-space-lg);
}

.drill-panel__titulo {
  font-family: var(--bi-font-display);
  font-size: var(--bi-fs-label);
  font-weight: var(--bi-fw-semibold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bi-text-secondary);
}

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

/* Drill breadcrumb — botão voltar */
.drill-back {
  cursor: pointer;
  color: var(--bi-text-secondary);
  font-family: var(--sans);
  font-size: var(--bi-fs-label);
  font-weight: var(--bi-fw-medium);
  background: none;
  border: none;
  padding:0;
  transition: color var(--bi-transition-fast);
}
.drill-back:hover { color: var(--bi-text-primary); }
/* Variante de ACENTO. O `.drill-back` padrão nasce em tinta fraca porque vive
   dentro de um drill, onde já há um título forte ao lado. Quando ele é o
   PRIMEIRO controle de uma superfície — a saída de uma tela de trabalho — a
   tinta fraca o faz ler como desabilitado. Aqui ele é um caminho, e caminho tem
   a cor do acento. */
.drill-back--acento { color: var(--acc-ink); font-weight: 600; }
.drill-back--acento:hover { color: var(--acc); }
.drill-back--acento:focus-visible { outline: 2px solid var(--acc); outline-offset: 2px; border-radius: var(--r-sm); }

/* Drill close button */
.drill-close {
  cursor: pointer;
  background: none;
  border: none;
  color: var(--bi-text-muted);
  font-size: 1.1rem;
  line-height: 1;
  padding:var(--bi-space-3xs);
  border-radius: var(--bi-radius-sm);
  transition: color var(--bi-transition-fast), background var(--bi-transition-fast);
}
.drill-close:hover {
  color: var(--negative-text);
  background: var(--negative-subtle);
}

/* Table row clicável (drill) */
.row-clickable {
  cursor: pointer;
  transition: background var(--bi-transition-fast);
}
.row-clickable:hover {
  background: var(--bi-bg-hover);
}

.row-clickable:active td {
  background: var(--bi-bg-active);
}

/* Drill hint — instrução progressiva no L0 */
.drill-hint {
  font-size: var(--bi-fs-caption);
  color: var(--bi-text-muted);
  text-align: center;
  padding:var(--bi-space-xs) 0;
  min-height: 1.5em;
  transition: opacity var(--bi-transition-fast);
}

/* Barra secundária de controles (período / toggles / busca) — já era a receita
   exata do .card (glass/sh-glass = surf/none, ver tokens), então virou
   .card.card-body + utilities Bootstrap direto no template (d-flex/flex-row/
   align-items-center/gap-2/flex-wrap/mb-3). Zero residual: a classe
   `.secondary-bar` só permanece na marcação porque `:is(.command-bar,
   .secondary-bar) .pill` (acima) e a regra mobile de `.vr` (abaixo) a usam
   como seletor ancestral. */

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  .drill-panel { animation: none; }
}

/* ==========================================================================
   25. RESPONSIVE (original section continues)
   ========================================================================== */

@media (max-width: 768px) {
  .kpi-band {
    grid-template-columns: repeat(2, 1fr);
    margin:0 0 var(--bi-space-md);
  }

  /* MOBILE: step KPI numbers down + let grid cells shrink, so values stop
     clipping the cell edge (hero was 3rem / secondary 2rem — far too large in a
     ~185px cell). Page-agnostic: helps every .kpi-band page at once. */
  .kpi-band__cell { min-width: 0; }

  /* divisor vertical do topbar de filtros (Bootstrap .vr): esconder quando
     a linha quebra (flex-wrap) — evita traço solto entre grupos empilhados. */
  .command-bar__row .vr,
  .secondary-bar .vr {
    display: none;
  }
}

@media (max-width: 1200px) {
  .kpi-band {
    grid-template-columns: 1.2fr 1.4fr 1fr 1fr;
  }
}

/* MOBILE: the multi-col KPI band variants (5/4/3-col, used by estoques /
   inadimplencia / despesas_comex / fluxo via _kpi_cell.html) must ALSO collapse
   to 2-col on phones. Without this they kept their desktop column count at 390px
   and the secondary cells overlapped ("LIBERADOBLOQUEADO"). Placed after the
   ≤1200 block so it wins by source order. */

/* ==========================================================================
   26. FATURAMENTO — scoped overrides
   All rules here are gated by [data-pagina="faturamento"] so they do not
   leak to sister BI pages. See plan: /root/.claude/plans/inherited-toasting-kahn.md
   ========================================================================== */

/* --- Card header density --- */
.page[data-pagina="faturamento"] .card-header {
  padding:var(--bi-space-xs2) var(--bi-space-md);
}

/* --- Sinais Operacionais (PMR / Estoque / Inadimplência) --- */
.page[data-pagina="faturamento"] [data-bi-section="sinais-operacionais"] .kpi-tile {
  padding:0.5rem 1rem;
}

/* --- Evolução Temporal: tighten chart heights --- */
.page[data-pagina="faturamento"] [data-bi-section="evolucao-faturamento"] .chart--short {
  height: 13.75rem;
}
.page[data-pagina="faturamento"] [data-bi-section="evolucao-margem"] .chart--short {
  height: 10rem;
}

/* --- Top Produtos: chart fills the row height (driven by the Evolução stack),
       no fixed cap → no dead whitespace. See the flex-fill block below. --- */

/* --- Top Clientes + Mapa: the data-bi-section element IS the FCDS .card
       (card-hd + content). Height-bounded in block (f); make both flex columns so
       the list / map+ranking fill or scroll within — no dead whitespace, equal
       heights. --- */
.page[data-pagina="faturamento"] [data-bi-section="mapa-uf"] {
  display: flex;
  flex-direction: column;
}
.page[data-pagina="faturamento"] [data-bi-section="mapa-uf"] > .mapa {
  flex: 1 1 auto;
  min-height: 0;
}
.page[data-pagina="faturamento"] [data-bi-section="mapa-uf"] .mapa {
  grid-template-columns: 2fr 1fr;
}

/* --- Mapa por Estado: responsive header wrap --- */
.page[data-pagina="faturamento"] .mapa__header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap:var(--bi-space-sm) var(--bi-space-md);
}

.page[data-pagina="faturamento"] .mapa__controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap:var(--bi-space-sm);
  margin-left:auto;
}

@media (max-width: 991.98px) {
  .page[data-pagina="faturamento"] .mapa__controls {
    margin-left:0;
    width: 100%;
    justify-content: flex-start;
  }
  .page[data-pagina="faturamento"] .mapa__actions {
    margin-left:auto;
  }
}

/* :hover base removido — 100% coberto pela def global (5495: color !important) */

/* Canonical active indicator: accent-soft pill (not an underline).
   color/background movidos p/ def global !important (5496); só border-radius sobrevive. */

/* ============================================================
   Contas a Receber — Treasury Board
   ============================================================ */

/* KPI band -------------------------------------------------- */
/* O tape de 3 pilares virou a row de cartões canônica do app (Bootstrap
   .row > .col > .card, igual a despesas/faturamento) — layout, empilhamento no
   mobile e valência de cor saem de utilities. A antiga `.cr-chart-band` (15rem)
   existia porque nenhum degrau da escala canônica servia; hoje a altura sai do
   nº de buckets via biChartConfig.alturaPorCategoria, e a classe saiu. */

/* Board ----------------------------------------------------- */
.cr-board {
  display: flex;
  flex-direction: column;
  gap:0;
}

/* Row ------------------------------------------------------- */
.cr-row {
  display: grid;
  grid-template-columns: 16.25rem 1fr 10rem;
  align-items: center;
  padding:0.5rem var(--bi-space-md);
  border-bottom: var(--bi-border-subtle);
  border-left: 3px solid transparent;
  background: var(--bi-bg-surface);
  transition: background 0.1s;

  animation: cr-row-enter 0.25s ease both;
  animation-delay: calc(var(--i, 0) * 35ms);
}

@keyframes cr-row-enter {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .cr-row { animation-duration: 0ms !important; }
}

.cr-row:hover { background: var(--surf-2); }

.cr-row--abaixo  { border-left-color: var(--negative-text); }
.cr-row--acima   { border-left-color: rgba(5, 150, 105, 0.4); }

/* Identity column */
.cr-row__identity { min-width: 0; }

.cr-row__name-wrap {
  display: flex;
  align-items: center;
  gap:var(--bi-space-xs2);
}

.cr-row__name {
  font-family: var(--bi-font-display);
  font-size: 1rem;
  font-weight: 600;
  color: var(--command);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cr-row__meta {
  font-family: var(--bi-font-mono);
  font-size: 0.875rem;
  color: var(--bi-text-muted);
  margin-top:var(--bi-space-3xs);
  font-variant-numeric: tabular-nums;
}

/* Visual column */
.cr-row__visual { padding:0 var(--bi-space-md); }

.cr-row__valor {
  font-family: var(--bi-font-mono);
  font-size: 1rem;
  font-variant-numeric: tabular-nums;
  color: var(--command);
  margin-bottom:0.25rem;
}

.cr-row__meter-wrap {
  position: relative;
  margin-top:var(--bi-space-3xs);
  height: 0.25rem;
}

/* Extras da tela sobre a .barra compartilhada: o marcador de estouro e o
   rótulo de mínimo, que só o ranking de portadores tem. */
.cr-row__meter { --barra-altura: 0.25rem; --barra-cor: var(--positive-text); overflow: visible; }

.cr-row__meter[data-overflow="true"]::after {
  content: '';
  position: absolute;
  right: -2px;
  top: -2px;
  bottom: -2px;
  width: 0.125rem;
  background: var(--positive-text);
  border-radius: 0 var(--bs-border-radius-sm) var(--bs-border-radius-sm) 0;
}

.cr-row__meter-label {
  position: absolute;
  right: 0;
  top: -14px;
  font-family: var(--bi-font-mono);
  font-size: 0.875rem;
  color: var(--bi-text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Status column */
.cr-row__status { text-align: right; }

.cr-row__diff {
  display: block;
  font-family: var(--bi-font-display);
  font-size: 1rem;
  font-weight: 600;
  margin-top:var(--bi-space-3xs);
  font-variant-numeric: tabular-nums;
}

.cr-row__diff--acima  { color: var(--positive-text); }
.cr-row__diff--abaixo { color: var(--negative-text); }

/* Toggle Vencimentos (Não desc. ↔ Descontado) — variante azul, não vermelha */

/* Chart subtitle */
.cr-chart-subtitle {
  font-family: var(--bi-font-mono);
  font-size: 0.875rem;
  color: var(--bi-text-muted);
  letter-spacing: 0.04em;
  margin-top:0;
}

/* Row valor display with filho breakdown */
.cr-row__valor-wrap {
  display: flex;
  align-items: baseline;
  gap:var(--bi-space-sm);
  margin-bottom:0;
}

.cr-row__valor {
  font-family: var(--bi-font-mono);
  font-size: 1rem;
  font-variant-numeric: tabular-nums;
  color: var(--command);
}

.cr-row__valor-proprio {
  font-family: var(--bi-font-mono);
  font-size: 0.875rem;
  font-variant-numeric: tabular-nums;
  color: var(--bi-text-muted);
}

/* ============================================================
   Contas a Receber — Layout Containment (proportion refactor)
   ============================================================ */

/* A barra de participação tem teto PRÓPRIO: é limite de componente (uma barra
   de 1.500px não comunica proporção melhor que uma de 480px), não de página.
   Nada mais capa largura — a tela ocupa o espaço disponível. */
.cr-row__meter-wrap {
  max-width: 30rem;
}

/* ============================================================
   DESPESAS FINANCEIRAS (PSQ014)
   ============================================================ */

.df-venc--perigo {
    color: var(--negative-text);
    font-weight: 600;
}
.df-venc--aviso {
    color: var(--warning);
    font-weight: 600;
}
/* Mapa de cor semântica: perigo->danger, aviso->warning, neutro->info,
   primary->primary. Emitters re-classed in despesas_comex.js. */

/* Refresh button spinner state */
.btn-icon--loading i {
    animation: bi-spin 1s linear infinite;
}
@keyframes bi-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
    .btn-icon--loading i { animation: none; }
}

/* Despesas — doughnut + legenda: deixa a legenda quebrar/encolher no mobile para a
   coluna de % não cortar. (Veio do <style> inline do template, removido na migração
   do KPI band para cards Bootstrap.) */
@media (max-width: 768px) {
    /* legenda do doughnut (despesas + despesas_logistica usam os mesmos IDs) */
    #bi-distribuicao-container { flex-wrap: wrap; }
    #bi-distribuicao-legenda { min-width: 0; font-size: 0.875rem; }
}

/* Override KPI band: 4 colunas iguais (vs default 7) — evita overflow em 1024 */
[data-pagina="despesas_comex"] .kpi-band {
    grid-template-columns: repeat(5, 1fr);
}

@media (max-width: 992px) {
    [data-pagina="despesas_comex"] .kpi-band {
        grid-template-columns: repeat(2, 1fr);
    }
}

/* Painel de progresso determinado (df-progress) — substitui o loader durante o
   pipeline longo do despesas_comex; construído sobre .logo-loader. Consumidor
   único → namespaced global .df-progress* (sem escopo de página). */
.df-progress {
    position: absolute;
    inset: 0;
    z-index: 20;
    background: var(--bi-bg-surface);
    border-radius: var(--bi-radius-md);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap:var(--bi-space-sm);
    padding:clamp(3rem, 8vh, 3rem) var(--bi-space-lg);
    text-align: center;
}
.df-progress__logo-wrap {
    position: relative;
    width: clamp(120px, 22vw, 220px);
    aspect-ratio: 2048 / 342;
}
.df-progress__logo-wrap .logo-loader__base,
.df-progress__logo-wrap .logo-loader__mask {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}
.df-progress__title {
    font-family: var(--bi-font-display);
    font-size: var(--bi-fs-heading);
    font-weight: var(--bi-fw-bold);
    color: var(--bi-text-primary);
    letter-spacing: 0.02em;
    text-transform: uppercase;
    margin-top:var(--bi-space-sm);
}
.df-progress__message {
    font-size: 1rem;
    color: var(--bi-text-secondary);
    min-height: 1.2em;
    transition: opacity 0.2s;
}
.df-progress__logo-wrap .logo-loader__fill[data-determinate="true"] {
    animation: none;
    transition: width 0.4s ease;
}
.df-progress__meta {
    display: flex;
    gap:var(--bi-space-md);
    font-size: 0.875rem;
    color: var(--bi-text-muted);
    font-variant-numeric: tabular-nums;
    margin-top:var(--bi-space-xs);
}
.df-progress__hint {
    font-size: 0.875rem;
    color: var(--bi-text-muted);
    font-style: italic;
    margin-top:var(--bi-space-sm);
    max-width: 23.75rem;
    line-height: 1.4;
}

/* ── Drawer Lote Atual (despesas comex) ────────────────────────────── */
#df-lote-drawer {
  --bs-offcanvas-width: 22.5rem;
}

/* Células de estado por linha (favorito/borderô/pago) — consumidor único
   despesas_comex → namespaced global .df-col-*. */
.df-col-favorito,
.df-col-bordero,
.df-col-pago {
    white-space: nowrap;
    min-width: 2.5rem;
    text-align: center;
}
.df-col-bordero .form-check-input,
.df-col-pago .form-check-input {
    cursor: pointer;
    width: 1rem;
    height: 1rem;
    margin:0;
}
.df-col-bordero .form-check-input:disabled,
.df-col-pago .form-check-input:disabled {
    cursor: default;
}

/* Botão estrela de favorito (df-btn-fav) — consumidor único → global. */
.df-btn-fav {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--ink-4);
    font-size: 1rem;
    padding:0 var(--bi-space-3xs);
    line-height: 1;
    flex-shrink: 0;
    transition: color 0.15s;
}
.df-btn-fav:hover { color: var(--warning); }
.df-btn-fav:disabled { opacity: 0.5; cursor: default; }
.df-btn-fav.df-fav--ativo { color: var(--warning); }

/* Faturamento NF tables freeze identity-only (Ações·Data·NF) via `.stickcols`.
   Keep horizontal drag from scrolling the page on touch. */
@media (max-width:767.98px) {
  .datatable .datatable-scroll { overscroll-behavior-x: contain; }
}
/* ════════════════════════════════════════════════════════════════════════
   SIMULADOR DE VENDAS — "Instrumento de Margem" (dense / técnico)
   Subject = PRODUTO + PROPOSTA. A NF é só fonte auxiliar das alíquotas.
   Mono-dominante, monocromático + 1 acento (command), status só no veredito.
   Escopado sob .
   ════════════════════════════════════════════════════════════════════════ */

/* — Autocomplete de produto — */
/* flex-basis removido: dentro de .simx-secao (flex column) o basis virava
   ALTURA, reservando 280px fantasma abaixo do input. */
/* Seção do produto sobe na pilha p/ o dropdown não ficar atrás da "Sua proposta" */
#sim-secao-produto { position: relative; z-index: 20; }
.simx-ac { position: relative; width: 100%; }
/* Produto selecionado vira badge ocupando o campo de busca (input fica oculto) */
.simx-ac__chip {
    display: flex; align-items: center; justify-content: space-between; gap:0.5rem;
    width: 100%; box-sizing: border-box;
    padding:0.25rem 0.25rem 0.25rem 0.5rem;
    font: 700 0.8125rem var(--bi-font-mono); color: var(--command);
    background: var(--simx-tint);
    border: var(--bs-border-width) solid var(--command); border-radius: var(--bi-radius-sm);
}
.simx-ac__chip-txt {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Botão de limpar produto = .btn-close do Bootstrap. */
/* Lista = .dropdown-menu/.dropdown-item do Bootstrap; aqui só o encaixe
   sob o input (o menu não é aberto pelo componente Dropdown, e sim por
   d-none no JS — daí o `.show` fixo no markup). */
.simx-ac__results {
    position: absolute; top: calc(100% + 2px); left: 0; right: 0; z-index: 30;
    max-height: 17.5rem; overflow-y: auto;
}
/* Chips e avisos = .badge do design system (sobre o .badge do Bootstrap). */

/* — Cartão de NF no deck — */

/* — Alavancas (o editor da PROPOSTA) — */
.simx-lever {
    display: grid; grid-template-columns: 7rem 1fr 6.5rem 4rem; align-items: center; gap:0.5rem;
    padding:0.25rem 0; border-bottom: var(--bi-border-subtle);
}
.simx-lever__label { font-size: 0.875rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--bi-text-secondary); }
.simx-lever__slider { accent-color: var(--command); }
.simx-lever__num { text-align: right; font-family: var(--bi-font-mono); font-variant-numeric: tabular-nums; }
.simx-lever__delta { font-size: 0.875rem; font-variant-numeric: tabular-nums; text-align: right; color: var(--bi-text-muted); }

/* — Mini stepper (alvo) — */
/* stepper: ver .input-group mais abaixo */

/* ============================================================
   Simulador de Vendas — dashboard 2-col v5
   ============================================================ */

.simx-board {
    padding:var(--bi-space-md);
    display: grid;
    grid-template-columns: minmax(20rem, 22.5rem) minmax(22.5rem, 1fr) minmax(23.75rem, 1.15fr);
    grid-template-areas: "lado custos principal";
    gap:var(--bi-space-md) var(--bi-space-lg);
    align-items: stretch;
}
.simx-board__lado      {
    grid-area: lado;
    display: flex; flex-direction: column; gap:var(--bi-space-sm);
    justify-content: space-between;   /* espalha seções p/ alinhar a base com as outras colunas */
}
/* Coluna do meio — custos/negociação. Estica na altura da linha e distribui o
   conteúdo para ocupar o espaço (sem whitespace morto no topo, sem aperto). */
.simx-board__custos {
    grid-area: custos;
    align-self: stretch;
    display: flex; flex-direction: column; gap:var(--bi-space-md);
}
/* Card de alavancas cresce e espalha as linhas para preencher a coluna */
.simx-board__custos > .simx-secao {
    flex: 1 1 auto;
    justify-content: space-between;
    gap:0.5rem;
}
.simx-board__principal {
    grid-area: principal;
    display: flex; flex-direction: column; gap:var(--bi-space-sm);
}
.simx-board__filtros {
    display: flex; flex-wrap: wrap; gap:0.5rem; align-items: center;
}
.simx-board__nflista {
    display: flex; flex-direction: column; gap:0.25rem;
    max-height: 26.25rem; overflow-y: auto;
    padding-right:0.25rem;
}
.simx-board__placeholder {
    padding:1rem;
    background: var(--bi-bg-surface);
    border: var(--bs-border-width) dashed var(--bi-border-color);
    border-radius: var(--bi-radius-sm);
    color: var(--bi-text-muted);
    font-family: var(--bi-font-mono); font-size: 0.875rem;
    text-align: center;
}

@media (max-width: 992px) {
    .simx-board {
        grid-template-columns: 1fr;
        grid-template-areas: "lado" "custos" "principal";
    }
    .simx-board__custos { align-self: stretch; }
    .simx-board__nflista { max-height: 17.5rem; }
}

/* Seções de entrada (col 1/2) = controles. Recuam para fundo cinza + borda
   sutil, sem elevação, deixando o Demonstrativo (col 3, branco/sombra/acento)
   ser a única "figura" elevada. Inputs brancos por cima ganham contraste. */
.simx-secao {
    display: flex; flex-direction: column; gap:0.5rem;
    background: var(--bi-bg-hover);
    border: var(--bi-border-subtle); border-radius: var(--bi-radius-md);
    padding:var(--bi-space-sm) var(--bi-space-md);
}
.simx-secao__contador {
    font: 400 0.7rem var(--bi-font-mono); color: var(--bi-text-muted);
    text-transform: none; letter-spacing: 0;
}
.simx-secao__acao {
    align-self: flex-start; margin-top:0.25rem;
}
.simx-secao__titulo {
    font: 600 0.72rem/1 var(--bi-font-condensed, var(--bi-font-mono));
    text-transform: uppercase; letter-spacing: 0.1em;
    color: var(--bi-text-muted); margin:0 0 0.25rem 0;
}
.simx-campo {
    display: flex; flex-direction: column; gap:0.25rem;
}
.simx-campo__rotulo {
    font: 500 0.78rem var(--bi-font-condensed, var(--bi-font-mono));
    color: var(--bi-text-secondary);
}
.simx-campo__valor {
    display: inline-flex; align-items: center; gap:0.5rem;
}
.simx-campo__nota {
    font: 400 0.74rem var(--bi-font-mono);
    color: var(--bi-text-muted);
}
.simx-campo__nota--ativo {
    color: var(--command); font-weight: 700;
}
.simx-difal-legenda {
    margin:0.25rem 0 0 0; line-height: 1.35;
    color: var(--bi-text-muted); font-style: italic;
}
.simx-secao--modo {
    padding-bottom:0.5rem; border-bottom: var(--bs-border-width) solid var(--bi-border-color);
}
.simx-aliq-grid {
    display: grid; grid-template-columns: repeat(2, 1fr); gap:0.5rem 0.5rem;
    margin-top:0.5rem;
}
.simx-aliq {
    display: flex; flex-direction: column; gap:0.25rem;
}
.simx-aliq > span {
    font: 500 0.72rem var(--bi-font-condensed, var(--bi-font-mono));
    color: var(--bi-text-secondary);
}
/* Campos = .form-control/.form-select do Bootstrap; sobra só o do simulador. */
.simx-input--num { text-align: right; font-variant-numeric: tabular-nums; }

/* DRE — protagonista. Coluna 3 carrega a resposta (MB%); ganha moldura
   pesada, acento command no topo e elevação para puxar o olho dos painéis
   de entrada (col 1/2), que recuam. */
.simx-dre {
    background: var(--bi-bg-surface);
    border: var(--bi-border);
    border-top: 3px solid var(--command);
    border-radius: var(--bi-radius-md);
    padding:var(--bi-space-md) var(--bi-space-md) var(--bi-space-sm);
    box-shadow: var(--bi-shadow-md);
    display: flex; flex-direction: column; gap:0.25rem;
    flex: 1 1 auto;   /* DRE preenche a altura da col 3, base alinhada às demais */
}
.simx-dre__linha {
    display: grid; grid-template-columns: 1.5rem minmax(0, 1fr) auto 4.5rem;
    align-items: baseline; gap:0.5rem;
    font-family: var(--bi-font-mono); font-size: 1rem;
    color: var(--bi-text-primary);
}
.simx-dre__linha--sub,
.simx-dre__linha--muted {
    font-size: 0.875rem; color: var(--bi-text-secondary);
}
.simx-dre__op {
    text-align: right; color: var(--bi-text-muted); font-weight: 600;
}
.simx-dre__val { font-variant-numeric: tabular-nums; text-align: right; }
.simx-dre__pct {
    font-weight: 700; padding-left:0.5rem; text-align: right;
}
/* Alíquota efetiva aplicada na linha (% sobre a base do cálculo). Coluna direita
   de 4.5rem, alinhada com a coluna de MB%/MC%; tom secundário para não competir. */
.simx-dre__rate {
    padding-left:0.5rem; text-align: right;
    font-weight: 400; font-size: 0.875rem;
    color: var(--bi-text-muted); font-variant-numeric: tabular-nums;
}
/* Margem Bruta = herói da tela. O HERÓI é o % (curto): cresce ~1.9rem/800 e
   recebe a cor de status. O valor em R$ fica moderado e o rótulo encolhe
   (ellipsis) para nunca estourar a largura da coluna. */
.simx-dre__linha--mb {
    grid-template-columns: 1.5rem minmax(0, 1fr) auto auto;
    align-items: center;
    border-top: 2px solid var(--command);
    padding-top:0.5rem; margin-top:0.5rem;
    font-weight: 700; line-height: 1.1;
}
.simx-dre__linha--mb .simx-dre__label {
    font-size: 0.875rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.08em;
    color: var(--bi-text-secondary);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.simx-dre__linha--mb .simx-dre__val {
    font-size: 1.05rem; font-weight: 700;
}
.simx-dre__linha--mb .simx-dre__pct {
    font-size: 1.9rem; font-weight: 800; line-height: 1; white-space: nowrap;
}
.simx-dre__linha--mb[data-status="ok"]    { color: var(--positive-text); }
.simx-dre__linha--mb[data-status="aviso"] { color: var(--warning); }
.simx-dre__linha--mb[data-status="ruim"]  { color: var(--negative-text); }
.simx-dre__titulo {
    font: 700 0.88rem/1 var(--bi-font-condensed, var(--bi-font-mono));
    text-transform: uppercase; letter-spacing: 0.1em;
    color: var(--bi-text-secondary); margin:0 0 0.5rem 0;
}
.simx-dre__sub {
    margin:0.25rem 0 0.25rem 1rem;
    padding:0.25rem 0 0.25rem 0.5rem;   /* coluna % da sub-linha alinha com a das linhas principais */
    border-left: 2px solid var(--bi-border-color);
    display: flex; flex-direction: column; gap:0.25rem;
}
.simx-dre__sub-linha {
    display: grid; grid-template-columns: 1.5rem 1fr auto 4.5rem;
    align-items: baseline; gap:0.5rem;
    font-family: var(--bi-font-mono); font-size: 0.875rem;
    color: var(--bi-text-secondary);
}
.simx-dre__linha--subtotal {
    border-top: var(--bs-border-width) dashed var(--bi-border-color);
    padding-top:0.25rem; margin-top:0;
    font-weight: 600;
}
/* MC renderizada DENTRO do card do demonstrativo — continuação, não card separado */
.simx-dre__mc-bloco {
    margin-top:0.5rem; padding-top:0.5rem;
    border-top: var(--bs-border-width) solid var(--bi-border-color);
    display: flex; flex-direction: column; gap:0.25rem;
}
.simx-dre__titulo--mc {
    margin:0 0 0 0; font-size: 0.875rem; color: var(--bi-text-muted);
}

/* Banner de aviso (fallback global) */
/* Banner de aviso = .alert.alert-warning do Bootstrap. */

/* Bloco "Margem de negociação" */
.simx-negociar {
    background: var(--bi-bg-hover);
    border: var(--bi-border-subtle); border-radius: var(--bi-radius-md);
    padding:var(--bi-space-sm) var(--bi-space-md);
    display: flex; flex-direction: column; gap:0.25rem;
}
.simx-negociar__linha {
    display: grid; grid-template-columns: 1fr auto; gap:0.5rem;
    align-items: center;
    font-family: var(--bi-font-mono); font-size: 0.875rem;
}
.simx-negociar__nota {
    margin:0.25rem 0 0; font-size: 0.875rem; color: var(--bi-text-muted);
}
/* Valores que o vendedor leva pra mesa: preço mínimo e desconto máximo.
   Sobem de peso/escala para virar leitura de relance. */
#sim-solver-preco,
#sim-solver-desc {
    font-weight: 800; font-size: 1.1rem;
    font-variant-numeric: tabular-nums; color: var(--command);
}

/* Footer "base:" */
.simx-base {
    font: 400 0.74rem/1.3 var(--bi-font-mono);
    color: var(--bi-text-muted);
    border-top: var(--bs-border-width) dashed var(--bi-border-color);
    padding-top:0.5rem;
    display: flex; flex-wrap: wrap; gap:0.25rem 0.5rem; align-items: baseline;
}
.simx-base__rotulo {
    text-transform: uppercase; letter-spacing: 0.08em;
    font-size: 0.875rem; color: var(--bi-text-secondary);
}
.simx-base__disclaimer {
    flex-basis: 100%; margin:0 0 0; font-size: 0.875rem; line-height: 1.25;
}

/* — Chip DIFAL — */

/* Alavancas (sliders custo/frete/comissão/desconto) — sempre visíveis */
.simx-lever {
    display: grid; grid-template-columns: 7.5rem 1fr 5rem 3rem;
    align-items: center; gap:0.5rem;
    padding:0 0;
    font-family: var(--bi-font-mono); font-size: 0.875rem;
}
.simx-lever__num { height: 1.55rem; }
.simx-secao__acao { margin-top:0; }
.simx-lever__label { color: var(--bi-text-secondary); }
.simx-lever__num { height: 1.7rem; min-height: 1.7rem; padding:0 0.5rem; }
.simx-lever__delta {
    font-size: 0.875rem; text-align: right; color: var(--bi-text-muted);
}
.simx-lever__delta[data-estado="subiu"]  { color: var(--positive-text); }
.simx-lever__delta[data-estado="desceu"] { color: var(--negative-text); }

/* Stepper = .input-group.input-group-sm do Bootstrap; sobra o que o layout pede. */
/* input-group estica por padrão; aqui o stepper é um controle compacto. */
.simx-step .form-control { flex: 0 0 3.5rem; }
.simx-step input { font-family: var(--bi-font-mono); font-variant-numeric: tabular-nums; }

.simx-input--filtro { flex: 0 1 180px; }

@media (max-width: 992px) {
    .simx-board { padding:var(--bi-space-sm); gap:var(--bi-space-md); }
    .simx-lever { grid-template-columns: 5rem 1fr 4rem 2.5rem; }
}
@media (max-width: 576px) {
    .simx-lever__delta { display: none; }
    .simx-lever { grid-template-columns: 5rem 1fr 4rem; }
}
/* Vinha de um <style> inline em simulador.html — CSS autoral só mora aqui. */
@media (max-width: 768px) {
    .simx-secao--modo .simx-campo__valor { flex-wrap: wrap; row-gap:0.5rem; }
    .simx-deck { position: fixed; left: .5rem; right: .5rem; bottom: .5rem; width: auto; max-height: 80vh; }
    .simx-dre__linha--mb .simx-dre__pct { font-size: 1.5rem; }
    .simx-dre__linha--mb .simx-dre__val { font-size: 1rem; }
    .simx-step input { height: 2.5rem; min-height: 2.5rem; }
    .simx-lever__num { height: 2.5rem; min-height: 2.5rem; }
}

/* ════════════════════════════════════════════════════════════════════════
   Simulador de Vendas — revisão v6: tela em 1 viewport (sem scroll),
   picker de NF em deck sob demanda + sistema de movimento.
   Movimento: transform/opacity (60fps), easing out-quint/expo, respeita
   prefers-reduced-motion. Sem bounce/elastic.
   ════════════════════════════════════════════════════════════════════════ */
:root {
    --simx-ease:      cubic-bezier(0.22, 1, 0.36, 1);   /* out-quint */
    --simx-ease-expo: cubic-bezier(0.16, 1, 0.3, 1);    /* confiante */
    --simx-t-fast: 130ms;
    --simx-t:      220ms;
    --simx-t-slow: 360ms;
    /* `--command: var(--acc)` morava aqui, com o comentário "ninguém além do
       simulador lê var(--command)". Era falso, e caro: este bloco é :root, não
       o escopo do simulador, então o alias valia para o app inteiro — inclusive
       para .logo-loader__fill, a logo do carregamento. Foi por isso que --acc
       virou #0b0b0c: queriam a logo PRETA e empurraram o acento global para o
       preto até ela ficar. Sem o alias, --command volta ao near-black que o
       próprio nome promete (#2b3038) e a logo é preta sem arrastar ninguém. O
       simulador segue com o acento onde ele pediu acento, via --simx-tint. */
    --simx-tint:   color-mix(in oklch, var(--acc) 14%, transparent);
}

/* — Entrada: subida escalonada das seções no load — */
@keyframes simxRise {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: none; }
}
.simx-board__lado > *,
.simx-board__custos > *,
.simx-board__principal > article {
    animation: simxRise var(--simx-t-slow) var(--simx-ease) both;
}
.simx-board__custos > *:nth-child(1) { animation-delay: 40ms; }
.simx-board__custos > *:nth-child(2) { animation-delay: 110ms; }
.simx-board__lado > *:nth-child(1) { animation-delay: 20ms; }
.simx-board__lado > *:nth-child(2) { animation-delay: 70ms; }
.simx-board__lado > *:nth-child(3) { animation-delay: 120ms; }
.simx-board__lado > *:nth-child(4) { animation-delay: 170ms; }
.simx-board__lado > *:nth-child(5) { animation-delay: 220ms; }
/* Só o 3º existe: o painel principal tem UM <article> na 3ª posição — os
   irmãos 2 e 4 nunca casaram (medido no navegador, zero alvos), então os dois
   atrasos que moravam aqui eram enfeite de código. */
.simx-board__principal > article:nth-child(3) { animation-delay: 150ms; }

/* — Hover/respiro das seções (afeta sombra, não layout) — */
.simx-secao,
.simx-dre,
.simx-negociar {
    transition: box-shadow var(--simx-t) var(--simx-ease),
                border-color var(--simx-t) var(--simx-ease);
}

/* — Modo: linha slim no topo, sem card — */
.simx-secao--modo {
    padding:0 0 0.5rem;
    background: transparent; border: none; border-bottom: var(--bs-border-width) dashed var(--bi-border-color);
    border-radius: 0;
    animation-delay: 0ms !important;
}

/* — Proposta lado a lado (qtd | preço) — */
.simx-proposta-grid {
    display: grid; grid-template-columns: 1fr 1fr;
    gap:var(--bi-space-sm) var(--bi-space-md);
    align-items: end;   /* inputs alinhados na base mesmo se um rótulo quebrar linha */
}

/* — Input das alavancas: brilho no foco (transição suave) — */
.simx-lever__num {
    transition: border-color var(--simx-t-fast) var(--simx-ease),
                box-shadow var(--simx-t-fast) var(--simx-ease),
                background var(--simx-t-fast) var(--simx-ease);
}
.simx-lever__num:focus {
    outline: none; border-color: var(--command);
    box-shadow: 0 0 0 3px var(--simx-tint);
}
.simx-lever__slider { transition: filter var(--simx-t-fast) var(--simx-ease); }
.simx-lever__slider:active { filter: brightness(1.1); }

/* — Botões com feedback de clique — */
.simx-secao__acao,
.simx-base__trocar {
    transition: transform var(--simx-t-fast) var(--simx-ease),
                background var(--simx-t-fast) var(--simx-ease),
                border-color var(--simx-t-fast) var(--simx-ease);
}
.simx-secao__acao:active,
.simx-base__trocar:active { transform: scale(0.94); }
/* Foco por teclado: mesmo anel command dos inputs, para consistência a11y */
.simx-reiniciar:focus-visible,
.simx-secao__acao:focus-visible,
.simx-base__trocar:focus-visible {
    outline: 2px solid var(--command); outline-offset: 1px;
}

/* — Delta das alavancas: pulsa ao mudar — */
@keyframes simxDeltaPulse {
    from { transform: translateY(-2px); opacity: 0.4; }
    to   { transform: none; opacity: 1; }
}
.simx-lever__delta[data-estado="subiu"],
.simx-lever__delta[data-estado="desceu"] {
    animation: simxDeltaPulse var(--simx-t) var(--simx-ease);
}

/* — DRE: reveal escalonado das linhas quando troca a base — */
@keyframes simxRevealLine {
    from { opacity: 0; transform: translateX(-6px); }
    to   { opacity: 1; transform: none; }
}
.simx-dre.simx-reveal .simx-dre__sub-linha,
.simx-dre.simx-reveal > .simx-dre__linha {
    animation: simxRevealLine var(--simx-t) var(--simx-ease) both;
}
.simx-dre.simx-reveal .simx-dre__sub-linha:nth-child(1) { animation-delay: 30ms; }
.simx-dre.simx-reveal .simx-dre__sub-linha:nth-child(2) { animation-delay: 60ms; }
.simx-dre.simx-reveal .simx-dre__sub-linha:nth-child(3) { animation-delay: 90ms; }
.simx-dre.simx-reveal .simx-dre__sub-linha:nth-child(4) { animation-delay: 120ms; }
.simx-dre.simx-reveal .simx-dre__sub-linha:nth-child(5) { animation-delay: 150ms; }
.simx-dre.simx-reveal .simx-dre__sub-linha:nth-child(6) { animation-delay: 180ms; }
.simx-dre.simx-reveal .simx-dre__sub-linha:nth-child(7) { animation-delay: 210ms; }

/* — MB: o número grande pulsa quando entra status novo — */
@keyframes simxMbPop {
    0%   { transform: scale(1); }
    35%  { transform: scale(1.06); }
    100% { transform: scale(1); }
}
.simx-dre__linha--mb.simx-mb-pop .simx-dre__pct { animation: simxMbPop var(--simx-t-slow) var(--simx-ease); display: inline-block; }

/* ── Deck de vendas anteriores (sob demanda, no rodapé) ─────────────────── */
.simx-base { position: relative; }
.simx-base__trocar {
    margin-left:0.25rem; padding:0 0.5rem;
    font: 600 0.66rem/1 var(--bi-font-mono); text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--command);
    background: transparent; border: var(--bs-border-width) solid var(--command); border-radius: var(--bi-radius-sm);
    cursor: pointer;
}
.simx-base__trocar[aria-expanded="true"] { background: var(--simx-tint); }
.simx-base__trocar .fa-chevron-up { transition: transform var(--simx-t) var(--simx-ease); }
.simx-base__trocar[aria-expanded="true"] .fa-chevron-up { transform: rotate(180deg); }

/* — Botão Reiniciar: pílula neutra ao lado do toggle de modo — */
.simx-reiniciar {
    margin-left:auto; padding:0 0.5rem;
    font: 600 0.66rem/1 var(--bi-font-mono); text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--bi-text-secondary);
    background: transparent; border: var(--bs-border-width) solid var(--bi-border-color); border-radius: var(--bi-radius-sm);
    cursor: pointer; white-space: nowrap;
    transition: color var(--simx-t-fast) var(--simx-ease),
                border-color var(--simx-t-fast) var(--simx-ease),
                transform var(--simx-t-fast) var(--simx-ease);
}
.simx-reiniciar:hover {
    color: var(--command); border-color: var(--command);
}
.simx-reiniciar:active { transform: scale(0.94); }

.simx-deck-backdrop {
    position: fixed; inset: 0; z-index: 39; background: transparent;
    animation: simxRise var(--simx-t-fast) var(--simx-ease);
}
.simx-deck {
    position: absolute; left: 0; bottom: calc(100% + 0.5rem); z-index: 40;
    width: min(660px, 96vw);
    display: flex; flex-direction: column; gap:var(--bi-space-sm);
    padding:var(--bi-space-md);
    background: var(--bi-bg-surface);
    border: var(--bs-border-width) solid var(--command); border-radius: var(--bi-radius-md);
    box-shadow: var(--bi-shadow-lg);
    transform-origin: bottom left;
    opacity: 0; visibility: hidden; pointer-events: none;
    transform: translateY(10px) scale(0.98);
    transition: opacity var(--simx-t) var(--simx-ease),
                transform var(--simx-t) var(--simx-ease-expo),
                visibility 0s linear var(--simx-t);
}
.simx-deck.is-open {
    opacity: 1; visibility: visible; pointer-events: auto;
    transform: none;
    transition: opacity var(--simx-t) var(--simx-ease),
                transform var(--simx-t) var(--simx-ease-expo),
                visibility 0s;
}
.simx-deck__titulo {
    font: 600 0.72rem/1 var(--bi-font-condensed, var(--bi-font-mono));
    text-transform: uppercase; letter-spacing: 0.1em; color: var(--bi-text-muted); margin:0;
}
.simx-deck .simx-board__nflista {
    max-height: 46vh;
}
/* Linhas da lista entram escalonadas quando o deck abre */

.simx-base__resumo { color: var(--bi-text-secondary); }
.simx-base__resumo .simx-base__nf { color: var(--command); font-weight: 700; }

/* ── Gate de entrada: modal centrado para escolher a origem dos números ── */
.simx-gate-backdrop {
    position: fixed; inset: 0; z-index: var(--z-modal);
    background: rgba(33, 37, 41, 0.32);
    animation: simxRise var(--simx-t-fast) var(--simx-ease);
}
.simx-gate {
    position: fixed; z-index: var(--z-modal-inner);
    top: 50%; left: 50%;
    width: min(440px, 92vw);
    padding:var(--bi-space-lg, 1rem);
    background: var(--bi-bg-surface);
    border: var(--bs-border-width) solid var(--command); border-radius: var(--bi-radius-md);
    box-shadow: var(--bi-shadow-lg);
    opacity: 0; visibility: hidden; pointer-events: none;
    transform: translate(-50%, -50%) scale(0.97);
    transition: opacity var(--simx-t) var(--simx-ease),
                transform var(--simx-t) var(--simx-ease-expo),
                visibility 0s linear var(--simx-t);
}
.simx-gate.is-open {
    opacity: 1; visibility: visible; pointer-events: auto;
    transform: translate(-50%, -50%) scale(1);
    transition: opacity var(--simx-t) var(--simx-ease),
                transform var(--simx-t) var(--simx-ease-expo),
                visibility 0s;
}
.simx-gate__titulo {
    font: 700 1.05rem/1.2 var(--bi-font-condensed, inherit);
    color: var(--bi-text-primary); margin:0 0 var(--bi-space-xs, 0.5rem);
}
.simx-gate__texto {
    font-size: 0.875rem; color: var(--bi-text-secondary);
    margin:0 0 var(--bi-space-md); line-height: 1.45;
}
.simx-gate__resumo {
    display: grid; grid-template-columns: 1fr 1fr; gap:var(--bi-space-xs, 0.5rem) var(--bi-space-md);
    margin:0 0 var(--bi-space-sm); padding:var(--bi-space-sm);
    background: var(--bi-bg-hover); border-radius: var(--bi-radius-sm, 4px);
}
.simx-gate__resumo div { display: flex; flex-direction: column; }
.simx-gate__resumo dt {
    font-size: 0.875rem; text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--bi-text-muted); margin:0;
}
.simx-gate__resumo dd {
    font: 700 1rem/1.1 var(--bi-font-mono, inherit); color: var(--bi-text-primary); margin:0;
}
.simx-gate__fonte {
    font-size: 0.875rem; color: var(--bi-text-muted);
    margin:0 0 var(--bi-space-md);
}
.simx-gate__acoes {
    display: flex; flex-wrap: wrap; gap:var(--bi-space-sm); justify-content: flex-end;
}

/* Botão de confirmação/prosseguir = verde (polaridade de ação do design system).
   "Usar a última venda" / "Começar" levam o vendedor adiante: sinal afirmativo. */

/* Caminho alternativo "Digitar manualmente" = avermelhado (perigo): sai da venda
   recomendada para a calculadora em branco. Contraste de polaridade com o verde. */
/* Mesmo estilo de .btn--danger do design system (demo): vermelho sólido, texto branco. */

@media (prefers-reduced-motion: reduce) {
    .simx-gate,
    .simx-gate.is-open { transition: none; }
    .simx-gate-backdrop { animation: none; }
}

/* ── Feedback de carregamento (toda consulta SQL dá sinal visível) ──────── */
.simx-board__principal { position: relative; }
.simx-loading {
    position: absolute; inset: 0; z-index: 20;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap:0.5rem; text-align: center; padding:var(--bi-space-md);
    background: color-mix(in oklch, var(--bi-bg-surface) 82%, transparent);
    backdrop-filter: blur(1.5px);
    border-radius: var(--bi-radius-md);
    animation: simxRise var(--simx-t) var(--simx-ease);
}
.simx-loading__spinner {
    width: 1.9rem; height: 1.9rem; border-radius: 50%;
    border: 3px solid var(--bi-border-color); border-top-color: var(--command);
    animation: simxSpin 0.7s linear infinite;
}
@keyframes simxSpin { to { transform: rotate(360deg); } }
.simx-loading__txt { font: 700 0.85rem var(--bi-font-mono); color: var(--bi-text-primary); }
.simx-loading__sub { font: 400 0.72rem var(--bi-font-mono); color: var(--bi-text-muted); }

/* autocomplete: item de carregamento com mini-spinner */
.simx-ac__opt--load,
.simx-ac__opt--vazio { font-style: italic; }
.simx-ac__opt--load::before {
    content: ''; display: inline-block; width: 0.8rem; height: 0.8rem; margin-right:0.5rem;
    vertical-align: -1px; border-radius: 50%;
    border: 2px solid var(--bi-border-color); border-top-color: var(--command);
    animation: simxSpin 0.7s linear infinite;
}

@media (max-width: 992px) {
    .simx-proposta-grid { grid-template-columns: 1fr; }
    .simx-deck { width: min(660px, 96vw); }
}

@media (prefers-reduced-motion: reduce) {
    /* escopo: subárvore do board + overlays montados no body (gate/deck/backdrops).
       NÃO usar `*` global aqui — mataria animação do app inteiro. */
    .simx-board *, .simx-board *::before, .simx-board *::after,
    .simx-gate, .simx-gate *, .simx-deck, .simx-deck *,
    .simx-gate-backdrop, .simx-deck-backdrop {
        animation-duration: 0.01ms !important;
        animation-delay: 0ms !important;
        transition-duration: 0.01ms !important;
    }
    .simx-deck { transition: visibility 0s !important; }
}

/* Fluxo Bancário: as tabelas usam o primitivo .stickcols canônico (stick--1/
   stick--edge no JS) — border-collapse, offset, divisor, hover, striped e
   total-row vêm todos de lá. Sem regras de coluna congelada por página. */
/* Cor semântica de número ± — CANÔNICA e compartilhada. Substitui a cópia
   ad-hoc .fb-num--* (e é a alvo p/ aposentar .delta.pos/neg, .md.pos/neg,
   .sig.neg, .cr-row__diff--*, .simx-*[data-status]). */
/* `!important` porque isto é UTILITÁRIO, não componente: a convenção do Bootstrap
   para utilitário de cor (.text-danger e cia. também são !important). Sem isso
   qualquer regra de componente declarada DEPOIS no arquivo vencia por ordem de
   fonte — foi o que aconteceu com .pp-card__dias-num, que anulava o semáforo em
   silêncio (sem erro, sem teste vermelho). */
.num--pos { color: var(--positive-text) !important; }
.num--neg { color: var(--negative-text) !important; }
/* Faixa de atenção (entre o verde e o vermelho) — mesma laranja dos gráficos, no
   degrau de TEXTO: .num--* pinta número, e o degrau base (3,40:1) só serve p/ área. */
.num--alerta { color: var(--chart-alerta-text) !important; }

/* PORT do Bootstrap 5.3 (o build vendorizado é 5.2.3, onde estes utilitários ainda
   não existem). Nomes e semântica idênticos aos de upstream, alimentados pelos
   tokens --bs-secondary-color/--bs-tertiary-color, que apontam para a escada de
   tinta do FCDS. Existem para que `color: var(--ink-3)` deixe de ser declarado
   dentro de cada componente: são ~99 declarações no arquivo que colapsam em dois
   utilitários. Ao subir para o Bootstrap 5.3, APAGUE este bloco — o upstream passa
   a fornecer as mesmas regras a partir dos mesmos tokens. */
.text-body-secondary { color: var(--bs-secondary-color) !important; }
.text-body-tertiary  { color: var(--bs-tertiary-color) !important; }
/* `.fw-medium` também só existe a partir do 5.3 — sem o port ela é no-op
   SILENCIOSA: a classe entra no HTML, ninguém reclama, e o peso cai para 400. */
.fw-medium { font-weight: 500 !important; }
/* Escalas do 5.3 na íntegra (0–5 = 0/.25/.5/1/1.5/3rem), não só os passos usados
   hoje: utilitário pela metade é no-op silenciosa no primeiro consumidor novo. */
.row-gap-0 { row-gap:0 !important; }
.row-gap-1 { row-gap:0.25rem !important; }
.row-gap-2 { row-gap:0.5rem !important; }
.row-gap-3 { row-gap:1rem !important; }
.row-gap-4 { row-gap:1.5rem !important; }
.row-gap-5 { row-gap:3rem !important; }
.column-gap-0 { column-gap:0 !important; }
.column-gap-1 { column-gap:0.25rem !important; }
.column-gap-2 { column-gap:0.5rem !important; }
.column-gap-3 { column-gap:1rem !important; }
.column-gap-4 { column-gap:1.5rem !important; }
.column-gap-5 { column-gap:3rem !important; }
.overflow-y-auto { overflow-y: auto !important; }
.overflow-y-hidden { overflow-y: hidden !important; }
.overflow-y-visible { overflow-y: visible !important; }
.overflow-y-scroll { overflow-y: scroll !important; }
.overflow-x-auto { overflow-x: auto !important; }
.overflow-x-hidden { overflow-x: hidden !important; }
.overflow-x-visible { overflow-x: visible !important; }
.overflow-x-scroll { overflow-x: scroll !important; }

/* ── .caps-label — micro-rótulo em CAIXA ALTA ────────────────────────────────
   O mesmo rótulo (0.875rem + uppercase + tracking + tinta secundária) está
   escrito 58 vezes neste arquivo, com 12 valores diferentes de letter-spacing:
   cabeçalho de tabela, rótulo de filtro, título de painel, rótulo de KPI…
   Uma peça só, com o tracking parametrizado por `--caps-track` para o caso
   raro em que a densidade do bloco pede outro valor. Peso e cor seguem
   utilitário (`fw-bold`, `text-body-secondary`) quando divergem do padrão. */
.caps-label {
  font-size:0.875rem;
  font-weight: 600;
  line-height: 1.3;
  text-transform: uppercase;
  letter-spacing: var(--caps-track, .04em);
  color: var(--ink-3);
}

/* ════════════════════════════════════════════════════════════════════════
   TD dos bancos — pivot drill-down (conta corrente → conta financeira)
   Linha-pai expansível (negrito + caret), linha-filha indentada, Total Geral
   no rodapé. Fiel ao Excel "TD dos bancos".
   ════════════════════════════════════════════════════════════════════════ */
/* Conta-pai: negrito; expansível = clicável */
.fb-td-conta > td {
    font-weight: var(--bi-fw-semibold);
}
.fb-td-conta--expansivel {
    cursor: pointer;
}
.fb-td-conta--expansivel:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: -2px;
}
/* Caret: reserva largura fixa em todas as contas-pai → rótulos alinhados,
   tenham filhas ou não. Sinal só nas expansíveis: + recolhido, − expandido. */
/* Caret = pílula .drill-plus canônica, dirigida pelo aria-expanded da linha
   (sem JS extra). Linhas-pai não-expansíveis viram espaçador 16px p/ alinhar. */
.fb-td-caret {
    display: inline-flex; align-items: center; justify-content: center;
    width: 1rem; height: 1rem; margin-right:0.35em; vertical-align: middle; flex: 0 0 auto;
}
.fb-td-conta--expansivel .fb-td-caret {
    border: var(--bs-border-width) solid var(--line-3); border-radius: var(--bs-border-radius);
    background: var(--surf); color: var(--ink); cursor: pointer;
}
.fb-td-conta--expansivel .fb-td-caret::before {
    content: '\f067'; font-family: "Font Awesome 6 Free"; font-weight: 900; font-size: 0.875rem; line-height: 1;
}
.fb-td-conta--expansivel[aria-expanded="true"] .fb-td-caret::before {
    content: '\f068';
}
/* Conta financeira (filha): indentada, peso normal, tom secundário */
.fb-td-cf > td:first-child {
    padding-left:var(--bi-space-xl);
    font-weight: var(--bi-fw-normal);
    color: var(--bi-text-secondary);
}
/* Total Geral: célula congelada casa o cinza do total-row → agora coberto pelo
   primitivo .stickcols tr.tbl__total-row (ver §stickcols). */
/* Botão "Expandir tudo" no header do card */
.fb-td-toggle-all {
    font-size: var(--bi-fs-label);
    text-decoration: none;
    white-space: nowrap;
}

/* === Promoted from statement-theme.css (Batch 8) — permanent ownership ===
   These component rules are appended at the END of main.css (the last content
   stylesheet in the per-page load order) so they keep winning over earlier
   main.css + custom.css rules exactly as statement-theme.css did when
   it loaded last. !important and selectors are preserved verbatim. The 4
   SAFE-TO-DROP duplicates (font @import, --color-indicator-*, --color-chart-cat-*, soft borders
   -------------------------------------------------------------------------- */
/* .cardbox saiu daqui — seu base (§6 .cardbox) já define surf/line/--r/none
   idênticos; o !important era resíduo de quando este bloco era statement-theme.css
   (arquivo separado carregado depois). .kpi-band FICA: o !important sobrescreve
   de propósito o raio/sombra do base dela pra casar o "statement glass". */
.kpi-band{
  background:var(--surf) !important;
  border:var(--bs-border-width) solid var(--line) !important;
  border-radius:var(--r) !important;
  box-shadow:none !important;
}

.command-bar__filters{   /* .command-bar (bare) saiu — container não renderizado */
  background:var(--glass) !important;
  /* backdrop-filter removed — see note on .cardbox above */
  border:var(--bs-border-width) solid var(--line) !important;
  border-radius:var(--bi-radius-lg) !important;
  box-shadow:var(--sh-glass) !important;
}

/* `.btn-limpar` mantém o look statement aqui; `.pill` saiu deste bloco e voltou
   para a sua base (§PILL), sem `!important` — era este `!important` que invertia
   a cascata do componente inteiro. O `.btn-limpar` fica como estava: não é pill,
   e desestabilizá-lo não faz parte deste saneamento. */
.btn-limpar{
  border:var(--bs-border-width) solid var(--bi-border-color) !important;
  background:var(--bi-bg-hover) !important;
  color:var(--bi-text-secondary) !important;
  border-radius:var(--bs-border-radius-pill) !important;
  font-weight:500;
  transition:all .12s;
}
.btn-limpar:hover{ background:var(--bi-bg-surface) !important; border-color:var(--bi-border-color-heavy) !important; color:var(--bi-text-primary) !important; }

/* Estado ativo. Sem `!important`: (0,2,0) já vence a base (0,1,0). */
.pill.active,
.pill.selected,
.pill[aria-pressed="true"]{
  background:var(--acc-soft); border-color:var(--acc-line); color:var(--acc-ink);
}

/* ── LINHA SELECIONADA (list-group) ───────────────────────────────────────────
   Mesmo trio de tokens do `.pill.active` acima: uma só ideia de "isto está
   selecionado" na app inteira. Antes eram três — importar-of caía no
   `.list-group-item.active` de fábrica (fill #0d6efd sólido, texto branco),
   metas tinha override próprio (fill --acc, texto branco) e histórico-preços
   usava `--surf-2` via `.is-focused`.

   Fundo suave + texto escuro em vez de fill sólido + texto branco não é só
   gosto: com texto branco, qualquer regra de hover que clareie o fundo apaga o
   conteúdo — foi exatamente o bug que o override do metas existia para contornar.
   Com texto escuro essa classe de bug não existe. A barra inset marca a linha
   escolhida sem depender de contraste de fundo, igual ao item ativo da sidebar.

   Especificidade (0,2,0) empata com a do Bootstrap e vence por ordem de arquivo
   (custom.css carrega depois de styles.css) — inclusive sobre
   `.list-group-item-action:hover`, que também é (0,2,0) e vem antes. */
.list-group-item.active{
  background:var(--acc-soft);
  border-color:var(--acc-line);
  color:var(--ink);
  box-shadow:inset 3px 0 0 var(--acc);
}
/* Linha inerte: o texto acinzentado do Bootstrap sozinho não diz "não clicável".
   Vale tanto para `.disabled` quanto para o atributo `disabled` de <button>. */
.list-group-item:disabled,
.list-group-item.disabled{ background:var(--surf-2); cursor:not-allowed; }
/* O modificador BEM `.pill--active` continua ESCOPADO aos três contextos que o
   usam. Uma regra global `.pill--active` pintaria de ativo lugares que hoje não
   pintam — mudaria pixel, e o alvo desta fase é cascata, não visual. */
:is(.command-bar, .secondary-bar) .pill--active{
  background:var(--acc-soft); border-color:var(--acc-line); color:var(--acc-ink);
  font-weight:var(--bi-fw-semibold);
}
:is(.command-bar, .secondary-bar) .pill--active:hover{
  background:var(--acc-soft); border-color:var(--acc-line);
}
.mapa__pills .pill--active,
.mapa__actions .pill--active{
  background:var(--acc-soft); border-color:var(--acc-line); color:var(--acc-ink);
}
.fcds-modal .pill--active{
  background:var(--acc-soft); border-color:var(--acc-line); color:var(--acc-ink);
}
.fcds-modal .pill--active:hover{
  background:var(--acc-soft); border-color:var(--acc-line);
}
.mapa__actions .pill--active:hover{
  background:var(--acc-line); border-color:var(--acc-line);
}
.btn-buscar-trigger{
  background:var(--brand) !important; border:var(--bs-border-width) solid var(--brand) !important; color:var(--bi-text-on-accent) !important;
  border-radius:var(--bs-border-radius-pill) !important;
}
.btn-buscar-trigger:hover{ background:var(--brand-strong) !important; border-color:var(--brand-strong) !important; }

/* toggle switch → statement */

/* tables, mono numerals */
.tbl,
.dataTable,
table.datatable{ font-family:var(--sans); }
.tnum,[class*="-value"],[class*="__value"]{ font-family:var(--bi-font-mono); font-variant-numeric:tabular-nums; }

/* --------------------------------------------------------------------------
   6. SEGMENTED ABC badges + deltas → statement semantic
   -------------------------------------------------------------------------- */
.text-success{ color:var(--positive-text) !important; }
.text-danger{ color:var(--negative-text) !important; }

/* ==========================================================================
   10. PAGE COHERENCE — give the legacy .cardbox sections the statement glass
   look + an aligned, evenly-inset grid (one visual language across the page).
   ========================================================================== */
/* a) horizontal alignment: inset everything from the page edge equally.
   Gutter applied ONCE: the FCDS shell `.content` already provides the 20px
   side inset, so `.page` zeroes its horizontal padding (was 24px) to avoid
   the 20+24=44px double-inset. `.page` keeps only the bottom inset. */
.page{ padding:0 0 var(--bi-space-lg) !important; }
.page > section{ padding-left:0 !important; padding-right:0 !important; }.page .row.g-2{
  --bs-gutter-x:var(--bi-space-md) !important; --bs-gutter-y:var(--bi-space-md) !important;
}

/* c) card header → statement label (small, muted, airy); drop heavy border/accent */

/* tame the section title labels too */

/* d) density caps: tall lists/tables scroll inside the card instead of stretching
   the page. Caps come from FCDS tokens (custom.css) so every scroll tier is
   defined in one place: card-list (--bi-scroll-cap / .card-scroll), table
   (--bi-table-scroll-cap), datatable (--bi-dt-scroll-cap). */
/* Reusable scroll-capped table (shared pattern): a long table scrolls inside its
   card and keeps its column header pinned, instead of stretching the page.
   Vertical sticky header — the metas grid is the reference.
   Override the cap per table with `--bi-table-scroll-max`. */
.tbl-scroll{ max-height:var(--bi-table-scroll-max, var(--bi-table-scroll-cap)); overflow:auto; }
.tbl-scroll thead th{ position:sticky; top:0; z-index:2; background:var(--bi-bg-surface); }
/* Every DataTable renders inside a .datatable-scroll wrapper (the toolbar above it stays
   put). Cap it so long / large-page grids scroll inside the card instead of stretching
   the page, and pin the column-label header row. `thead tr:last-child th` is
   grouped-header-safe: a multi-row (grouped) header pins only the label row, so the
   rows never stack/overlap at top:0. z:10 sits above the body's left-column-sticky
   cells (z 5-9); each page's own col-sticky header rules keep the corner cell on top.
   Override the cap per table with --bi-dt-scroll-max.
   (Replaces the old dead `[data-bi-section="transacoes"] .cardbox__body` cap — the
   FCDS markup has no such element, so the NF grid was stretching the page.) */
.datatable-scroll{ max-height:var(--bi-dt-scroll-max, var(--bi-dt-scroll-cap)); isolation:isolate; }
/* !important: DataTables' own CSS sets `position:relative` on the sort header and
   `.tbl.dataTable thead th{background:transparent !important}` — both would
   otherwise beat this on pages without a left-column-sticky rule. (Sticky still acts
   as the containing block for the sort-arrow ::after, so sorting is unaffected.) */
/* TODAS as linhas do thead grudam, não só a última. Onde há uma 2ª linha (os
   filtros por coluna), `tr:last-child` prendia só ela e deixava a linha de
   TÍTULOS rolar embora — o usuário ficava com as caixas de filtro flutuando sem
   os nomes das colunas em cima. A 2ª linha desce pela altura da 1ª, medida em JS
   (biUtils.recalcularColunasTravadas → --thead-linha1-altura), porque a altura
   depende de fonte/zoom/quebra e não dá para fixar em CSS. Tabela de uma linha
   só: nth-child(2) não casa e nada muda. */
.datatable-scroll thead tr th{ position:sticky !important; z-index:10; background:var(--bi-bg-surface) !important; }
.datatable-scroll thead tr:first-child th{ top:0 !important; }
.datatable-scroll thead tr:nth-child(2) th{ top:var(--thead-linha1-altura, 0px) !important; z-index:9; }
[data-bi-section="transacoes"] .dataTables_wrapper{ font-size:0.875rem; }

/* e) calm the coloured table cells to the soft palette (already via tokens, but
   force the inline green/red used in transações to the statement tones) */
[data-bi-section="transacoes"] .text-success,
.tbl .text-success{ color:var(--positive) !important; }
[data-bi-section="transacoes"] .text-danger,
.tbl .text-danger{ color:var(--negative-text) !important; }

/* ==========================================================================
   11. FULL REFINEMENT — legacy charts, tables, tabs, lists to statement grade
   ========================================================================== */
/* --- tabs (transações) → canonical accent-soft pill (same as fcds.components) --- */

/* Título dentro do header do card: rótulo em caixa alta (era .cardbox__title) */
.card-header .card-title{ font-size:0.875rem; font-weight:600; letter-spacing:.1em;
  text-transform:uppercase; color:var(--bi-text-secondary); margin:0; }

/* Célula de margem (MB/MC) = .progress do Bootstrap; só a geometria responsiva
   da barrinha e o tamanho do rótulo ficam aqui (utilitário do BS não cobre). */
.mb-cell__bar{ height: 0.25rem; width: 3.75rem;
  /* magnitude é neutra de propósito (sem valência verde/âmbar/vermelho): mantém o
     slate do --command em vez do primary azul que o .progress-bar traz por padrão */
  --bs-progress-bar-bg: var(--command); }
.mb-cell__pct{ font-size:var(--bi-fs-body); }
@media (min-width:768px){
  .mb-cell__bar{ width: 3rem; }
  .mb-cell__pct{ font-size:var(--bi-fs-label); }
}

.form-control:focus, .form-select:focus{ border-color:var(--acc-line); box-shadow:0 0 0 2px var(--acc-soft); }

/* Checkbox/radio/switch = Bootstrap ORIGINAL (styles.css), sem recolor FCDS.
   O accent-recolor foi removido a pedido do usuário — NÃO restaurar. */

/* Tabs = .nav-pills do Bootstrap, temadas pela API de variáveis dele (substituem .fcds-tabs) */
/* Só GEOMETRIA e tipografia: as três variáveis de COR (--bs-nav-link-color,
   -hover-color e o par --bs-nav-pills-link-active-*) foram removidas por diretiva
   do usuário — a pill ativa volta ao azul de fábrica do Bootstrap. */
.nav-pills{
  --bs-nav-link-padding-y: var(--bi-space-xs2);
  --bs-nav-link-padding-x: var(--bi-space-md);
  --bs-nav-link-font-size: 0.875rem;
  --bs-nav-link-font-weight: 500;
  --bs-nav-pills-border-radius: var(--r-sm, 11px);
  gap:var(--bi-space-xs2);
  margin-bottom:var(--bi-space-xs);
}
.nav-pills .nav-link.active{ font-weight: 600; }
.nav-pills .nav-link .badge{ font-size:0.875rem; font-weight:600; border-radius:var(--bs-border-radius-pill); padding:0 0.5rem; margin-left:var(--bi-space-xs); }

/* --- DataTables → statement table styling --- */
.tbl.dataTable thead th{
  font-size:0.875rem !important; font-weight:600 !important; letter-spacing:.08em; text-transform:uppercase;
  color:var(--bi-text-muted) !important; background:var(--bi-bg-surface) !important; border-bottom:1px solid var(--bi-border-color) !important;
  padding:var(--bi-space-xs2) calc(var(--bi-space-sm) + var(--bi-space-xs2)) var(--bi-space-sm) !important;
}
.tbl.dataTable tbody td{
  font-size:0.875rem !important; color:var(--bi-text-secondary); border-top:1px solid var(--bi-border-color-subtle) !important; border-bottom:0 !important;
  padding:var(--bi-space-sm) calc(var(--bi-space-sm) + var(--bi-space-xs2)) !important; vertical-align:middle;
}
/* `:not()` cobre os DOIS painéis congelados. Só a esquerda estava excluída, e a
   célula congelada à DIREITA caía aqui: fundo transparente + a listra do
   Bootstrap, que é um overlay de 5% de preto — não fundo opaco. Resultado
   medido na fila de separação: `background-color: rgba(0,0,0,0)` nas linhas
   `.odd`, com a data da coluna de trás aparecendo através do botão. */
.tbl.dataTable.table-striped > tbody > tr:nth-of-type(odd)
  > *:not([class*="stick--"]):not([class*="stick-r--"]){ background:transparent !important; }
/* Ver a nota do hover em `.tbl tbody tr:hover td`: o estado é overlay do Bootstrap,
   não fundo opaco. Sem `!important` porque não há mais fundo opaco pra vencer. */
.tbl.dataTable tbody tr:hover > *{ --bs-table-accent-bg: var(--bs-table-hover-bg); }

/* Cabeçalho de bloco do rowGroup (hoje só a inadimplência agrupa: um bloco por
   cliente). O CSS do CDN pinta a linha com rgba(0,0,0,.1) — tarja escura que, em
   clientes de 1-2 títulos, cai quase a cada duas linhas e o olho lê como zebra
   quebrada. O bloco passa a ser marcado por hierarquia e espaço: nome do cliente
   com peso, filete de início de bloco e ar acima. Cor não carrega essa informação. */
.tbl.dataTable tbody tr.dtrg-group,
.tbl.dataTable tbody tr.dtrg-group th{
  background:var(--bi-bg-surface) !important;
  color:var(--bi-text-primary) !important;
  font-size:0.875rem !important; font-weight:600 !important;
  border-top:1px solid var(--bi-border-color) !important;
  padding:var(--bi-space-md) calc(var(--bi-space-sm) + var(--bi-space-xs2)) var(--bi-space-xs2) !important;
}
.tbl.dataTable tbody tr.dtrg-group:first-child th{ border-top:0 !important; padding-top:var(--bi-space-xs2) !important; }
/* O hover marca a linha de título (a unidade acionável). O cabeçalho não é clicável. */
.tbl.dataTable tbody tr.dtrg-group:hover > *{ --bs-table-accent-bg: transparent; }
.tbl.dataTable .tnum,
.tbl.dataTable td[class*="valor"],.tbl.dataTable td[class*="margem"]{ font-family:var(--bi-font-mono); font-variant-numeric:tabular-nums; }

/* Espaço à direita do rótulo para a seta de ordenação do DataTables. As setas
   são ::before/::after absolutas em right:10px; o padding shorthand acima só
   reservava ~8px, então a seta colidia/sobrepunha o texto do cabeçalho. Vale
   para QUALQUER DataTables (mobile e desktop) — especificidade maior que as
   regras de padding acima, então ganha sem depender da ordem. */
.tbl.dataTable thead th.sorting,
.tbl.dataTable thead th.sorting_asc,
.tbl.dataTable thead th.sorting_desc,
.tbl.dataTable thead th.sorting_disabled{
  padding-right:calc(var(--bi-space-sm) + 1rem) !important;
}

/* Desktop refinement (≥768px): standardize the four faturamento DataTables on FCDS type
   tokens + symmetric, tighter padding (recovers the horizontal room a 4–6 col freeze needs),
   right-align numeric headers over their values, and width-cap the long descriptive columns
   to 2 lines. The base rules above are left intact, so mobile renders exactly as before. */
@media (min-width:768px){
  /* Typography unified app-wide on the base .tbl tokens (12px/600 heads, --bi-fs-body
     body, .06em letter-spacing). Only the LAYOUT refinements (tighter symmetric padding,
     numeric right-align) stay here; the former 13px/700 + .04em escape hatch was removed. */
  .tbl.dataTable thead th{
    padding:var(--bi-space-xs2) var(--bi-space-sm) !important;
  }
  .tbl.dataTable thead th.tbl__numeric{ text-align:right; }
  .tbl.dataTable tbody td{
    line-height:1.3;
    padding:var(--bi-space-xs2) var(--bi-space-sm) !important;
  }
  /* Cap the long descriptive columns at the TD level so the table can't park its
     fill-the-container slack as one big inter-column gap on wide screens (the columns
     ballooned to ~283px at 2560px). The table still fills (width:100%); residual slack
     spreads thinly across the remaining columns. */
  .tbl.dataTable td.col-text{ max-width: 15rem; }
  /* 2-line clamp for long text (cliente, representante, sub-segmento, histórico). Lives on an
     inner <div> — `display:-webkit-box` on the <td> itself would drop table-cell layout. Fills
     the (capped) cell so text no longer floats left inside a wider TD. Full value via title (hover). */
  .tbl.dataTable td .cell-clamp2{
    display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2;
    overflow:hidden; max-width:100%; white-space:normal; overflow-wrap:anywhere;
  }
  /* (Removed escape hatch: the 7-table 13px/700 head override + numeric font-family
     override. Heads/body now follow the unified base .tbl tokens — auditoria P5/ruling 4.) */
  /* Despesas-comex tem cabeçalhos de 2 palavras que quebram em 2 linhas e preenchem a
     largura — reserva uma calha à direita p/ as setas de ordenação (▲▼ em right:10px)
     não sobreporem o texto. Escopo só nas 3 tabelas para não mexer no Faturamento. */
  #df-tabela-previsoes thead th, #df-tabela-abertos thead th, #df-tabela-pagos thead th{
    padding-right:1rem !important;
  }
  
  /* Valor Bruto stays semibold on mobile (the JS span keeps `fw-semibold` so mobile is untouched);
     on desktop force it to the uniform 400. !important needed to beat Bootstrap's .fw-semibold. */
  #bi-tabela-notas td .fw-semibold, #bi-tabela-notas-maes td .fw-semibold,
  #bi-tabela-devolucoes td .fw-semibold{ font-weight:var(--bi-fw-regular) !important; }
  /* KILL THE INTER-COLUMN GAP. The table was forced to fill its container (`.tbl{width:100%}`
     + `.datatable table.dataTable{min-width:100%}` + Bootstrap `w-100`), so on screens wider
     than the content the slack inflated columns into gaps (and the col-text max-width couldn't
     hold against width:100%). Size the table to its CONTENT instead: width:max-content (so columns
     are tight and the col-text caps actually apply), max-width:100% so it still scrolls when the
     content is wider than the area. On an ultra-wide monitor the table ends and the rest of the
     card is blank — that is the cost of "no gaps". Desktop-only; mobile keeps the full-bleed w-100. */
  #bi-tabela-notas, #bi-tabela-devolucoes, #bi-tabela-despesas-fundo, #bi-tabela-notas-maes,
  #crm-matriz{
    width:max-content !important; max-width:100%; min-width:0;
  }
}

/* ============================================================================
   STICKY / FROZEN COLUMNS — unified
   Replaces the old per-page engines (faturamento `bi-col-sticky` +
   despesas_comex `df-col-sticky`). The visual contract (opacity, z ladder, edge,
   isolation) is pure CSS; only the per-column `left` offset is data-driven, set
   as `--stick-left-N` by biUtils.recalcularColunasTravadas. That helper is
   wired into the standard DataTable `drawCallback` (utils.js), so it recomputes on
   EVERY draw — init, sort, page, filter, AND column-visibility (ColVis) — plus a
   shared resize listener. That `draw.dt` coupling is the fix for the old engine,
   which only re-fired on init/resize/tab-switch and so misaligned after ColVis.
   (Pure-CSS calc() offsets were ruled out: in table-layout:auto a <td>'s width is
   only a hint, so declared widths don't hold and the cumulative lefts drift.)

   Usage: add `stickcols` to the <table>; tag each frozen cell `stick--N`
   (1-based, contiguous from the left) and the LAST frozen cell also `stick--edge`.
   `.datatable-scroll` carries `isolation:isolate` so this z ladder can't fight page
   dropdowns/modals. Placed AFTER the striped/hover rules above so frozen cells read
   opaque by source order, not by an !important pile-up. ======================== */
table.stickcols{ border-collapse:separate; border-spacing:0; }
/* opaque cells so scrolled content never shows through the frozen panel */
.stickcols > tbody > tr > td[class*="stick--"]{ position:sticky; background:var(--bi-bg-surface); }
/* position !important: DataTables sets `position:relative` on SORTABLE sort-headers
   (para a seta ::after), o que vence a sticky e faz a coluna congelada do CABEÇALHO
   scrollar horizontalmente (só a não-ordenável escapava). Mesma armadilha já tratada
   p/ o header vertical em .datatable-scroll (ver acima). Sticky segue como bloco
   contêiner da seta, ordenação intacta. */
.stickcols > thead > tr > th[class*="stick--"]{ position:sticky !important; background:var(--bi-bg-surface); }
/* Célula congelada NÃO repinta no hover: ela mantém a surface opaca (que é o que
   impede o conteúdo rolado de aparecer por baixo) e recebe o mesmo overlay de hover
   da linha, igual às demais. Repintar aqui com o hex antigo empilhava overlay sobre
   #f3f4f7 e deixava a coluna congelada mais escura que o resto da linha. */
/* striped: célula congelada casa a faixa zebra do Bootstrap .table-striped
   (senão a coluna sticky mostra a surface e "quebra" a listra). Genérico. */
.stickcols.table-striped > tbody > tr:nth-of-type(odd) > td[class*="stick--"]{ background:var(--surf-2); }
/* espelho da regra acima para o painel congelado à DIREITA. Faltava: o bloco do
   `stick-r--` foi escrito depois e herdou tudo menos a listra, então a coluna
   fixa ficava branca (ou transparente, sob o DataTables) contra a faixa zebra. */
.stickcols.table-striped > tbody > tr:nth-of-type(odd) > td[class*="stick-r--"]{
  background:var(--surf-2); }
/* linha de total: célula congelada casa o cinza do .tbl__total-row */
.stickcols tr.tbl__total-row > td[class*="stick--"]{ background:var(--surf-2); }
/* per-column left offset — JS-measured (biUtils.recalcularColunasTravadas) */
.stickcols .stick--1{ left:var(--stick-left-1, 0px); }
.stickcols .stick--2{ left:var(--stick-left-2, 0px); }
.stickcols .stick--3{ left:var(--stick-left-3, 0px); }
.stickcols .stick--4{ left:var(--stick-left-4, 0px); }
.stickcols .stick--5{ left:var(--stick-left-5, 0px); }
/* z ladder — leftmost paints over next, header over body, corner wins */
.stickcols > tbody > tr > .stick--1{ z-index:5; }
.stickcols > tbody > tr > .stick--2{ z-index:4; }
.stickcols > tbody > tr > .stick--3{ z-index:3; }
.stickcols > tbody > tr > .stick--4{ z-index:2; }
.stickcols > tbody > tr > .stick--5{ z-index:1; }
.stickcols > thead > tr > th.stick--1{ z-index:15; }
.stickcols > thead > tr > th.stick--2{ z-index:14; }
.stickcols > thead > tr > th.stick--3{ z-index:13; }
.stickcols > thead > tr > th.stick--4{ z-index:12; }
.stickcols > thead > tr > th.stick--5{ z-index:11; }
/* Frozen-panel right edge: crisp hairline + soft depth, marking where freezing ends.
   Drawn with a ::after pseudo (NOT box-shadow on the cell): Bootstrap `.table-striped`
   paints its zebra with `box-shadow: inset 0 0 0 9999px` on every cell, which would
   override a cell box-shadow and make the divider vanish on striped rows. The pseudo
   is immune. The cells are position:sticky (positioned), so ::after anchors to them. */
.stickcols td.stick--edge::after,
.stickcols th.stick--edge::after{
  content:""; position:absolute; top:0; right:0; bottom:0; width:1px; pointer-events:none;
  background:var(--bi-border-color);
  box-shadow:4px 0 6px -2px rgba(16,24,40,.18);
}

/* ── RIGHT-edge frozen columns (mirror of the left freeze) ──────────────────────
   For wide worksheet/matrix tables that pin a trailing TOTAL column. Tag each frozen
   cell `stick-r--N` (1-based, contiguous from the RIGHT; --1 = rightmost) and the
   leftmost right-frozen cell also `stick-r--redge` (draws the divider on its LEFT).
   JS sets `--stick-right-N`, accumulated right→left, in the same single pass as the
   left offsets (biUtils.recalcularColunasTravadas). Selectors are disjoint from the
   left set ("stick-r--" never contains "stick--"). ============================ */
.stickcols > tbody > tr > td[class*="stick-r--"]{ position:sticky; background:var(--bi-bg-surface); }
.stickcols > thead > tr > th[class*="stick-r--"]{ position:sticky; background:var(--bi-bg-surface); }
/* Sem repintura no hover — mesma razão da coluna congelada à esquerda (ver acima). */
.stickcols .stick-r--1{ right:var(--stick-right-1, 0px); }
.stickcols .stick-r--2{ right:var(--stick-right-2, 0px); }
.stickcols .stick-r--3{ right:var(--stick-right-3, 0px); }
/* z ladder — right panel sits above body cells and above the left stack's edges */
.stickcols > tbody > tr > .stick-r--1{ z-index:8; }
.stickcols > tbody > tr > .stick-r--2{ z-index:7; }
.stickcols > tbody > tr > .stick-r--3{ z-index:6; }
.stickcols > thead > tr > th.stick-r--1{ z-index:18; }
.stickcols > thead > tr > th.stick-r--2{ z-index:17; }
.stickcols > thead > tr > th.stick-r--3{ z-index:16; }
/* divider on the LEFT edge of the right-frozen panel */
.stickcols td.stick-r--redge::before,
.stickcols th.stick-r--redge::before{
  content:""; position:absolute; top:0; left:0; bottom:0; width:1px; pointer-events:none;
  background:var(--bi-border-color);
  box-shadow:-4px 0 6px -2px rgba(16,24,40,.18);
}

/* ── Standard drill/expand affordance ──────────────────────────────────────────
   The system-wide cue that an element opens a drill/detail panel. Put `.drill-plus`
   on a <button> (or span[role=button]) inside the drillable header/row/cell. Subtle by
   default, accent on hover/focus; keyboard-focusable. One affordance, every surface. */
.drill-plus{
  display:inline-flex; align-items:center; justify-content:center;
  width: 1rem; height: 1rem; padding:0; flex:0 0 auto; cursor:pointer;
  border:var(--bs-border-width) solid var(--line-3); border-radius:var(--bs-border-radius);
  background:var(--surf); color:var(--ink);
  transition:background .15s ease, color .15s ease, border-color .15s ease;
}
/* Ícone canônico: Font Awesome 6 Free (fa-solid = 900) — plus fechado, minus
   aberto. Centra de fato (métrica do glifo FA, sem baseline de texto). Cor ink
   (ativo, não cinza-inativo). Estado pela classe .is-open. */
.drill-plus::before{ content:"\f067"; font-family:"Font Awesome 6 Free"; font-weight:900; font-size:0.875rem; line-height:1; }
.drill-plus.is-open::before{ content:"\f068"; }
.drill-plus:hover{ background:var(--surf-2); color:var(--ink); border-color:var(--ink-3); }
.drill-plus:focus-visible{ outline:2px solid var(--info); outline-offset:1px; }

/* ── Directional cell tint (cores.md DIRECTION channel) ─────────────────────────
   Worksheet/matrix result cells whose value carries good/bad meaning. Background uses
   the *-subtle tint, text the AA-safe *-text token (warning uses the deeper indicator
   alias for small-text contrast). ALWAYS pair with a non-color backup (sign/icon) in
   the cell content — never hue alone (cores.md §5, colorblind-safe). ================ */

/* ── Faturamento wide tables (Notas Fiscais / Notas Mães): RESPONSIVE TIERED FREEZE ──
   Desktop-only. Identity Ações·Data·NF (--1..--3) freeze from 768px; Valor Bruto (--4)
   joins at 1024px; MB·MC (--5·--6) join at 1360px. Columns release from the right edge
   inward as the viewport narrows, keeping the frozen panel ≲40% of the table at every
   width. NF keeps `stick--edge` (its mobile identity pin); on desktop the frozen-panel
   divider is hidden on NF and redrawn on the LAST frozen column of the active tier.
   The phone block below (≤767px OR ≤540px height) is UNCHANGED: every tier here carries
   `and (min-height: 33.8125rem)` so short-landscape phones never hit it, and none use
   `!important`, so the phone block's `!important` always wins there. The cumulative
   `--stick-left-N` offsets are set for ALL six cols by biUtils.recalcularColunasTravadas
   regardless of tier; a column rendered `static` simply ignores its unused `left`.
   Reusable divider recipe is duplicated per tier (CSS can't @apply a pseudo). */
@media (min-width:768px) and (min-height:541px){
  /* extra left offsets (cols 1–4 left come from the base rules above) + full z ladder */
  #bi-tabela-notas .stick--5,#bi-tabela-notas-maes .stick--5{ left:var(--stick-left-5,0px); }
  #bi-tabela-notas .stick--6,#bi-tabela-notas-maes .stick--6{ left:var(--stick-left-6,0px); }
  #bi-tabela-notas > tbody > tr > .stick--4,#bi-tabela-notas-maes > tbody > tr > .stick--4{ z-index:3; }
  #bi-tabela-notas > tbody > tr > .stick--5,#bi-tabela-notas-maes > tbody > tr > .stick--5{ z-index:2; }
  #bi-tabela-notas > tbody > tr > .stick--6,#bi-tabela-notas-maes > tbody > tr > .stick--6{ z-index:1; }
  #bi-tabela-notas > thead > tr > th.stick--4,#bi-tabela-notas-maes > thead > tr > th.stick--4{ z-index:13; }
  #bi-tabela-notas > thead > tr > th.stick--5,#bi-tabela-notas-maes > thead > tr > th.stick--5{ z-index:12; }
  #bi-tabela-notas > thead > tr > th.stick--6,#bi-tabela-notas-maes > thead > tr > th.stick--6{ z-index:11; }
  /* NARROW (768–1023): only identity frozen — Valor·MB·MC scroll with the data.
     Only `position:static` (static cells ignore `left`); we must NOT clear `left` here, or the
     wide tier — which re-sets position:sticky but inherits `left` from above — would lose its
     offset and fail to pin. */
  #bi-tabela-notas .stick--4,#bi-tabela-notas .stick--5,#bi-tabela-notas .stick--6,
  #bi-tabela-notas-maes .stick--4,#bi-tabela-notas-maes .stick--5,#bi-tabela-notas-maes .stick--6{
    position:static;
  }
}
/* MID (≥1024): freeze Valor Bruto (--4); divider moves to after Valor, off NF */
@media (min-width:992px) and (min-height:541px){
  #bi-tabela-notas .stick--4,#bi-tabela-notas-maes .stick--4{ position:sticky; left:var(--stick-left-4,0px); }
  #bi-tabela-notas .stick--edge::after,#bi-tabela-notas-maes .stick--edge::after{ display:none; }
  #bi-tabela-notas td.stick--4::after,#bi-tabela-notas th.stick--4::after,
  #bi-tabela-notas-maes td.stick--4::after,#bi-tabela-notas-maes th.stick--4::after{
    content:""; position:absolute; top:0; right:0; bottom:0; width:1px; pointer-events:none;
    background:var(--bi-border-color); box-shadow:4px 0 6px -2px rgba(16,24,40,.18);
  }
}
/* WIDE (≥1360): also freeze MB·MC (--5·--6); divider moves to after MC%, off Valor */
@media (min-width:1400px) and (min-height:541px){
  #bi-tabela-notas .stick--5,#bi-tabela-notas .stick--6,
  #bi-tabela-notas-maes .stick--5,#bi-tabela-notas-maes .stick--6{ position:sticky; }
  #bi-tabela-notas td.stick--4::after,#bi-tabela-notas th.stick--4::after,
  #bi-tabela-notas-maes td.stick--4::after,#bi-tabela-notas-maes th.stick--4::after{ display:none; }
  #bi-tabela-notas td.stick--6::after,#bi-tabela-notas th.stick--6::after,
  #bi-tabela-notas-maes td.stick--6::after,#bi-tabela-notas-maes th.stick--6::after{
    content:""; position:absolute; top:0; right:0; bottom:0; width:1px; pointer-events:none;
    background:var(--bi-border-color); box-shadow:4px 0 6px -2px rgba(16,24,40,.18);
  }
}
/* Phones (narrow portrait OR short landscape): collapse the frozen panel to just
   the edge/identity column so it stops eating the viewport. The other frozen cols
   go static and scroll with the data; only `.stick--edge` (the NF number — the
   row identity) stays pinned at left:0. The max-height clause catches landscape
   phones, whose width (~844px) would otherwise miss a max-width breakpoint. */
@media (max-width:767.98px), (max-height: 540px){
  /* Body cells of the non-edge frozen cols scroll horizontally (free the width). */
  .stickcols > tbody > tr > td[class*="stick--"]:not(.stick--edge){ position:static !important; }
  /* Header cells must KEEP their vertical pin (top:0) — only drop the horizontal
     freeze (left:auto). Forcing them static killed the sticky header row. */
  .stickcols > thead > tr > th[class*="stick--"]:not(.stick--edge){ left:auto !important; }
  .stickcols .stick--edge{ left:0 !important; }
}

/* REMOVIDO — `.content .card{width:100vw;margin-inline:calc(50% - 50vw)}` no mobile
   (0185647c). Valia quando toda seção do celular era UM card de linha inteira; quando as
   bandas de KPI viraram GRADE de cards (`row row-cols-2` em 12 telas, `.kpi8` aqui), a
   mesma regra passou a estourar card de meia linha: 100vw dentro de trilha de ~189px =
   duas cartas sobrepostas, a da esquerda fora da tela. `body{overflow-x:clip}` engolia o
   estouro sem barra de rolagem, então só se via conteúdo decepado. NÃO reintroduzir: o
   card no mobile é o card canônico, e a goteira lateral é do `.content` (§5). */

/* ── Faturamento mobile layout (rides on the full-width drawer shell) ─────────
   Gate matches the shell mobile gate (760/540) so it's active in both orientations. */
@media (max-width:767.98px), (max-height: 540px){
  /* UF map: stack map over ranking — side-by-side clips the ranking values at phone
     width. Source order is map→ranking, so no `order` (preserves focus order). */
  .page[data-pagina="faturamento"] [data-bi-section="mapa-uf"] .mapa{ grid-template-columns:1fr; gap:var(--bi-space-md); }
  .mapa__map-wrap{ min-height: 13.75rem; }
  .mapa-ranking__share{ width:auto; min-width: 2.625rem; }
  #card-mapa.is-fullscreen .mapa{ grid-template-columns:3fr 2fr !important; }
  /* Nem o CARD nem o GAP da grade são retocados aqui: o card fica com o padding
     canônico (8/16/16) em qualquer largura e `--gap` já é 0.5rem — a regra que
     "apertava" o gap no mobile repetia o valor padrão e foi removida. O que o mobile
     ajusta é a goteira da superfície (.content, §5), não o componente. */
  /* The data grids themselves reach the band edges (cancel the card's inset) so the
     table uses the full width; the toolbar/tabs above keep the inset as chrome. The
     band's hairlines still frame the section, so it reads coherent, not detached.
     Applies to every page's table-wrapper / ranking-table wrapper. */
  .content .tbl-wrapper{
    margin-left:calc(-1 * var(--bi-space-md)); margin-right:calc(-1 * var(--bi-space-md));
    /* the wrapper's own 16px radius + side borders would show as rounded corners at the
       band edges — drop them; the band frames the table. */
    border-radius:0; border-left:0; border-right:0;
  }
}

/* DataTables chrome (search / length / info / paginate) → minimal light */
.dataTables_wrapper .dataTables_filter input,
.dataTables_wrapper .dataTables_length select{
  border:1px solid var(--bi-border-color) !important; border-radius:var(--bs-border-radius-lg) !important; background:var(--bi-bg-hover) !important;
  color:var(--bi-text-primary) !important; padding:var(--bi-space-xs) var(--bi-space-sm) !important; font-size:0.875rem; outline:none;
}
.dataTables_wrapper .dataTables_filter input:focus,
.dataTables_wrapper .dataTables_length select:focus{ border-color:var(--acc-line) !important; box-shadow:var(--ring); }
.dataTables_wrapper .dataTables_info,
.dataTables_wrapper .dataTables_length,
.dataTables_wrapper .dataTables_filter{ font-size:0.875rem; color:var(--bi-text-muted); }
/* PAGINAÇÃO: sem regra nenhuma. Moravam aqui ~45 linhas que repintavam link,
   página ativa, hover e desabilitado, e depois soldavam as células com borda
   compartilhada e cantos retos — tudo com !important, e tudo reimplementando o
   que o .pagination do Bootstrap já faz de fábrica (inclusive a solda, via
   `.page-item:not(:first-child) .page-link{margin-left:-1px}`). Apagado por
   diretiva do usuário: a paginação é a do Bootstrap, sem intermediário. */

/* --- charts: give them consistent comfortable heights --- */
.chart{ position:relative; }

/* segment/ABC toggle + small controls in card headers → statement chips */
.card-header .btn{
  border-radius:var(--bs-border-radius-pill) !important; font-size:0.875rem !important;
}

/* ==========================================================================
   12. LAYOUT REFINEMENT — cards become true flex columns so their charts FILL
   the card (no dead vertical voids), each row's two columns end at the same
   baseline, and one column drives the row height.
   ========================================================================== */

/* b) Top-20 Produtos: the section IS the FCDS .card (card-hd + .chart--xl).
   Make it a flex column so the chart fills the bounded card height
   (maintainAspectRatio:false → 20 bars compress to fit, no whitespace). */
[data-bi-section="top-produtos"]{ display:flex; flex-direction:column; }

/* f) Bound the two mixed-content rows: a tall element (20-bar chart / 20-row
   client list) must not balloon its neighbour (evolução stack / choropleth).
   The data-bi-section element is itself the .card. Fixed row height + internal
   fill/scroll; released on mobile (<993px) where cards stack to span-12. */
@media (min-width:992px) {
  /* Row A — Sub-segmento + Evolução de Faturamento: equal height via the row's
     align-items:stretch (.fcds-row-eq); no fixed height so the capped sub-board
     and the chart match the taller of the two. */
  [data-pagina="faturamento"] [data-bi-section="mapa-uf"] { height: 33.25rem; }
  [data-pagina="faturamento"] [data-bi-section="mapa-uf"] .mapa__ranking { overflow-y: auto; }
}

/* c) Evolução (two stacked cards on the right) FILLS to the Top-20 height:
   each card's body grows and its chart fills it — no more void band. */
[data-bi-section="evolucao-faturamento"] #bi-evolucao-view-grafico,
[data-bi-section="evolucao-faturamento"] #bi-evolucao-view-sazonalidade{ flex:1 1 auto; display:flex; flex-direction:column; min-height:0; }
[data-bi-section="evolucao-faturamento"] .chart,
[data-bi-section="evolucao-margem"] .chart{ flex:1 1 auto; height:auto !important; min-height: 11.875rem; }
[data-bi-section="evolucao-faturamento"] #heatmap{ flex:1 1 auto; }

/* d) Clientes ↔ Mapa row: both fill to equal height; the clientes bar list and
   the map+ranking get matching internal scroll instead of stretching the page. */
[data-bi-section="mapa-uf"] .card-body{ flex:1 1 auto; display:flex; flex-direction:column; min-height:0; }
[data-bi-section="mapa-uf"] .mapa{ flex:1 1 auto; min-height: 21.25rem; }

/* e) section headers with inline toggles align like statement card-hd (label
   left, controls right, shared baseline) instead of wrapping. */

.card-header .card-title{ margin-right:auto; }

/* ==========================================================================
   PAGE-LOCAL STYLES (Fase 3 — extraídos de blocos <style> inline dos templates;
   token-clean, escopados por [data-pagina]/classes próprias. Movidos p/ cá para
   sair do HTML; cascata idêntica — main.css já era carregado por essas páginas).
   ========================================================================== */

/* ── catalogo ── */
.mermaid-container { overflow: auto; min-height: 25rem; }
.mermaid-container .mermaid { background: transparent; text-align: center; }
.catalogo-legenda {
    display: flex; gap:var(--bi-space-md); flex-wrap: wrap;
    font-size: 0.875rem; color: var(--ink-2);
}
.catalogo-legenda span { display: inline-flex; align-items: center; gap:var(--bi-space-2xs); }
.catalogo-legenda i { width: 0.625rem; height: 0.625rem; border-radius: 50%; flex-shrink: 0; }
.catalogo-legenda .swatch-codori  { background: var(--cat-1); }
.catalogo-legenda .swatch-codfam  { background: var(--cat-3); }
.catalogo-legenda .swatch-centro  { background: var(--cat-2); }
#bi-segpills { flex-wrap: wrap; }
.catalogo-empty { color: var(--ink-3); font-style: italic; padding:var(--bi-space-xl); text-align: center; }

/* margem: sem regras de página — larguras de coluna vivem em margem.js
   (columnDefs.width), o scroll horizontal mobile é o próprio .tbl-wrapper. */

/* ── despesas_logistica ── */

/* despesas_logistica: bloco `grid-column:1/-1` removido — os tiles são .card em
   .row row-cols-* (flexbox); grid-column em flex-item é inerte (regra morta). */
/* #bi-distribuicao-* consolidado acima (global; despesas + despesas_logistica) */

/* ── movimentacao ── */
.mov-kpi-cell--transito { border-left: var(--bs-border-width) dashed var(--bi-border-color); }
.mov-kpi-sub--mono { font-family: var(--bi-font-mono); font-size: var(--bi-fs-caption); }
.mov-produto-search--host { position: relative; }

/* ── precos_referencia ── */
.pr-intro { max-width: 70ch; }
.pr-busca { max-width: 18rem; }
@media (max-width: 768px) {
    [data-pagina="precos_referencia"] .table-responsive {
        overflow-x: auto; -webkit-overflow-scrolling: touch;
        margin-inline:-1rem; padding-inline:1rem;
    }
}

/* ==========================================================================
   fluxo_containers — enriquecimento das tabelas de detalhe
   Chip de grupo (canal categórico, neutro — grupo não tem bom/ruim, logo sem
   cor), ícone de via (glifo, não cor), situação com ícone semântico, e fade
   de zeros para a leitura cair no valor real. Tudo via tokens FCDS.
   ========================================================================== */
.fc-via {
    display: inline-flex;
    align-items: baseline;
    gap:0.45em;
}
.fc-via > i {
    color: var(--bi-text-muted);
    width: 1em;
    text-align: center;
    flex: none;
}
.fc-sit {
    display: inline-flex;
    align-items: baseline;
    gap:0.4em;
    white-space: nowrap;
}
.fc-zero { color: var(--bi-text-muted); }
.fc-atraso { color: var(--negative-text); font-weight: var(--bi-fw-semibold); }
/* Banner de status do refresh: cantos arredondados como os cards (não a faixa
   full-bleed quadrada herdada do despesas), borda completa + leve sombra. */
.fc-banner {
  border-radius: var(--bi-radius-md);
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.06);
}

/* ==========================================================================
   MERGED FROM bi/static/bi/css/tokens.css (P6) — ajuda-markdown help-modal styles.
   Font @import moved to base_fcds.html <link> (full Roboto family).
   ========================================================================== */
/* ==========================================================================
   tokens.css — fonts + contextual-help styles for the bi/ app.

   NOTE: all design TOKENS now live in a single file — custom.css
   (canonical color system + scale + app --bi-* tokens). This file no longer
   declares any :root tokens; it only loads the web fonts and styles the
   Markdown-rendered help modal (.ajuda-markdown), using FCDS tokens only.
   ========================================================================== */

/* ==========================================================================
   Ajuda contextual — estilos para HTML gerado pela lib Markdown Python
   (.ajuda-markdown envolve o conteúdo renderizado dentro do modal de ajuda)
   ========================================================================== */

.ajuda-markdown { color: var(--ink); font-size: 1rem; line-height: 1.6; }

.ajuda-markdown h1 { font-size: 1.2rem; font-weight: 700; margin-bottom:0.5rem; color: var(--ink); }
.ajuda-markdown h2 { font-size: 1rem; font-weight: 700; margin-top:1.5rem; padding-bottom:0.5rem; border-bottom: var(--bs-border-width) solid var(--line); color: var(--ink); }
.ajuda-markdown h3 { font-size: 1rem; font-weight: 600; margin-top:1rem; color: var(--ink-2); }

.ajuda-markdown p { margin-bottom:0.5rem; }
.ajuda-markdown ul, .ajuda-markdown ol { padding-left:1.5rem; margin-bottom:0.5rem; }
.ajuda-markdown li { margin-bottom:0.25rem; }

.ajuda-markdown blockquote {
    border-left: 3px solid var(--line);
    padding:0.5rem 1rem;
    margin:0.5rem 0;
    color: var(--ink-3);
    background: var(--surf-2);
    border-radius: 0 var(--bs-border-radius-sm) var(--bs-border-radius-sm) 0;
}

/* Equação — bloco de definição de KPI (MB, MC etc).
   Label à esquerda, corpo da equação à direita, alinhamento por CSS Grid. */
.ajuda-markdown .equacao {
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap:1rem;
    align-items: center;
    background: var(--surf);
    border: var(--bs-border-width) solid var(--line);
    border-left: 3px solid var(--acc);
    border-radius: var(--bs-border-radius);
    padding:1rem 1rem 1rem;
    margin:1rem 0 1rem;
    box-shadow: var(--sh1);
}
.ajuda-markdown .equacao + .equacao { margin-top:0.5rem; }

.ajuda-markdown pre {
    background: var(--surf-2);
    border: var(--bs-border-width) solid var(--line);
    border-radius: var(--bs-border-radius-sm);
    padding:0.5rem 1rem;
    font-size: 0.875rem;
    overflow-x: auto;
    color: var(--ink);
    white-space: pre;
}

.ajuda-markdown code {
    background: var(--surf-2);
    border: var(--bs-border-width) solid var(--line);
    border-radius: var(--bs-border-radius-sm);
    padding:0 0.25rem;
    font-size: 0.82em;
    color: var(--cat-5);
}

.ajuda-markdown pre code {
    background: none;
    border: none;
    padding:0;
    color: inherit;
    font-size: inherit;
}

.ajuda-markdown table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom:1rem;
    font-size: 0.875rem;
    table-layout: auto;
}

.ajuda-markdown th {
    background: var(--surf-2);
    font-weight: 600;
    text-align: left;
    padding:0.5rem 0.5rem;
    border: var(--bs-border-width) solid var(--line);
    color: var(--ink);
}

.ajuda-markdown td {
    padding:0.5rem 0.5rem;
    border: var(--bs-border-width) solid var(--line);
    vertical-align: top;
    color: var(--ink);
    word-break: break-word;
}

.ajuda-markdown td:first-child { text-align: right; color: var(--ink-3); white-space: nowrap; }
.ajuda-markdown td:nth-child(2) { font-weight: 600; }

.ajuda-markdown td code,
.ajuda-markdown th code {
    white-space: pre-wrap;
    font-size: 0.875rem;
    padding:0 0.25rem;
}

.ajuda-markdown tr:nth-child(even) td { background: var(--surf-2); }

.ajuda-markdown a { color: var(--acc); text-decoration: underline; }
.ajuda-markdown a:hover { color: var(--acc-d); }

/* Modal footer separador */

/* ===== MERGED FROM bi/static/bi/css/dre-steel.css (P5 — page-local dissolve) ===== */
/* DRE Steel — estilos locais da página (Fase 1).
 *
 * NOTA (regra de contribuição): CSS custom requer revisão humana. Componente de
 * demonstração de resultado: coluna-conta congelada, âncora "realizado" separada
 * da projeção, bandas de subtotal/resultado, regra de total contábil e numerais
 * condensados tabulares com negativos em parênteses — nada coberto por
 * utilitários Bootstrap/FCDS. Light theme apenas, só tokens FCDS. */

/* ── casca da tabela ──────────────────────────────────────────────────────── */
/* .table/.table-sm (Bootstrap) já dão width:100% (redundante com .tbl/.w-100,
 * removido daqui). Padding/border de célula na prática continuam vindo de
 * `.tbl thead th`/`.tbl tbody td` (maior especificidade que `.table`/
 * `.dre-tabela th`/`td` — 2 combinadores vs 1), então .table/.table-sm não
 * muda a densidade renderizada (computed padding idêntico 8003↔8004, 8px
 * 16px, validado ao vivo). O th/td residual abaixo (.3rem .7rem) é mantido
 * como registro da intenção de densidade própria da cascata financeira —
 * mesmo hoje shadowed pelo `.tbl`, remover mudaria o comportamento se algum
 * dia o `.tbl` for revisto, então não é lixo a apagar. border-collapse:separate
 * residual é exigido pelo sticky (position:sticky quebra com collapse; `.tbl`
 * força collapse, aqui reabrimos separate de propósito). */
.dre-scroll { overflow-x: auto; }
.dre-tabela { border-collapse: separate; border-spacing: 0; }
.dre-tabela th,
.dre-tabela td {
  padding:0.25rem 0.5rem;
  white-space: nowrap;
  border-bottom: 1px solid var(--line-2);
}
/* numerais condensados + tabulares: alinham e nunca quebram */
.dre-tabela tbody td,
.dre-tabela thead th.text-end {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
  letter-spacing: .01em;
  text-align: right;
}

/* ── cabeçalho: âncora mai/26 (realizado) × projeção jun–dez ───────────────── */
.dre-tabela thead th {
  background: var(--surf-2);
  color: var(--ink-2);
  font-weight: 600;
  font-size: 0.875rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  border-bottom: 1px solid var(--line-3);
  position: sticky;
  z-index: 3;
  vertical-align: bottom;
}
.dre-tabela thead tr:first-child th { top: 0; }
.dre-tabela thead tr:last-child  th { top: var(--dre-hd1, 1.9rem); }
.dre-grp { text-align: center; padding-block:0.25rem; }
.dre-grp--real { text-align: right; color: var(--ink-2); }
.dre-grp--proj { color: var(--brand-ink); background: var(--brand-soft); font-size: 0.875rem; }
.dre-tag {
  display: block;
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: .06em;
  color: var(--ink-4);
  margin-top:0;
}

/* ── coluna "Conta" congelada ─────────────────────────────────────────────── */
.dre-tabela .dre-stick {
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--surf);
  text-align: left;
  min-width: 18rem;
  box-shadow: 1px 0 0 var(--line-3);
}
.dre-tabela thead .dre-stick { z-index: 5; background: var(--surf-2); vertical-align: middle; }

/* ── coluna-âncora realizado (mai/26): tom de referência + divisor ────────── */
.dre-tabela .dre-mai {
  background: var(--surf-2);
  color: var(--ink-2);
  border-right: 2px solid var(--line-3);
}
.dre-tabela thead .dre-grp--real,
.dre-tabela thead .dre-mai { border-right: 2px solid var(--line-3); }
.dre-mai-h { font-weight: 700; color: var(--ink); }

/* botão de colapsar/expandir a coluna realizado */

/* ── bandas da cascata (espelham os fills do Excel, em tons FCDS) ─────────── */
/* nível 1: sub-agregados — (-) deduções, impostos, custo, gerenciais… */
.dre-tabela .dre-sub.dre-n1 > th,
.dre-tabela .dre-sub.dre-n1 > td { background: var(--surf-2); font-weight: 600; }
.dre-tabela .dre-sub.dre-n1 .dre-stick { padding-left:1.5rem; background: var(--surf-2); }
.dre-tabela .dre-sub.dre-n1 .dre-mai   { background: var(--surf-3); }

/* nível 0: linhas de resultado — Receita bruta, (=) Receita líq., Lucro bruto… */
.dre-tabela .dre-sub.dre-n0 > th,
.dre-tabela .dre-sub.dre-n0 > td {
  background: var(--surf-3);
  font-weight: 700;
  color: var(--ink);
  border-top: 1.5px solid var(--line-3);
}
.dre-tabela .dre-sub.dre-n0 .dre-stick,
.dre-tabela .dre-sub.dre-n0 .dre-mai { background: var(--surf-3); }

/* total final — regra dupla contábil (LO antes do IR) */
.dre-tabela .dre-total > th,
.dre-tabela .dre-total > td {
  border-top: 2px solid var(--ink-2);
  border-bottom: 2px solid var(--ink-2);
}

/* MB% (margem bruta) — sub-linha leve logo abaixo do Lucro bruto */
.dre-tabela .dre-mb > th,
.dre-tabela .dre-mb > td {
  background: var(--surf);
  color: var(--ink-3);
  font-weight: 500;
  font-size: 0.875rem;
  border-top: 0;
}
.dre-tabela .dre-mb .dre-stick { background: var(--surf); padding-left:1.5rem; font-style: italic; }
.dre-tabela .dre-mb .dre-mai { background: var(--surf); }

/* ── contas-folha (detalhe colapsável, somente leitura) ───────────────────── */
.dre-tabela .dre-conta .dre-stick { padding-left:3rem; font-weight: 400; }
.dre-tabela .dre-conta-lab { color: var(--ink-2); font-size: 0.875rem; }
.dre-tabela .dre-conta:hover > th,
.dre-tabela .dre-conta:hover > td { background: var(--brand-soft); }
.dre-tabela .dre-conta:hover .dre-mai { background: var(--brand-soft); }

/* negativos (custos/despesas) — canal de direção, só no numeral */
.dre-neg { color: var(--negative-text); }

/* grupos expansíveis */
.dre-temfilho { cursor: pointer; }
.dre-temfilho .drill-plus { color: var(--ink-3); margin-right:0.25rem; }
.dre-temfilho:hover .drill-plus { color: var(--brand); }

/* legenda do card */
.dre-legenda { color: var(--ink-3); font-size: 0.875rem; }

/* explicação curta do modelo (banner de topo) */

.dre-explica strong { color: var(--ink); font-weight: 600; }
.dre-explica code {
  font-family: var(--mono);
  background: var(--surf-3);
  padding:0 0.25rem;
  border-radius: var(--bs-border-radius-sm);
  color: var(--ink);
}
.dre-explica .fa-circle-question { color: var(--ink-3); }

/* knobs: separadores de grupo, rótulo + ajuda + unidade */
.dre-knob-grupo > th {
  background: var(--surf-2);
  color: var(--ink-3);
  font-size: 0.875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  padding:0.25rem 0.5rem;
  border-bottom: var(--bs-border-width) solid var(--line-3);
}
.dre-knob-lab { vertical-align: middle; }
.dre-knob-nome { display: inline-flex; align-items: center; gap:0.5rem; color: var(--ink); font-weight: 600; }
.dre-knob-hint { display: block; color: var(--ink-3); font-size: 0.875rem; font-weight: 400; margin-top:0; }
.dre-unidade {
  font-family: var(--mono);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--ink-3);
  background: var(--surf-2);
  border: var(--bs-border-width) solid var(--line-3);
  border-radius: var(--bs-border-radius-pill);
  padding:0 0.5rem;
  line-height: 1.3;
  letter-spacing: 0;
  text-transform: none;
}

/* ── inputs editáveis (knobs, coeficientes) ───────────────────────────────── */
.dre-inp{ width:100%; min-width:4.5rem; max-width:8.5rem; text-align:right; font-variant-numeric:tabular-nums; }
/* knobs/coef: rótulos à esquerda */
.dre-knobs th[scope="row"],
.dre-coef th[scope="row"] { text-align: left; font-weight: 500; color: var(--ink); }
.dre-knobs td { font-variant-numeric: tabular-nums; }

@media (prefers-reduced-motion: reduce) {
  .dre-inp { transition: none; }
}

/* ===== MERGED FROM bi/static/bi/css/faturamento-fcds.css (P5 — page-local dissolve) ===== */
/* ==========================================================================
   faturamento-fcds.css — page-owned glue for the Faturamento page on FCDS.
   The GENERIC helpers that used to live here (grid spans .fcds-span-*, equal-
   height .fcds-row-eq, segmented toggle .fcds-seg, the .fcds-tabs underline
   skin, .fcds-mini-lab, .fcds-siglink, .is-hidden) were PROMOTED to the shared
   layer (custom.css §10 + the canonical TABS block) so
   every migrated page composes them without copy-paste. What remains here is
   faturamento-ONLY section choreography. Uses ONLY fcds tokens — no hardcoded
   colours.
   ========================================================================== */

/* P7 — CLS: #fcds-grid starts empty and faturamento-fcds.js injects the KPI band
   after data loads. Reserve the band height while empty so the fill no longer
   collapses→expands (measured CLS ~1.77 → 0.13). */
#fcds-grid { min-height: 10.5rem; }

/* Sinais operacionais como linha full-width (mês corrente): 3 cards lado a lado.
   Fora do mês corrente a .sigcol mantém o padrão vertical (coluna span-4).
   .is-hidden (oculta o Ritmo Diário fora do mês corrente) é compartilhado. */
.sigcol.is-row { flex-direction: row; }
.sigcol.is-row .sig { flex: 1; }
@media (max-width: 992px) {
  .sigcol.is-row { flex-direction: column; }
}

/* Row B — Evolução de Margem (50%) ao lado do Mapa (50%), em altura igual.
   O card vira coluna flex e o gráfico ocupa a altura restante; o canvas é
   posicionado em absoluto para acompanhar essa altura (em vez de uma única
   linha de tendência inflar para ~571px via o loop de aspect-ratio do Chart.js
   quando não há altura definida). Resultado: a linha escala junto com o mapa. */
[data-bi-section="evolucao-margem"] { display: flex; flex-direction: column; }
[data-bi-section="evolucao-margem"] .chart {
  flex: 1 1 auto; height: auto; min-height: 15rem; position: relative;
}
[data-bi-section="evolucao-margem"] .chart canvas {
  position: absolute; inset: 0; height: 100% !important;
}

/* Ritmo Diário — gráfico ocupa toda a altura do card (mesmo padrão da margem),
   acompanhando a altura do board de Sub-segmento ao lado (fcds-row-eq). */
[data-bi-section="corredor-diario"] { display: flex; flex-direction: column; }
[data-bi-section="corredor-diario"] .chart {
  flex: 1 1 auto; height: auto; min-height: 15rem; position: relative;
}
[data-bi-section="corredor-diario"] .chart canvas {
  position: absolute; inset: 0; height: 100% !important;
}


/* Switch de formato numérico (abreviado ↔ completo) injetado no topbar por
   faturamento.js. Reusa o componente global .toggle ("Considerar devoluções");
   aqui só ajustamos o encaixe no topbar (altura, alinhamento, não encolher). */

/* AUTO-SHRINK — números completos ("R$ 16.201.272,89") são bem mais largos que os
   abreviados. Os valores da banda já são nowrap; no modo completo encolhemos o
   font-size com clamp() em unidades cqi (container query inline-size) → o tamanho
   acompanha a LARGURA REAL DA CÉLULA, não a viewport. Isso resolve os dois furos do
   vw anterior: (a) sidebar aberta deixa a viewport larga mas a célula estreita;
   (b) o grid colapsa 8→4→2 colunas. O teto px = tamanho original, então no desktop
   amplo fica praticamente inalterado. Escopo: .kpiband--completo (modo compacto
   intocado). Cada célula vira um container inline-size. */

/* ===== MERGED FROM bi/static/bi/css/gerencial-cordoalha.css (P5 — page-local dissolve) ===== */

/* ============================================================================
   gerencial-cordoalha.css — porte PIXEL-PERFECT do mockup aprovado, responsivo.
   Tokens e valores transcritos do mockup (paleta fria/clara, mono nos números).
   Escopo em .gc (dentro do shell FCDS). Sem legenda de rodapé (decisão do
   usuário). Drills em overlay próprio (.gc-ov), como o mockup.
   ========================================================================== */
.gc {
  /* Paleta Bootstrap literal (spec 2026-07-28 §11). A build vendorizada é
     5.2-era: NÃO existem --bs-tertiary-bg nem as famílias -bg-subtle /
     -border-subtle / -text-emphasis. Só o que está aqui existe.
     --accent é #0d6efd (BS puro), por decisão do usuário — diverge do
     --brand #006BB5 que o resto do app usa.
     --ink-2/--ink-3 são rgba TRANSLÚCIDOS: usar só em color, nunca como
     fundo de coluna sticky (senão a coluna vaza no scroll horizontal).
     --amber saiu: #ffc107 tem ~1.9:1 em branco, ilegível como texto. O nível
     "alerta" agora é sinalizado por preenchimento, não por cor de número.
     --accent-dim/--steel/--steel-hi saíram: zero uso (auditado 2026-07-28). */
  --panel:var(--bs-body-bg); --panel-3:var(--bs-gray-100);
  --ink:var(--bs-body-color); --ink-2:var(--bs-secondary-color);
  --ink-3:var(--bs-tertiary-color); --ink-4:var(--bs-gray-400);
  --line:var(--bs-border-color); --line-2:var(--bs-border-color-translucent);
  --accent:var(--bs-primary);
  --red:var(--bs-danger); --green:var(--bs-success);
  /* Sem override local de fonte: herda a Roboto única do :root (--sans/--mono). */
  margin:0 auto; display:flex; flex-direction:column; gap:0.5rem;
  color:var(--ink); font-family:var(--sans);
}
/* Rótulos/cabeçalhos herdam a sans do mockup (o shell usa Roboto); números já
   forçam --mono, então continuam monoespaçados. */
.gc, .gc button, .gc input { font-family:var(--sans); }

/* ── Abas de mês ─────────────────────────────────────────────────────────── */
/* Vivem no .card-header do card único (não são mais um card próprio), então
   não têm bordo/fundo/padding próprios; aqui só o residual sem primitiva:
   linha flex das abas + scroll horizontal (a build vendorizada do Bootstrap só
   tem .overflow-auto, que travaria o eixo Y também). */
.gc-months { display:flex; flex-direction: row; gap:0.25rem; align-items:center; overflow-x:auto;
  flex:1 1 auto; min-width:0; }
.gc-months__lbl { font-size:0.875rem; letter-spacing:.16em; text-transform:uppercase; color:var(--ink-3);
  font-weight:700; padding:0 0.5rem 0 0.25rem; white-space:nowrap; }
.gc-mtab { flex:1 1 0; min-width: 2.875rem; text-align:center; padding:0.5rem 0.25rem; border-radius:var(--bs-border-radius-lg); font-size:0.875rem;
  font-weight:600; color:var(--ink-2); cursor:pointer; white-space:nowrap; background:transparent; border:0; }
.gc-mtab:hover:not(.gc-mtab--off):not(.gc-mtab--on) { background:var(--panel-3); }
.gc-mtab--on { background:var(--accent); color:var(--bi-text-on-accent); font-weight:700; cursor:default; }
.gc-mtab--off { color:var(--ink-3); opacity:.45; cursor:default; }

/* ── Nota de mês fechado ─────────────────────────────────────────────────── */
/* Cor/padding vêm de .alert-secondary (Bootstrap); aqui só o layout em linha
   do ícone+texto e o encaixe edge-to-edge dentro do card-body. */
.gc-pastnote { display:flex; flex-direction: row; align-items:center; gap:0.5rem; margin:0;
  border-radius:0; border-left:0; border-right:0; border-top:0;
  font-size:0.875rem; font-weight:600; }
.gc-pastnote i { flex:0 0 auto; }

/* ── Painéis ─────────────────────────────────────────────────────────────── */
/* .gc-panel/.gc-panel__hd (bordo/bg/radius/overflow + layout do cabeçalho)
   viraram .card/.card-header (+ utilities Bootstrap d-flex/justify-content-
   between/align-items-baseline/flex-wrap/gap-2 direto no template). Fica só
   a tipografia "eyebrow" do título, que não tem equivalente Bootstrap. */
/* (.gc-panel__ttl saiu com a tira: o título do saldo virou `.gc-hd__ttl`,
   dentro da própria célula de rótulo do cabeçalho da matriz.) */

/* toggle de ordenação */
.gc-ord { display:inline-flex; align-items:center; gap:0.5rem; }
.gc-ord__lbl { font-size:0.875rem; letter-spacing:.22em; text-transform:uppercase; color:var(--ink-3); font-weight:700; }
.gc-ord__seg { display:inline-flex; border:var(--bs-border-width) solid var(--line); border-radius:var(--bs-border-radius-lg); overflow:hidden; }
.gc-ord__b { border:0; background:transparent; padding:0.5rem 0.5rem; font-size:0.875rem; font-weight:600; color:var(--ink-2); cursor:pointer; }
.gc-ord__b + .gc-ord__b { border-left:var(--bs-border-width) solid var(--line); }
.gc-ord__b:hover:not(.gc-ord__b--on) { background:var(--panel-3); }
.gc-ord__b--on { background:var(--accent); color:var(--bi-text-on-accent); font-weight:700; }
/* Toggle de conjunto (Cordoalha ↔ Arame). Vive no topbar, FORA do .gc, então
   NÃO pode usar os tokens locais (--accent etc. ficam indefinidos → branco no
   branco). Usa os tokens globais :root (--brand/--line/--ink). */
.gcx-seg { display:inline-flex; border:var(--bs-border-width) solid var(--line); border-radius:var(--bs-border-radius-lg); overflow:hidden; background:var(--surf); }
.gcx-seg__b { border:0; background:transparent; padding:0.25rem 1rem; font-size:0.875rem; font-weight:600; color:var(--ink-2); cursor:pointer; }
.gcx-seg__b + .gcx-seg__b { border-left:var(--bs-border-width) solid var(--line); }
.gcx-seg__b:hover:not(.gcx-seg__b--on) { background:var(--brand-soft); color:var(--brand-ink); }
.gcx-seg__b--on { background:var(--brand); color:var(--bi-text-on-accent); font-weight:700; }

/* O card tem raio nos quatro cantos, mas a última linha da matriz (fundo próprio)
   pintava por cima dos dois de baixo: topo arredondado, base em esquadro. Recorta
   o conteúdo na forma do card — nada aqui precisa escapar dele. */
.gc .card { overflow:hidden; }

/* ── Cabeçalho da bitola (era a tira `.gc-strip`) ────────────────────────── */
/* Saldo, barra, rótulo e código na MESMA célula da coluna: o alinhamento passa
   a ser o da tabela (morreram o espaçador de 216px que imitava a coluna de
   rótulo e o `min-width` repetido nos dois componentes) e a bitola é escrita
   uma vez só, não uma na tira e outra no cabeçalho. */
.gc-mx th.gc-bh { vertical-align:bottom; }
/* `nowrap` no NÚMERO (não no rótulo): sem ele o saldo partia no meio — "−17,3"
   virava "−17," / "3" quando a coluna aperta. */
.gc-bh__num { display:block; white-space:nowrap; font-family:var(--mono); font-size: var(--bi-fs-compact); line-height:1.1; font-weight:700;
  font-variant-numeric:tabular-nums; color:var(--green); }
.gc-bh--dn .gc-bh__num { color:var(--red); }
.gc-bh__bar { display:block; position:relative; height: 2.75rem; margin:0.25rem 0 0.375rem; }
.gc-bh__bar i { position:absolute; left:0; right:0; top:50%; border-top:var(--bs-border-width) dashed var(--ink-3); opacity:.45; }
.gc-bh__bar b { position:absolute; left:26%; right:26%; background:var(--green);
  border-radius: var(--bs-border-radius-sm) var(--bs-border-radius-sm) 0 0; }
.gc-bh--dn .gc-bh__bar b { background:var(--red); border-radius: 0 0 var(--bs-border-radius-sm) var(--bs-border-radius-sm); }
/* Desliga a HERANÇA de `word-break:break-word` do `thead th` em vez de PROIBIR a
   quebra: "15,2mm"/"12,7eng" são token único (sem espaço, sem oportunidade de
   quebra) e seguem inteiros — que era o motivo do antigo `nowrap` —, enquanto
   "BWG 18 torcido 10kg" (conjunto Arame, 16 colunas) quebra nos ESPAÇOS dentro
   da própria coluna. Com `nowrap` ele vazava por cima da coluna vizinha em
   qualquer largura de tela. */
.gc-bh__lbl { display:block; white-space:normal; word-break:normal; overflow-wrap:normal;
  font-size: var(--bi-fs-compact); font-weight:700; color:var(--ink); text-transform:none; letter-spacing:0; }
.gc-bh--dn .gc-bh__lbl { color:var(--red); }
.gc-bh__cod { display:block; white-space:nowrap; font-family:var(--mono); font-size: var(--bi-fs-micro); letter-spacing:-0.02em; color:var(--ink-3); }
.gc-bh__skel { display:block; margin:0 auto 0.25rem; }
/* Rótulo da 1ª coluna do cabeçalho: título (botão do resumo geral) + fórmula. */
.gc-hd__ttl { display:block; border:0; background:transparent; padding:0; cursor:pointer; text-align:left;
  font-size:0.875rem; letter-spacing:.15em; text-transform:uppercase; font-weight:700; color:var(--ink-2); }
.gc-hd__ttl:hover { color:var(--accent); }
.gc-hd__sub { display:block; font-size: var(--bi-fs-compact); font-weight:400; letter-spacing:0; text-transform:none; color:var(--ink-3); }
.gc-hd__cap { font-size: var(--bi-fs-micro); letter-spacing:.08em; text-transform:uppercase; font-weight:700; color:var(--ink-3); }

/* ── Runway: para onde o saldo caminha (2ª linha do cabeçalho) ───────────── */
/* A série e o mês da virada vêm prontos do backend (`runway`); aqui só a
   polilinha. Responde "quando falta", que a matriz de um mês só não responde. */
.gc-mx tr.gc-rwrow th { background:var(--panel-3); padding:0.375rem 0.375rem 0.25rem; vertical-align:middle; cursor:default; }
.gc-mx tr.gc-rwrow th.gc-rowh { background:var(--panel-3); }
.gc-rw { display:block; width:100%; height: 1.625rem; }
/* A nota só existe quando há virada; a coluna calma fica em silêncio. O
   `min-height` reserva a linha de texto para as colunas mudas não subirem e
   desalinharem as sparklines vizinhas. */
.gc-mx tr.gc-rwrow th { min-height:0; }
.gc-rw__nota { display:block; white-space:nowrap; font-size: var(--bi-fs-micro); font-weight:700; letter-spacing:0;
  text-transform:none; text-align:center; }
.gc-rw__nota--zera_em { color:var(--red); }
.gc-rw__nota--recupera_em { color:var(--green); }

/* ── Matriz ──────────────────────────────────────────────────────────────── */
/* A matriz rola dentro do card, com cabeçalho grudado: as barras e os rótulos
   de bitola são a referência de leitura de toda linha — se saem de vista ao
   rolar, o número do meio da tabela vira número sem dono. */
.gc-mxwrap { overflow:auto; max-height:calc(100vh - 9.5rem); }
/* O piso acompanha o Nº DE COLUNAS (`--gc-cols`, carimbado no render): 59.25rem
   fixo era calibrado para as 13 bitolas da cordoalha e espremia as 16 do arame
   até o rótulo virar ilegível. Quem rola é o `.gc-mxwrap` (já `overflow:auto`);
   a PÁGINA nunca rola na horizontal. */
table.gc-mx { border-collapse:collapse; width:100%; font-size:0.875rem; table-layout:fixed;
  min-width: calc(14.75rem + var(--gc-cols, 13) * 4.75rem); }
.gc-mx col.gc-c-rowh { width: 14.75rem; }
.gc-mx th, .gc-mx td { padding:0; white-space:nowrap; }
.gc-mx thead th { font-size:0.875rem; color:var(--ink-3);
  font-weight:700; text-align:center; padding:0.5rem 0.375rem 0.375rem; border-bottom:var(--bs-border-width) solid var(--line);
  border-right:var(--bs-border-width) solid var(--line-2);
  vertical-align:bottom; cursor:pointer;
  white-space:normal; line-height:1.15; word-break:break-word;
  position:sticky; top:0; z-index:2; background:var(--panel); }
/* A 2ª linha do cabeçalho (runway) gruda logo ABAIXO da 1ª — a altura é medida
   no cliente (`--gc-hd-h`), não chutada, porque depende da fonte e do zoom. */
.gc-mx tr.gc-rwrow th { top:var(--gc-hd-h, 8.75rem); z-index:2; }
.gc-mx thead th.gc-rowh { z-index:4; }
.gc-mx tr.gc-rwrow th.gc-rowh { z-index:5; }
/* Fundo OPACO obrigatório: a coluna fixa cobre as células que passam por
   baixo no scroll horizontal. Nunca usar --ink-2/--ink-3 aqui (são rgba). */
.gc-mx thead th.gc-rowh { border-right:var(--bs-border-width) solid var(--line-2); text-align:left; padding-left:0.875rem; width: 14.75rem; cursor:default;
  position:sticky; left:0; z-index:3; background:var(--bs-gray-100); }
.gc-mx thead th:not(.gc-rowh):hover { color:var(--accent); background:var(--panel-3); }
/* Ponto de risco no cabeçalho da bitola — canal não-cromático (ADR-006).
   Carrega sozinho o nível "alerta", que perdeu a cor de número quando a
   paleta virou Bootstrap (--bs-warning é ilegível como texto, mas como
   preenchimento de um ponto de 5px tem contraste de sobra). */
.gc-mx thead th .gc-rd { display:inline-block; width: 0.3125rem; height: 0.3125rem; border-radius:50%;
  margin-right:0.25rem; vertical-align:middle; }
.gc-mx thead th .gc-rd--critico { background:var(--bs-danger); }
.gc-mx thead th .gc-rd--alerta  { background:var(--bs-warning); }
/* Régua nos dois eixos (decisão do usuário): a matriz é lida célula a célula
   contra o Sênior, e a coluna precisa ser tão delimitada quanto a linha. */
.gc-mx tbody td { border-bottom:var(--bs-border-width) solid var(--line-2);
  border-right:var(--bs-border-width) solid var(--line-2); }
.gc-mx td.gc-k { border-right:var(--bs-border-width) solid var(--line-2); padding:0.4375rem 0.625rem 0.4375rem 0.875rem; color:var(--ink); font-weight:600; font-size: var(--bi-fs-compact); width: 14.75rem;
  white-space:normal; line-height:1.2; position:sticky; left:0; z-index:2; background:var(--bs-gray-100); }
.gc-mx td.gc-k .gc-kx { display:block; color:var(--ink-3); font-weight:400; font-size: var(--bi-fs-micro); margin-top:0; }
.gc-mx td.gc-cell { text-align:right; padding:0.4375rem 0.625rem; line-height:1.45; }
.gc-cv { font-family:var(--mono); font-variant-numeric:tabular-nums; font-size: var(--bi-fs-compact); }
.gc-cv.gc-z { color:var(--bs-gray-500); }
/* Segunda linha da célula: o dinheiro do pedido firme. Menor e cinza — o peso
   continua sendo a grandeza da tela; o valor é contexto, não concorrente. */
.gc-cr { display:block; font-family:var(--mono); font-size: var(--bi-fs-micro); line-height:1.2;
  font-variant-numeric:tabular-nums; color:var(--ink-3); }
/* Nível ALERTA (saldo positivo, mas abaixo dos pedidos já firmes). Era número
   preto — igual a uma linha qualquer — porque --bs-warning reprova contraste
   como texto; `--warning-text` é o amarelo escurecido do app, feito para isto,
   e o preenchimento suave garante que o nível não dependa só da cor do
   algarismo (ADR-006: o ponto do cabeçalho continua como canal não-cromático). */
.gc-cv.gc-cv--alerta { color:var(--warning-text); font-weight:700; }
/* Precisa vencer `.gc-mx tr.gc-result td` (mesma célula, banda do resultado),
   que é mais específica — sem os dois seletores o preenchimento não aparecia. */
.gc-mx td.gc-cell--alerta,
.gc-mx tr.gc-result td.gc-cell--alerta { background:var(--warning-subtle); }
.gc-bh--alerta .gc-bh__num { color:var(--warning-text); }
/* bandas: zona (forte) e grupo (leve) */
.gc-mx tr.gc-zone td { background:var(--panel-3); color:var(--ink-2); font-size: var(--bi-fs-micro); letter-spacing:.1em;
  text-transform:uppercase; font-weight:700; text-align:left; padding:0.375rem 1rem;
  border-top:var(--bs-border-width) solid var(--line); border-bottom:var(--bs-border-width) solid var(--line); }
/* Rótulo da banda (PASSADO/FUTURO) fixo à esquerda no scroll horizontal. A
   célula é colspan de largura total (sem folga p/ `sticky` nela mesma), então
   quem gruda é o SPAN interno — mais estreito que a célula, ele tem folga p/
   ficar em left:18px (alinhado ao recuo da coluna Indicador) ao arrastar a
   matriz no mobile. O fundo opaco `--panel-3` da célula cobre o que passa por baixo. */
.gc-mx tr.gc-zone td .gc-zone__lbl { position:sticky; left:18px; display:inline-block; }
/* Contexto da banda ("· jul/26, fecha no estoque atual") em caixa normal: a
   faixa inteira em caixa-alta com travessões pesava como título de seção. */
.gc-mx tr.gc-zone .gc-zone__ctx { font-size: var(--bi-fs-compact); font-weight:400; letter-spacing:0;
  text-transform:none; color:var(--ink-3); }
/* Dobradiça (Estoque atual) e resultado (Saldo projetado / se converter) pesam
   por SUPERFÍCIE. As duas réguas vermelhas em volta do saldo gritavam mais que
   os próprios números, que já são a única coisa colorida da matriz. */
.gc-mx tr.gc-hinge td, .gc-mx tr.gc-hinge td.gc-k { background:var(--panel-3); }
.gc-mx tr.gc-hinge td.gc-k { font-weight:700; }
.gc-mx tr.gc-result td, .gc-mx tr.gc-result td.gc-k { background:var(--panel-3); }
.gc-mx tr.gc-result td { border-top:var(--bs-border-width) solid var(--ink-3); }
.gc-mx tr.gc-result td.gc-k { font-weight:700; }
.gc-mx tr.gc-result .gc-cv { font-weight:700; font-size: var(--bi-fs-compact); }
.gc-mx tr.gc-dim td.gc-k { color:var(--ink-2); font-weight:400; }
.gc-mx tr.gc-dim .gc-cv { color:var(--ink-3); }
/* ── Mira ────────────────────────────────────────────────────────────────── */
/* Hover acende a linha inteira e a coluna inteira: em 13 colunas é o que
   impede ler o número de uma bitola na linha de outra. */
.gc-mx tbody tr.gc-row-on td, .gc-mx tbody tr.gc-row-on td.gc-k { background:var(--panel-3); }
.gc-mx tbody td.gc-col-on { background:var(--panel-3); }
.gc-mx thead th.gc-col-on { box-shadow: inset 0 -2px 0 var(--accent); }

/* Divisor do mês corrente na tira de meses: à esquerda fechado, à direita
   projeção. */
.gc-mdiv { flex:0 0 auto; align-self:stretch; width:var(--bs-border-width); background:var(--line); margin:0.25rem 0.375rem; }

/* afford: célula viva clicável (recorte L3) */
.gc-mx td.gc-cell.gc-hot { cursor:pointer; }
.gc-mx td.gc-cell.gc-hot:hover { background:var(--acc-soft); box-shadow: inset 0 0 0 var(--bs-border-width) var(--accent); }
/* Origem do drill: fica acesa enquanto o painel lateral mostra o conteúdo dela. */
.gc-mx td.gc-sel, .gc-mx td.gc-cell.gc-sel { box-shadow: inset 0 0 0 2px var(--accent); }
.gc-mx tbody tr:not(.gc-band):not(.gc-zone):not(.gc-dim) td.gc-k { cursor:pointer; }
.gc-mx tbody tr:not(.gc-band):not(.gc-zone):not(.gc-dim) td.gc-k:hover { color:var(--accent); }

/* ── Linha "carregando" (Task 7) ─────────────────────────────────────────── */
/* A fase que preenche esta linha ainda não chegou (backend manda
   `pendente:true`, sem `valores`) — sem drill, sem hover, só uma barra de
   esqueleto por célula no lugar do número. */
.gc-mx tr.gc-pendente td.gc-k { color:var(--ink-3); font-weight:400; cursor:default; }
.gc-mx tr.gc-pendente td.gc-cell { cursor:default; }
.gc-skel { display:inline-block; width:2.5rem; height:0.625rem; border-radius:var(--bs-border-radius-sm);
  background:linear-gradient(90deg, var(--panel-3) 25%, var(--line) 50%, var(--panel-3) 75%);
  background-size:200% 100%; animation:gc-skel-shimmer 1.4s ease-in-out infinite; }
@keyframes gc-skel-shimmer { 0% { background-position:200% 0; } 100% { background-position:-200% 0; } }
@media (prefers-reduced-motion: reduce) {
  .gc-skel { animation:none; background:var(--panel-3); }
}

/* ── Degradação Conexos ──────────────────────────────────────────────────── */
/* Banner de degradação: cor e contraste vêm de .alert-warning (Bootstrap);
   aqui só o layout em linha e o encaixe edge-to-edge dentro do card. */
.gc-degraded { display:flex; align-items:center; gap:0.5rem; margin:0;
  border-radius:0; border-left:0; border-right:0; border-top:0;
  font-size:0.875rem; font-weight:600; }
.gc-degraded i { flex:0 0 auto; }
/* Aviso de fonte fora do ar colado no subtítulo do cabeçalho ("Conexos
   indisponível"): o único espaço que separava os dois era o do HTML. */
.gc-zwarn { margin-left:0.5rem; }

/* (Overlay/diálogo/tabela de drill `.gc-ov/.gc-dlg/.gc-dt/.gc-drow` removidos —
   o drill agora usa o modal-padrão compartilhado abaixo, `biUtils.gridModal`.) */

/* === MODAL PADRÃO (biUtils.modalPadrao / gridModal) ============================
   Shell Bootstrap único (header/body/footer, título "Assunto — Item") + corpo de
   GRADE ordenável com thead/tfoot fixos. Body-appended → só tokens de :root
   (--ink, --line, --mono e variantes); nada de --panel/--accent (esses são
   .gc-scoped). NÃO escreva "asterisco+barra" dentro de comentário: fecha o
   comentário cedo e a regra seguinte some silenciosamente. */
/* Altura presa à viewport e UM só scroller: a grade. O corpo vira coluna flex que
   não rola; resumo, abas, pills e paginação ficam parados, e a sobra vai para o
   scroller da tabela (`.datatable-scroll` do DataTables ou `.fcds-gm__wrap` do
   gridModal), que rola com `thead` e `tfoot` grudados.
   Esta cadeia é o que sustenta o cabeçalho fixo — sem ela quem rola é o
   `.modal-body`, e aí `position:sticky` do `thead` não tem contra o que grudar e
   o cabeçalho da grade sai de vista. Cada seletor da lista do meio é um container
   intermediário que precisa repassar a altura adiante; um elo de fora e a altura
   morre ali (foi o que aconteceu com o `div` cru do `frameGrade`, que passou a
   levar `.fcds-modal__pane` justamente para entrar aqui). */
.fcds-modal .modal-body { display:flex; flex-direction:column; overflow:hidden; }
.fcds-modal .modal-body > * { flex:0 0 auto; }
.fcds-modal .tab-content,
.fcds-modal .tab-pane.active,
.fcds-modal [data-razao],
.fcds-modal [data-movimentos],
.fcds-modal .tbl-wrapper.datatable,
.fcds-modal .tbl-wrapper.datatable > .dataTables_wrapper,
.fcds-modal .fcds-modal__pane {
  display:flex; flex-direction:column; flex:1 1 auto; min-height:0;
}
.fcds-modal .datatable-scroll,
.fcds-modal .fcds-gm__wrap { flex:1 1 auto; min-height:0; max-height:none; }
/* Enquanto carrega, o alvo do loader recobra a reserva de altura — o
   `min-height:0` do item flex acima esmagaria o logo-loader a zero. */
.fcds-modal [data-bi-loading="tape"] { min-height: 11.75rem; }
/* Ícone de AÇÃO usa a cor de ação, não o cinza do shell: voltar e "mais info"
   são as duas coisas clicáveis do corpo, e vestidas de --ink-3 liam como
   decoração da moldura. */
.fcds-modal__voltar { border:0; background:transparent; color:var(--brand); cursor:pointer; padding:0 0.25rem; font-size:1rem; line-height:1; }
.fcds-modal__voltar:hover { color:var(--brand-ink); }
/* Metadado recua para 13px: antes era 20px, o MESMO tamanho do título, e assunto
   e contexto competiam. Rende mais no drill de estoque, cujo item é a descrição
   inteira do produto e quebrava o header em duas linhas (93px). */
.fcds-modal__item { color:var(--ink-3); font-weight:400; font-size: var(--bi-fs-compact); }
/* (A cifra do header saiu junto com o markup: era o mesmo número do TOTAL do
   rodapé, repetido a dois centímetros de distância.) */
/* (O `padding:0` que fazia a grade sangrar de borda a borda saiu: o corpo usa a
   calha de 1rem do Bootstrap como qualquer outro modal.) */
/* (A regra que escondia o rodapé no corpo de grade saiu: o shell do
   `modalPadrao` não emite mais `.modal-footer` nenhum, então ela não tinha
   sobre o que agir.) */
/* `flex:0 0 auto`: a faixa de abas é irmã do pane dentro de um `.fcds-modal__pane`
   (coluna flex). Sem isto ela encolheria junto com a grade ao faltar altura. */
.fcds-modal__tabs { padding:0.25rem 1rem 0; margin:0; flex:0 0 auto; }
.fcds-modal__tabs .nav-link { font-size: var(--bi-fs-compact); padding:0.25rem 0.625rem; color:var(--ink-3); }
.fcds-modal__tabs .nav-link.active { color:var(--ink); font-weight:700; }
/* (A faixa de escopo saiu: o recorte por bitola virou parte do TÍTULO do painel,
   e "ver todas as bitolas" já era o clique no rótulo da linha na matriz.) */
/* ── Chassi LATERAL (biUtils.gridPainel) ─────────────────────────────────── */
/* Mesmo corpo de grade do modal, moldura diferente: painel ancorado à direita
   que DOCA — `.main` cede a largura em vez de ficar coberto. Nasceu da matriz
   do gerencial, onde o gesto é comparar célula a célula: com modal, cada
   comparação custava abrir-fechar-abrir e a origem do drill ficava tapada.
   Alinhado ao rail lateral (abaixo da topbar sticky, que continua clicável). */
.fcds-lateral { position:fixed; top:52px; right:0; height:calc(100vh - 52px);
  width:var(--fcds-lateral-w, min(32.5rem, 92vw)); z-index:30; visibility:hidden; transform:translateX(100%);
  transition:transform .22s cubic-bezier(.22,1,.36,1), visibility .22s, width .22s cubic-bezier(.22,1,.36,1); }
.fcds-lateral[data-aberto] { transform:none; visibility:visible; }
.fcds-lateral .modal-content { height:100%; background:var(--surf); border:0;
  border-left:var(--bs-border-width) solid var(--line);
  border-radius:0; box-shadow:-1rem 0 2.5rem rgba(16,24,40,.10); }
/* Calhas EXPLÍCITAS. `.fcds-lateral` é um <aside>, não um `.modal`, então as
   custom properties `--bs-modal-*` não resolvem e o padding do header/body do
   Bootstrap cai para zero: título e botão de fechar nasciam colados na borda.
   Uma calha só (1rem) alinha título, chip de escopo e 1ª coluna da grade. */
.fcds-lateral .modal-header { padding:0.875rem 1rem 0.625rem; gap:0.5rem; align-items:flex-start;
  border-bottom:var(--bs-border-width) solid var(--line-2); }
.fcds-lateral .fcds-modal__titulo { margin:0; line-height:1.3; }
.fcds-lateral .btn-close { margin:0.125rem 0 0 auto; flex:0 0 auto; }
/* Corpo sem calha própria: a grade sangra de borda a borda e quem dá o recuo
   é a 1ª/última célula (1rem), senão o texto da tabela ficaria 32px para
   dentro enquanto o título fica em 16px. */
.fcds-lateral .modal-body { padding:0; }
/* No painel a largura é curta: coluna de texto encolhe com reticências em vez
   de empurrar a grade para o scroll horizontal — que jogava o TOTAL do rodapé
   para fora de vista. O texto inteiro fica no `title` da célula. */
.fcds-lateral .fcds-gm td:not(.fcds-gm__num) { max-width:15rem; overflow:hidden; text-overflow:ellipsis; }
.fcds-lateral .fcds-gm thead th { padding-top:0.375rem; padding-bottom:0.375rem; }
.fcds-lateral .fcds-gm tbody td { padding-top:0.3125rem; padding-bottom:0.3125rem; }
.fcds-lateral .fcds-gm tfoot td { padding-top:0.4375rem; padding-bottom:0.4375rem; }
.main { transition:margin-right .22s cubic-bezier(.22,1,.36,1); }
body[data-lateral] .main { margin-right:var(--fcds-lateral-w, min(32.5rem, 92vw)); }
/* Docar exige rail (3rem) + calhas (2.5rem) + o piso da matriz + o painel mais
   largo (42rem) — ~106.75rem. Abaixo disso ceder a largura não "abre espaço",
   espreme: a 1366px sobravam 606px de matriz e a célula que originou o drill
   saía de vista. Então o painel SOBREPÕE, como já fazia no mobile. */
@media (max-width:106.75rem) {
  body[data-lateral] .main { margin-right:0; }
}
@media (prefers-reduced-motion: reduce) {
  .fcds-lateral, .main { transition:none; }
}

.fcds-gm__wrap { overflow:auto; }
table.fcds-gm { border-collapse:collapse; width:100%; font-size: var(--bi-fs-compact); }
/* `text-align:left` NÃO volta aqui: `td` já é left por default do navegador, e a
   declaração só existia para — sem querer — vencer `.fcds-gm__num` (0,1,1 > 0,1,0).
   Era por isso que Qtd, R$ e data nunca alinharam à direita. O `th` precisa da
   declaração porque `th` é center por default.
   `border-right` também sai: com 7 colunas × 100+ linhas o quadriculado vira ruído.
   Quem separa o bloco numérico do bloco de texto agora é o respiro de §num. */
.fcds-gm th, .fcds-gm td { padding:0.25rem 0.625rem; white-space:nowrap; line-height:1.4;
  border-bottom:var(--bs-border-width) solid var(--line-2); }
.fcds-gm th { text-align:left; }
.fcds-gm tbody td:first-child, .fcds-gm thead th:first-child, .fcds-gm tfoot td:first-child { padding-left:1rem; }
.fcds-gm tbody td:last-child, .fcds-gm thead th:last-child, .fcds-gm tfoot td:last-child { padding-right:1rem; }
/* Coluna numérica ganha 6px a mais à esquerda: é o espaçamento que assume o
   trabalho da régua vertical removida. Sem ele, "12,7mm" cola em "39,6". */
.fcds-gm th.fcds-gm__num, .fcds-gm td.fcds-gm__num { text-align:right; padding-left:1rem;
  font-family:var(--mono); font-variant-numeric:tabular-nums; }
.fcds-gm thead th { position:sticky; top:0; z-index:2; background:var(--surf); cursor:pointer; user-select:none;
  padding-top:0.375rem; padding-bottom:0.375rem;
  font-size: var(--bi-fs-micro); letter-spacing:.09em; text-transform:uppercase; color:var(--ink-3);
  font-weight:700; border-bottom:var(--bs-border-width) solid var(--line); }
.fcds-gm thead th:hover { color:var(--ink); }
.fcds-gm thead th:focus-visible { outline:2px solid var(--acc); outline-offset:-2px; }
/* Seta de ordenação em slot de largura fixa — sem isto o cabeçalho reflowa a cada
   clique, porque a seta era concatenada ao texto. */
.fcds-gm__seta { display:inline-block; width:0.75rem; text-align:center; opacity:0.8; }
/* Total lê como banda: fundo próprio e régua de 1px (era 2px), sem peso extra. */
.fcds-gm tfoot td { position:sticky; bottom:0; z-index:2; background:var(--surf-2); font-weight:700;
  padding-top:0.3125rem; padding-bottom:0.3125rem; border-top:var(--bs-border-width) solid var(--ink); }
.fcds-gm tbody tr:hover td { background:var(--line-2); }
.fcds-gm__acao { width: 2.75rem; text-align:center; }
.fcds-gm__info { border:0; background:transparent; color:var(--brand); cursor:pointer; padding:0; font-size:1rem; line-height:1; }
.fcds-gm__info:hover { color:var(--brand-ink); }

/* ── Responsivo ──────────────────────────────────────────────────────────── */
@media (max-width:575.98px) {
  /* Calha 16px → 12px nas faixas próprias do componente; o cabeçalho ficou com a
     do Bootstrap. As faixas rolam na horizontal em vez de quebrar linha. */
  .fcds-modal__tabs { padding-left:0.75rem; padding-right:0.75rem;
    flex-wrap:nowrap; overflow-x:auto; }
  .fcds-gm th, .fcds-gm td { padding-left:0.5rem; padding-right:0.5rem; }
  .fcds-gm th.fcds-gm__num, .fcds-gm td.fcds-gm__num { padding-left:0.75rem; }
  .fcds-gm tbody td:first-child, .fcds-gm thead th:first-child, .fcds-gm tfoot td:first-child { padding-left:0.75rem; }
  .fcds-gm tbody td:last-child, .fcds-gm thead th:last-child, .fcds-gm tfoot td:last-child { padding-right:0.75rem; }
  .gc-mx td.gc-k, .gc-mx thead th.gc-rowh { width: 9.375rem; }
  .gc-mx col.gc-c-rowh { width: 9.375rem; }
}
/* ===== MERGED FROM bi/static/bi/css/inadimplencia.css (P5 — page-local dissolve) ===== */
/* ── Foco banner (FCDS inline status / active-filter banner) ─────────────── */

.foco-banner {
  margin:var(--bi-space-sm) var(--bi-space-md);
  padding:var(--bi-space-xs2) var(--bi-space-sm);
  border: var(--bs-border-width) solid color-mix(in srgb, var(--brand, var(--bi-text-primary)) 22%, transparent);
  border-radius: var(--bi-radius-sm);
  background: color-mix(in srgb, var(--brand, var(--bi-text-primary)) 6%, white);
  color: var(--bi-text-primary);
  font-size: var(--bi-fs-caption);
}

.foco-banner__clear {
  margin-left:var(--bi-space-sm);
  padding:0;
  border: 0;
  background: none;
  color: var(--brand, var(--negative-text));
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
}

/* ── Ranked list-row component (aging faixas + devedores) ─────────────────── */
/* Generated by inadimplencia.js (renderizarAgingTable / renderizarDevedores);
   this file is the sole definition — do not delete while that markup exists.   */

.top5__row {
  padding:var(--bi-space-sm) var(--bi-space-md);
  border-bottom: var(--bs-border-width) solid var(--line);
  border-left: 3px solid transparent;
  cursor: pointer;
  transition: background 120ms ease, border-left-color 120ms ease;
}

.top5__row:hover {
  background: var(--surf-2);
}

.top5__row--ativo {
  background: color-mix(in srgb, var(--negative-text) 6%, white);
  border-left-color: var(--negative-text);
}

/* Aging active uses per-faixa severity color (--faixa-cor set inline by JS) */
#bi-aging-lista .top5__row--ativo {
  background: color-mix(in srgb, var(--faixa-cor, var(--negative-text)) 8%, white);
  border-left-color: var(--faixa-cor, var(--negative-text));
}

.top5__rank {
  font-size: var(--bi-fs-caption);
  color: var(--bi-text-muted);
  font-weight: var(--bi-fw-semibold);
  flex-shrink: 0;
}

.top5__nome {
  font-size: var(--bi-fs-body);
  font-weight: var(--bi-fw-medium);
  color: var(--bi-text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
  min-width: 0;
}

.top5__row--ativo .top5__nome {
  color: var(--negative-text);
}

.top5__valor {
  font-family: var(--sans);
  font-size: 1.35rem;
  font-weight: var(--bi-fw-bold);
  color: var(--negative-text);
  line-height: 1;
  letter-spacing: -0.01em;
  white-space: nowrap;
  flex-shrink: 0;
}

.top5__bar-track { --barra-altura: 0.375rem; --barra-cor: var(--negative-text); margin-top:var(--bi-space-xs2); }

/* ── 2×2 analysis cards: equal-height scroll bodies ──────────────────────── */
/* The aging + devedores list bodies use the shared .card-scroll utility
   (custom.css) so they cap at --bi-scroll-cap and read at one height.
   See bi/templates/bi/inadimplencia.html (#bi-aging-card-body, #bi-top-clientes). */

/* ===== MERGED FROM bi/static/bi/css/mercado-importacao.css (P5 — page-local dissolve) ===== */
/* ============================================================================
   Mercado de Importação — folha de estilo própria da tela (rebuild "do zero").
   NÃO depende de main.css nem dos componentes legados (.card/.rank/.grid).
   Linguagem MODERNA: superfícies brancas macias, muito respiro, tipografia
   confiante (Roboto em numerais e corpo), paleta contida,
   barras desenhadas à mão (sem o visual padrão do Chart.js), micro-motion.

   Perspectiva: briefing competitivo de preço (inspirado no deck Logcomex
   FOUR × AWA × South Service) — veredito de preço como tese, estrutura de
   mercado como apoio. Tudo escopado em `.mx` para não vazar para o resto do app.
   ========================================================================== */

.mx {
  /* superfícies */
  --mx-panel: #ffffff;
  --mx-inset: #f5f7fa;          /* trilhos de barra, insets */
  --mx-ink: #0f1722;            /* near-black levemente frio */
  --mx-ink-2: #5b6573;
  --mx-ink-3: #98a1ae;
  --mx-line: #eef1f5;
  --mx-line-2: #e0e5ec;

  /* identidade / papéis (cor com significado) */
  --mx-four: #006bb5;           /* FOUR — azul da marca */
  --mx-four-soft: #e7f1fa;
  --mx-rival: #d97706;          /* concorrente nomeado — âmbar */
  --mx-rival-soft: #fdf1e1;
  --mx-other: #7c8aa0;          /* demais importadores — slate sólido (não "disabled") */
  --mx-bar: #2f7dc4;            /* barras de ranking neutras — azul confiante */

  /* veredito (semântico, tons modernos) */
  --mx-up: #e11d48;             /* mais cara = ruim (rosa-vermelho) */
  --mx-up-soft: #fde7ec;
  --mx-down: #059669;           /* mais barata = bom (esmeralda) */
  --mx-down-soft: #e1f4ed;

  --mx-radius: 20px;
  --mx-radius-sm: 13px;
  --mx-radius-xs: 9px;
  --mx-shadow: 0 1px 2px rgba(15, 23, 42, .04), 0 14px 32px -10px rgba(15, 23, 42, .12);
  --mx-shadow-sm: 0 1px 2px rgba(15, 23, 42, .05), 0 8px 18px -10px rgba(15, 23, 42, .10);
  --mx-gap:clamp(1rem, 1.4vw + 0.5rem, 1.5rem);

  color: var(--mx-ink);
  font-variant-numeric: tabular-nums;
}

.mx *,
.mx *::before,
.mx *::after { box-sizing: border-box; }

.mx-body[hidden] { display: none; }

/* ── Estado vazio / erro ──────────────────────────────────────────────────── */
.mx-empty {
  margin-top:var(--mx-gap);
  padding:clamp(1.5rem, 6vw, 3rem) 1.5rem;
  background: var(--mx-panel); border-radius: var(--mx-radius);
  box-shadow: var(--mx-shadow-sm);
  text-align: center; color: var(--mx-ink-2); font-size: 1rem; line-height: 1.6;
}

/* ════════════════════════════════════════════════════════════════════════════
   MASTHEAD — identidade do relatório + tamanho do mercado
   ════════════════════════════════════════════════════════════════════════════ */
.mx-mast {
  display: flex; align-items: flex-end; justify-content: space-between;
  flex-wrap: wrap; gap:1rem 3rem;
  padding:0.25rem 0 1.5rem;
}
.mx-mast__id { min-width: 0; }
.mx-mast__title {
  margin:0; font-family: var(--bi-font-display); font-weight: 600;
  font-size: clamp(2rem, 1.2rem + 3.2vw, 3.3rem); line-height: 0.98;
  letter-spacing: -0.015em; color: var(--mx-ink); text-wrap: balance;
}
/* faixa de totais do mercado — chips suaves */
.mx-totals { display: flex; flex-wrap: wrap; gap:0.5rem; margin:0; }
.mx-tot {
  display: flex; flex-direction: column; gap:0;
  padding:0.5rem 1rem; background: var(--mx-panel); border-radius: var(--mx-radius-xs);
  box-shadow: var(--mx-shadow-sm);
}
.mx-tot__l { font-size: 0.875rem; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase; color: var(--mx-ink-3); white-space: nowrap; }
.mx-tot__v { font-family: var(--bi-font-display); font-weight: 600; font-size: 1.3rem; line-height: 1; color: var(--mx-ink); white-space: nowrap; }
.mx-tot--lead { background: var(--mx-four); }
.mx-tot--lead .mx-tot__l { color: rgba(255, 255, 255, .78); }
.mx-tot--lead .mx-tot__v { color: var(--bi-text-on-accent); font-size: 1.55rem; }

/* ════════════════════════════════════════════════════════════════════════════
   VEREDITO — a tese da página (assinatura)
   ════════════════════════════════════════════════════════════════════════════ */
/* Bordo/bg/radius/sombra vêm de .card.shadow-sm.border-0 (aplicado no
   template); aqui só o residual sem primitiva: grid interno de 2 colunas +
   espaçamentos responsivos (clamp) que o .card fixo não cobre. */
.mx-verdict {
  display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  gap:clamp(1.5rem, 3vw, 3rem);
  margin-top:var(--mx-gap);
  padding:clamp(1.5rem, 2.4vw, 3rem);
}
.mx-verdict__kick {
  display: block; font-size: 0.875rem; font-weight: 600; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--mx-ink-3); margin-bottom:1rem;
}
.mx-verdict__headline {
  margin:0 0 1.5rem; display: flex; align-items: baseline; flex-wrap: wrap; gap:0 1rem;
  line-height: 0.9;
}
.mx-delta {
  font-family: var(--bi-font-display); font-weight: 700;
  font-size: clamp(3.2rem, 2rem + 6vw, 6rem); line-height: 0.84; letter-spacing: -0.03em;
  color: var(--mx-ink);
}
.mx-delta--up { color: var(--mx-up); }
.mx-delta--down { color: var(--mx-down); }
.mx-delta--brand { color: var(--mx-four); }
.mx-verdict__word {
  font-size: clamp(1.15rem, 0.8rem + 1.1vw, 1.7rem); font-weight: 600; color: var(--mx-ink);
  max-width: 18ch;
}
.mx-verdict__word b { font-weight: 700; }

/* head-to-head: FOUR vs rival mais barato (o callout do deck) */
.mx-h2h { display: flex; flex-direction: column; gap:0.5rem; max-width: 28.75rem; }
.mx-h2h__row { display: grid; grid-template-columns: 4rem 1fr auto; align-items: center; gap:0.5rem; }
.mx-h2h__name { font-size: 0.875rem; font-weight: 700; letter-spacing: 0.02em; text-transform: uppercase; color: var(--mx-ink-2); }
.mx-h2h__row--four .mx-h2h__name { color: var(--mx-four); }
.mx-h2h__row--rival .mx-h2h__name { color: var(--mx-rival); }
.mx-h2h__track { height: 0.875rem; --bs-progress-bg: var(--mx-inset); border-radius: var(--bs-border-radius-pill); }
.mx-h2h__fill { border-radius: var(--bs-border-radius-pill); transform-origin: left center; }
.mx-h2h__row--four .mx-h2h__fill { --bs-progress-bar-bg: var(--mx-four); }
.mx-h2h__row--rival .mx-h2h__fill { --bs-progress-bar-bg: var(--mx-rival); }
.mx-h2h__val { font-family: var(--bi-font-display); font-weight: 600; font-size: 1.05rem; color: var(--mx-ink); white-space: nowrap; }
.mx-h2h__foot { margin:0.25rem 0 0; font-size: 0.875rem; color: var(--mx-ink-3); }

/* coluna direita: fatia + rank */
.mx-verdict__stats {
  display: flex; flex-direction: column; justify-content: center; gap:1.5rem;
  padding-left:clamp(1.5rem, 3vw, 3rem); border-left: var(--bs-border-width) solid var(--mx-line);
}
.mx-stat { display: flex; flex-direction: column; gap:0.25rem; }
.mx-stat__v { font-family: var(--bi-font-display); font-weight: 700; font-size: clamp(2.2rem, 1.4rem + 2.4vw, 3.1rem); line-height: 0.92; letter-spacing: -0.02em; color: var(--mx-ink); }
.mx-stat--share .mx-stat__v { color: var(--mx-four); }
.mx-stat__l { font-size: 0.875rem; color: var(--mx-ink-2); max-width: 22ch; }

/* ════════════════════════════════════════════════════════════════════════════
   PAINEL genérico + cabeçalho
   ════════════════════════════════════════════════════════════════════════════ */
/* Bordo/bg/radius/sombra e a estrutura cabeçalho+corpo vêm de
   .card.shadow-sm.border-0 > .card-header (+ utilities d-flex/justify-
   content-between/align-items-baseline/flex-wrap/gap-2) > .card-body,
   aplicado direto no template. .card já é flex-column e .card-body já é
   flex:1 1 auto (Bootstrap), então os painéis de gráfico (ex-.mx-panel--chart)
   não precisam mais de regra própria — só ganham a classe `d-flex` no
   .card-body para os filhos que crescem (.mx-spark/.mx-transporte, abaixo)
   se esticarem dentro dele. Residual: min-width:0 evita overflow do item
   dentro do CSS Grid (.mx-grid), efeito que o .card sozinho não resolve. */
.mx-panel { min-width: 0; }
.mx-panel__title { margin:0; font-size: 1.02rem; font-weight: 700; letter-spacing: -0.01em; color: var(--mx-ink); }
.mx-panel__note { font-size: 0.875rem; color: var(--mx-ink-3); }

/* ── Escada de preços (painel destacado) ──────────────────────────────────── */
.mx-ladder { margin-top:var(--mx-gap); }
.mx-legend { display: flex; flex-wrap: wrap; gap:0.5rem 1rem; margin:-0.25rem 0 1rem; }
.mx-legend__i { display: inline-flex; align-items: center; gap:0.5rem; font-size: 0.875rem; color: var(--mx-ink-2); }
.mx-legend__i::before { content: ''; width: 0.6875rem; height: 0.6875rem; border-radius: var(--bs-border-radius-sm); }
.mx-legend__i--four::before { background: var(--mx-four); }
.mx-legend__i--rival::before { background: var(--mx-rival); }
.mx-legend__i--other::before { background: var(--mx-other); }

/* toggle preço/peso — pill segmentado moderno */
.mx-toggle { display: inline-flex; padding:0.25rem; background: var(--mx-inset); border-radius: var(--bs-border-radius-pill); }
.mx-toggle__b {
  appearance: none; border: 0; background: transparent; cursor: pointer;
  font: inherit; font-size: 0.875rem; font-weight: 600; color: var(--mx-ink-2);
  padding:0.25rem 1rem; border-radius: var(--bs-border-radius-pill); transition: background .18s ease, color .18s ease;
}
.mx-toggle__b[aria-pressed="true"] { background: var(--mx-panel); color: var(--mx-ink); box-shadow: var(--mx-shadow-sm); }
.mx-toggle__b:focus-visible { outline: 2px solid var(--mx-four); outline-offset: 2px; }

/* barras horizontais da escada */
.mx-bars { display: flex; flex-direction: column; gap:1rem; }
.mx-bar { display: grid; grid-template-columns: minmax(6.875rem, 10.5rem) 1fr; align-items: center; gap:1rem; }
.mx-bar__name { font-size: 0.875rem; color: var(--mx-ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mx-bar--self .mx-bar__name { font-weight: 700; color: var(--mx-four); }
.mx-bar__track { position: relative; display: flex; align-items: center; gap:0.5rem; }
.mx-bar__fill { flex: 0 0 auto; height: 1.625rem; border-radius: var(--bs-border-radius-lg); transform-origin: left center; min-width: 0.1875rem; }
.mx-bar__fill--four { background: var(--mx-four); }
.mx-bar__fill--rival { background: var(--mx-rival); }
.mx-bar__fill--other { background: var(--mx-other); }
.mx-bar__val { font-family: var(--bi-font-display); font-weight: 600; font-size: 1rem; color: var(--mx-ink); white-space: nowrap; }

/* ════════════════════════════════════════════════════════════════════════════
   SEÇÕES + GRID
   ════════════════════════════════════════════════════════════════════════════ */
.mx-sec { display: flex; align-items: baseline; gap:0.5rem; margin:clamp(1.5rem, 4vw, 3rem) 0 0; }
.mx-sec__t { margin:0; font-family: var(--bi-font-display); font-weight: 600; font-size: 1.55rem; letter-spacing: -0.01em; color: var(--mx-ink); }
.mx-sec__s { font-size: 0.875rem; color: var(--mx-ink-3); }

.mx-grid { display: grid; gap:var(--mx-gap); margin-top:var(--mx-gap); }
.mx-grid--8-4 { grid-template-columns: 2fr 1fr; }
.mx-grid--2 { grid-template-columns: 1fr 1fr; }

/* ── Lista ranqueada (própria — substitui .rank) ───────────────────────── */
.mx-rank { display: flex; flex-direction: column; }
.mx-rank__row { padding:0.5rem 0; border-top: var(--bs-border-width) solid var(--mx-line); }
.mx-rank__row:first-child { border-top: 0; }
.mx-rank__top { display: flex; align-items: baseline; gap:0.5rem; margin-bottom:0.5rem; }
.mx-rank__pos { flex-shrink: 0; min-width: 1.375rem; font-family: var(--bi-font-display); font-weight: 600; font-size: 1rem; color: var(--mx-ink-3); }
.mx-rank__name { flex: 1 1 auto; min-width: 0; font-size: 0.875rem; color: var(--mx-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mx-rank__val { flex-shrink: 0; font-family: var(--bi-font-display); font-weight: 600; font-size: 1rem; color: var(--mx-ink); }
.mx-rank__sub { margin:-0 0 0.5rem 1.5rem; font-size: 0.875rem; color: var(--mx-ink-3); }
.mx-rank__track { height: 0.4375rem; --bs-progress-bg: var(--mx-inset); border-radius: var(--bs-border-radius-pill); }
.mx-rank__fill { border-radius: var(--bs-border-radius-pill); --bs-progress-bar-bg: var(--mx-bar); transform-origin: left center; }
.mx-rank__row--self .mx-rank__name { font-weight: 700; color: var(--mx-four); }
.mx-rank__row--self .mx-rank__fill { --bs-progress-bar-bg: var(--mx-four); }
.mx-rank__row--self .mx-rank__pos { color: var(--mx-four); }

/* card-scroll: limita altura de listas longas mantendo painéis alinhados */
.mx-scroll { max-height: 22.5rem; overflow: auto; }
.mx-scroll::-webkit-scrollbar { width: 0.5rem; }
.mx-scroll::-webkit-scrollbar-thumb { background: var(--mx-line-2); border-radius: var(--bs-border-radius-pill); }

/* ── Tendência mensal (spark de barras verticais — próprio) ───────────────── */
.mx-spark { flex: 1 1 auto; width: 100%; display: flex; align-items: flex-end; justify-content: space-around; gap:clamp(0.5rem, 2vw, 1.5rem); min-height: 13.125rem; padding-top:1.5rem; }
.mx-spark__col { flex: 1 1 0; display: flex; flex-direction: column; align-items: center; gap:0.5rem; height: 100%; justify-content: flex-end; min-width: 0; }
.mx-spark__bar-wrap { flex: 1 1 auto; width: 100%; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap:0.25rem; }
.mx-spark__bar { width: min(100%, 60px); border-radius: var(--bs-border-radius-lg) var(--bs-border-radius-lg) 0 0; background: var(--mx-four); transform-origin: bottom center; min-height: 0.1875rem; }
.mx-spark__v { font-family: var(--bi-font-display); font-weight: 600; font-size: 0.875rem; color: var(--mx-ink-2); white-space: nowrap; }
.mx-spark__x { font-size: 0.875rem; color: var(--mx-ink-3); white-space: nowrap; }

/* ── Mapa UF (Leaflet) + ranking ──────────────────────────────────────────── */
.mx-geo { display: grid; grid-template-columns: 1.4fr 1fr; gap:1rem; align-items: start; }
.mx-geo__map { height: 20rem; border-radius: var(--mx-radius-sm); overflow: hidden; background: var(--mx-inset); }
.mx-geo__map .leaflet-container { background: transparent; font: inherit; outline: none; }
.mx-geo__map .leaflet-interactive:focus { outline: none; }

/* ── Donut do modal de transporte (conic-gradient — próprio, sem Chart.js) ── */
/* display:flex + flex:1 1 auto residual: antes vinha de
   `.mx-panel--chart > :last-child` (removido); precisa continuar crescendo
   dentro do .card-body.d-flex e sendo container flex para o .mx-donut-wrap. */
.mx-transporte { width: 100%; display: flex; flex: 1 1 auto; }
.mx-donut-wrap { flex: 1 1 auto; width: 100%; display: flex; align-items: center; justify-content: center; gap:clamp(1rem, 3vw, 3rem); flex-wrap: wrap; }
.mx-donut { --mx-donut-bg: conic-gradient(var(--mx-inset) 0 100%);
  flex-shrink: 0; width: clamp(160px, 14vw, 210px); aspect-ratio: 1; border-radius: 50%;
  background: var(--mx-donut-bg);
  -webkit-mask: radial-gradient(circle 60px at center, transparent 98%, var(--ink) 100%);
          mask: radial-gradient(circle 60px at center, transparent 98%, var(--ink) 100%);
}
.mx-donut-leg { display: flex; flex-direction: column; gap:0.5rem; min-width: 0; }
.mx-donut-leg__i { display: grid; grid-template-columns: 0.75rem 1fr auto; align-items: center; gap:0.5rem; font-size: 0.875rem; }
.mx-donut-leg__dot { width: 0.75rem; height: 0.75rem; border-radius: var(--bs-border-radius-sm); }
.mx-donut-leg__l { color: var(--mx-ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mx-donut-leg__v { font-family: var(--bi-font-display); font-weight: 600; color: var(--mx-ink); }

.mx-mini-empty { padding:1.5rem 0.5rem; text-align: center; color: var(--mx-ink-3); font-size: 0.875rem; }

/* ── Picker no topbar (escopo global, fora de .mx) ────────────────────────── */
.mi-pick { display: flex; align-items: center; gap:0.5rem; min-width: 0; }
.mi-pick__lab { font-size: 0.875rem; font-weight: 600; color: var(--bi-text-secondary); }
.mi-pick__sel { width: auto; min-width: 10.625rem; max-width: 21.25rem; }
.mi-pick__per { font-size: 0.875rem; white-space: nowrap; }

/* ════════════════════════════════════════════════════════════════════════════
   MOTION — entrada suave + crescimento de barras (respeita reduced-motion)
   ════════════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: no-preference) {
  .mx-verdict, .mx-ladder, .mx-panel, .mx-mast { animation: mx-rise .5s cubic-bezier(.22, 1, .36, 1) both; }
  .mx-ladder { animation-delay: .04s; }
  @keyframes mx-rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

  .mx-bar__fill, .mx-rank__fill, .mx-h2h__fill { animation: mx-grow-x .55s cubic-bezier(.22, 1, .36, 1) both; }
  @keyframes mx-grow-x { from { transform: scaleX(0); } to { transform: scaleX(1); } }
  .mx-spark__bar { animation: mx-grow-y .55s cubic-bezier(.22, 1, .36, 1) both; }
  @keyframes mx-grow-y { from { transform: scaleY(0); } to { transform: scaleY(1); } }
}

/* ════════════════════════════════════════════════════════════════════════════
   RESPONSIVO
   ════════════════════════════════════════════════════════════════════════════ */
@media (max-width:991.98px) {
  .mx-grid--8-4, .mx-grid--2 { grid-template-columns: 1fr; }
  .mx-geo { grid-template-columns: 1fr; }
}
@media (max-width:767.98px) {
  .mx-verdict { grid-template-columns: 1fr; }
  .mx-verdict__stats { flex-direction: row; gap:1.5rem; padding-left:0; border-left: 0; padding-top:1.5rem; border-top: var(--bs-border-width) solid var(--mx-line); }
  .mx-bar { grid-template-columns: 6rem 1fr; }
  .mx-tot--lead { width: 100%; }
}

/* .fresh (badge de frescor) é canônico único acima (§ Badge de frescor) —
   dedup: o bloco duplicado que vivia aqui (hardcode #059669) foi removido. */

/* ===== MERGED FROM bi/static/bi/css/metas.css (P5 — page-local dissolve) ===== */
/* Editor de Metas — master-detail. Classes .met-* globais (namespaced). Tema claro. */
/* Surfaces (.card/.grid), tokens e spans vêm de static/fcds/*. Aqui só o que é
   específico do editor master-detail (roster, grid de metas, célula editável). */

/* O .content de base_fcds.html já fornece o padding da página — não duplicar. */

/* ── toolbar no topbar (empresa/ano + status); sem engine fcds-filterbar pois a
   página não tem biFiltros — os controles vivem nos blocks topbar_filters/_actions ── */
/* empresa/ano vivem dentro do .pop (chip do topbar) — empilhados */
.met-tb-field {
    display: flex;
    flex-direction: column;
    gap:0.25rem;
    font-size: 0.875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--ink-3);
    margin-bottom:0;
}
.met-tb-field + .met-tb-field { margin-top:0.5rem; }
.met-tb-field select { width: 100%; min-width: 11rem; }
/* no mobile o crumb empurra o chip p/ a direita — ancora o pop pela direita
   p/ não encostar na borda da viewport. */
@media (max-width:575.98px) {
  #met-cfg-pop { left: auto; right: 0; }
}
.met-status {
    font-size: 0.875rem;
    font-weight: 500;
    min-height: 1rem;
    white-space: nowrap;
}

/* ── workspace master-detail (.grid fornece colunas; .card fornece superfície) ── */
.met-workspace {
    align-items: stretch;
    min-height: 65vh;
}
/* roster e detail são .card — zeramos o padding para que listas/grid encostem nas
   bordas; o card-hd recupera o respiro do topo. */
.met-roster,
.met-detail {
    padding:0;
    overflow: hidden;
}
.met-roster {
    align-self: flex-start;
    position: sticky;
    top: 0.5rem;
}
.met-roster .card-hd {
    margin:0;
    padding:var(--bi-space-sm) 0.5rem;
    background: var(--surf-2);
    border-bottom: var(--bs-border-width) solid var(--line);
}
.met-detail {
    display: flex;
    flex-direction: column;
}
.met-list { list-style: none; margin:0; padding:var(--bi-space-xs); }
.met-list__item {
    padding:0.5rem 0.5rem;
    border-radius: var(--bs-border-radius);
    font-size: 0.875rem;
    cursor: pointer;
    color: var(--ink);
    transition: background 0.12s;
}
/* hover (não-ativo): cinza nítido contra o painel branco do roster. */
/* O override de item ativo do met-list saiu daqui: virou a regra canônica
   `.list-group-item.active` na seção de estados de seleção. O bug de texto branco
   sumindo no hover morreu junto — no tratamento canônico o texto é escuro, então
   nenhuma combinação de fundo claro o apaga. */
.met-grid-titulo {
    font-size: 1rem;
    font-weight: 700;
    margin:0;
    color: var(--ink);
}
/* Rola nos 2 eixos DENTRO do painel (altura limitada) — assim o thead (linha de
   cabeçalho) e a 1ª coluna ficam fixos. */
.met-grid-scroll {
    overflow: auto;
    max-height: 72vh;
}

/* ── grid ─────────────────────────────────────────────────────────────────── */
.met-grid {
    border-collapse: separate;
    border-spacing: 0;
    width: 100%;
    font-size: 0.875rem;
}
.met-grid th,
.met-grid td {
    border-bottom: var(--bs-border-width) solid var(--line);
    padding:var(--bi-space-xs) var(--bi-space-xs2);
    white-space: nowrap;
}
.met-grid thead th {
    position: sticky;
    top: 0;
    background: var(--surf-2);
    z-index: 2;
    font-size: 0.875rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--ink-3);
    text-align: center;
}
.met-th-rotulo,
.met-rotulo {
    position: sticky;
    left: 0;
    background: var(--surf);
    z-index: 1;
    text-align: left;
    min-width: 12.5rem;
    box-shadow: 1px 0 0 var(--line);
}
.met-th-rotulo { background: var(--surf-2); z-index: 3; }
.met-rotulo-sub { display: block; font-weight: 600; color: var(--ink); min-height: 0.2rem; }
.met-rotulo-tipo {
    display: flex; align-items: center; gap:var(--bi-space-xs2);
    font-size: 0.875rem; color: var(--ink-3);
}
/* marcador semântico da família do eixo (reforça o rótulo textual, não substitui).
   As 4 famílias usam tokens categóricos distintos p/ não colapsarem em 2 cores. */
.met-rotulo-tipo::before {
    content: ""; flex: none; width: 0.4375rem; height: 0.4375rem; border-radius: var(--bs-border-radius-sm);
    background: var(--ink-3);
}
.met-fam--receita::before { background: var(--cat-1); }
.met-fam--margem::before  { background: var(--cat-4); }
.met-fam--volume::before  { background: var(--cat-6); }
.met-fam--despesa::before { background: var(--cat-7); }
/* separador entre sub-segmentos (1ª linha de cada grupo) */
.met-grid tbody tr.met-grupo > td { border-top: 2px solid var(--line); }

.met-td-mes { padding:var(--bi-space-3xs); }
.met-cell{ width:9.5rem; text-align:right; font-variant-numeric:tabular-nums; }
.met-total {
    text-align: right;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
    background: var(--surf-2);
}
/* total/média em recálculo no backend (debounce pós-edição) — mantém o valor
   anterior visível, só esmaece até a resposta chegar (não bloqueia digitação) */
.met-total--pendente { color: var(--ink-3); }
.met-acao { text-align: center; }
/* ── adicionar linha ──────────────────────────────────────────────────────── */
.met-add {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap:var(--bi-space-sm);
    padding:0.5rem 1rem;
    border-top: var(--bs-border-width) solid var(--line);
    background: var(--surf-2);
}
.met-add__rotulo { font-size: 0.875rem; color: var(--ink-3); }
.met-add select { min-width: 11rem; }

@media (max-width: 992px) {
    .met-roster { position: static; }
}
@media (max-width: 768px) {
    .met-list__item { padding:0.5rem 0.5rem; font-size: 1rem; min-height: 2.75rem; display: flex; align-items: center; }
}

/* ===== MERGED FROM static/css/forecast-comex.css (P5 — page-local dissolve) ===== */
/* ============================================================
   Forecast Comex — FCDS reskin
   Proprietary "FIDS" styling dropped (IBM Plex + bespoke header).
   Now built on the FCDS design language: the page uses the FCDS
   shell (topbar actions + .kpiband stats + .card board); this file
   only styles the board's own grid/rows/badges/obs/modals/drawer,
   all through the FCDS token set (--fc-* are FCDS-aliased tokens).
   ============================================================ */

/* off-screen drawer must not trigger horizontal scroll.
   Escopado à própria tela: como regra global (`body{...}`) vinda de uma folha
   page-local, atingia todas as páginas e podia matar `position:sticky` em
   descendentes. Mesmo padrão `body:has(...)` já usado pela tracking-comex. */
body:has(.page[data-pagina="forecast_comex"]) { overflow-x: hidden; }

/* shared 6-column grid (Processo · Produto · Chegada · Entrega · Freetime · Ações).
   Col-headers, rows and skeleton rows MUST stay in lockstep. */
.fids-col-headers,
.fids-row {
  display: grid;
  grid-template-columns:
    minmax(190px, 1.3fr) minmax(170px, 1.4fr) 156px 156px 168px 118px;
  gap:var(--bi-space-md, 1rem);
  align-items: start;
}

/* Filtros = .btn-check + .btn do Bootstrap; a barra é utilitária no template. */

/* ── Column headers ────────────────────────────────────────── */
.fids-col-headers {
  padding:0 0.25rem 0.5rem;
  margin-bottom:0;
  border-bottom: var(--bs-border-width) solid var(--fc-border);
}
.fids-col-header {
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-3);
  line-height: 1.2;
}
.fids-col-header-sub {
  display: block;
  font-size: 0.875rem;
  font-weight: 500;
  letter-spacing: .03em;
  color: var(--ink-4);
  text-transform: none;
}

/* ── Rows ──────────────────────────────────────────────────── */
.fids-row {
  padding:0.5rem 0.25rem;
  border-bottom: var(--bs-border-width) solid var(--fc-border);
  animation: fids-row-in .28s ease both;
  transition: background var(--fc-transition);
}
.fids-row:hover { background: var(--surf-2); }
.fids-row--urgent { box-shadow: inset 3px 0 0 var(--negative); }
@keyframes fids-row-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

.fids-cell { min-width: 0; display: flex; flex-direction: column; gap:0.25rem; }
/* A célula é uma coluna flex: sem isto o badge estica na largura toda da coluna
   (o `align-self` vinha dos .fids-*-badge bespoke que viraram .badge). */
.fids-cell > .badge { align-self: flex-start; }
.fids-cell--acoes { flex-direction: row; align-items: flex-start; gap:0.25rem; flex-wrap: wrap; }

.fids-processo-head { display: flex; align-items: center; gap:0.5rem; }
.fids-transport-icon { color: var(--ink-3); font-size: 0.875rem; width: 1rem; text-align: center; flex-shrink: 0; }
.fids-processo-code { font-family: var(--bi-font-mono); font-weight: 600; font-size: 0.875rem; color: var(--ink); word-break: break-word; }

.fids-produto-item { display: flex; flex-direction: column; gap:0; padding:0 0; }
.fids-produto-item + .fids-produto-item { margin-top:0.25rem; padding-top:0.25rem; border-top: var(--bs-border-width) dashed var(--fc-border); }
.fids-produto-item-desc { font-size: 0.875rem; color: var(--ink); line-height: 1.3; }
.fids-produto-item-qty { font-family: var(--bi-font-mono); font-size: 0.875rem; color: var(--ink-3); }

/* ── Date pairs (Chegada / Entrega) ────────────────────────── */
.fids-date-pair { display: flex; flex-direction: column; gap:0.25rem; }
.fids-date-prev-label {
  display: block;
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.fids-date-prev { font-family: var(--bi-font-mono); font-size: 0.875rem; color: var(--ink-2); }
.fids-date-real { font-family: var(--bi-font-mono); font-size: 0.875rem; font-weight: 600; color: var(--ink); }
.fids-date-real--empty, .fids-entrega-vazio { color: var(--ink-4); font-weight: 400; }
.fids-entrega-real { font-family: var(--bi-font-mono); font-size: 0.875rem; font-weight: 600; color: var(--positive-text); }
.fids-eta-ts { margin-left:0.25rem; font-family: var(--bi-font-mono); font-size: 0.875rem; font-weight: 400; color: var(--ink-4); letter-spacing: 0; }

/* ── Badges (urgência) — pill FCDS: bg sutil + dot + texto ──── */

.fids-badge-dot { width: 0.375rem; height: 0.375rem; border-radius: 50%; background: currentColor; flex-shrink: 0; }

/* ── Freetime ──────────────────────────────────────────────── */
.fids-cell--freetime { gap:0.25rem; }
.fids-freetime-prazo { font-family: var(--bi-font-mono); font-size: 0.875rem; color: var(--ink-2); }
.fids-freetime-na { color: var(--ink-4); font-size: 0.875rem; }
/* ── Situação badge / meta badge / containers ──────────────── */

.fids-searates-pin { font-size: 0.875rem; }

/* ── Observação inline ─────────────────────────────────────── */
.fids-obs-secao { align-self: flex-start; max-width: 100%; }
.fids-obs-container { display: flex; flex-direction: column; gap:0.25rem; }
.fids-obs-display {
  font-size: 0.875rem;
  line-height: 1.35;
  color: var(--ink-2);
  cursor: text;
  border-radius: var(--fc-radius);
}
.fids-obs-secao--processo .fids-obs-display {
  border: var(--bs-border-width) solid var(--fc-border);
  background: var(--surf);
  padding:0.25rem 0.5rem;
}
.fids-obs-secao--processo .fids-obs-display:hover { border-color: var(--line-3); background: var(--surf-2); }
.fids-obs--vazio { color: var(--ink-4); }
.fids-obs--placeholder { color: var(--ink-4); font-style: italic; }
.fids-obs-edit { display: flex; flex-direction: column; gap:0.25rem; }
/* .form-control-sm + só a largura mínima que a célula da grade exige. */
.fids-obs-textarea { min-width: 11.25rem; resize: vertical; }
.fids-obs-actions { display: flex; gap:0.25rem; }

.fids-obs-status { font-size: 0.875rem; color: var(--fc-urgent-fg); }

/* ── Loading / skeleton / empty / error ────────────────────── */
/* .fids-loading/.fids-skeleton removidos — loading unificado (overlay Bootstrap). */

.fids-empty { display: flex; flex-direction: column; align-items: center; gap:0.5rem; padding:3rem 0; text-align: center; }
.fids-empty-icon { font-size: 2rem; color: var(--ink-4); }
.fids-empty-title { font-size: 1rem; font-weight: 600; color: var(--ink-2); }
.fids-empty-sub, .fids-empty-ts { font-size: 0.875rem; color: var(--ink-3); }
.fids-empty-ts { color: var(--ink-4); }

.fids-error { display: flex; flex-direction: column; align-items: center; gap:0.5rem; padding:3rem 0; text-align: center; }
.fids-error-icon { font-size: 1.8rem; color: var(--fc-urgent-fg); }
.fids-error-msg { font-size: 1rem; font-weight: 600; color: var(--ink); }
.fids-error-hint { font-size: 0.875rem; color: var(--ink-3); }

/* ── Legenda ───────────────────────────────────────────────── */
.fids-legend { display: flex; align-items: center; flex-wrap: wrap; gap:0.5rem; padding-top:1rem; margin-top:0.25rem; border-top: var(--bs-border-width) solid var(--fc-border); }
.fids-legend-label { font-size: 0.875rem; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; color: var(--ink-3); }

/* ══════════════════════════════════════════════════════════
   MODAIS — overlay único compartilhado, shell = .modal do Bootstrap
   (dialog/content/header/body/footer/btn-close). Só sobra aqui o que
   é conteúdo próprio deste modal.
   ══════════════════════════════════════════════════════════ */
.fids-modal-codigo { font-family: var(--bi-font-mono); font-weight: 600; color: var(--ink-2); }
.fids-modal-loading { display: flex; align-items: center; gap:0.5rem; color: var(--ink-3); font-size: 0.875rem; }
.fids-modal-status { font-size: 0.875rem; color: var(--ink-3); }
.fids-modal-marcar-todos { display: flex; align-items: center; gap:0.5rem; flex-wrap: wrap; padding-bottom:0.5rem; border-bottom: var(--bs-border-width) solid var(--fc-border); }
.fids-modal-container-list { display: flex; flex-direction: column; gap:0.25rem; max-height: 20rem; overflow: auto; }
.fids-modal-container-row { display: flex; align-items: center; justify-content: space-between; gap:0.5rem; }
.fids-modal-container-num { font-family: var(--bi-font-mono); font-size: 0.875rem; color: var(--ink); }

/* tracking modal */
.fids-tracking-header { flex-direction: column; align-items: flex-start; gap:0.25rem; }
.fids-tracking-titulo { display: flex; align-items: center; gap:0.5rem; }
.fids-tracking-status { font-size: 0.875rem; font-weight: 600; color: var(--acc-ink); }
.fids-tracking-submeta { font-size: 0.875rem; color: var(--ink-3); margin-bottom:0.5rem; }
.fids-tracking-sep { margin:0 0.25rem; color: var(--ink-4); }
.fids-tracking-rota { display: flex; align-items: center; gap:0.5rem; flex-wrap: wrap; padding:0.5rem 0.5rem; background: var(--surf-2); border-radius: var(--fc-radius-md); margin-bottom:0.5rem; }
.fids-tracking-rota-ponto { font-weight: 600; font-size: 0.875rem; color: var(--ink); }
.fids-tracking-rota-seta { color: var(--ink-4); }
.fids-tracking-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(9.375rem, 1fr)); gap:0.5rem 1rem; margin-bottom:1rem; }
.fids-tracking-linha { display: flex; flex-direction: column; gap:0; }
.fids-tracking-linha-label { font-size: 0.875rem; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; color: var(--ink-4); }
.fids-tracking-linha-valor { font-size: 0.875rem; color: var(--ink); font-family: var(--bi-font-mono); }
.fids-tracking-log-titulo { font-size: 0.875rem; font-weight: 700; color: var(--ink-2); margin-bottom:0.5rem; }
.fids-tracking-vazio { display: flex; flex-direction: column; align-items: center; gap:0.25rem; padding:1.5rem 0; text-align: center; color: var(--ink-3); }
.fids-tracking-vazio i { font-size: 1.6rem; color: var(--ink-4); }
.fids-tracking-vazio-sub { font-size: 0.875rem; color: var(--ink-4); }

/* timeline */
.fids-tl { list-style: none; margin:0; padding:0; }
.fids-tl-item { position: relative; padding:0 0 1rem 1.5rem; }
.fids-tl-item::before { content: ""; position: absolute; left: 6px; top: 14px; bottom: 0; width: 0.125rem; background: var(--fc-border); }
.fids-tl-item:last-child::before { display: none; }
.fids-tl-dot { position: absolute; left: 0; top: 3px; width: 0.8125rem; height: 0.8125rem; border-radius: 50%; background: var(--surf); border: 2px solid var(--line-3); }
.fids-tl-item--done .fids-tl-dot { background: var(--positive); border-color: var(--positive); }
.fids-tl-item--future { opacity: .6; }
.fids-tl-data { font-family: var(--bi-font-mono); font-size: 0.875rem; color: var(--ink-3); }
.fids-tl-desc { font-size: 0.875rem; font-weight: 600; color: var(--ink); margin:0 0; }
.fids-tl-local { display: flex; align-items: center; gap:0.25rem; font-size: 0.875rem; color: var(--ink-3); }
.fids-tl-qtd { margin-left:0.25rem; font-family: var(--bi-font-mono); color: var(--ink-4); }

/* ══════════════════════════════════════════════════════════
   ETL DRAWER — .offcanvas do Bootstrap (backdrop/ESC/scroll nativos)
   ══════════════════════════════════════════════════════════ */
#fids-etl-drawer { --bs-offcanvas-width: min(560px, 94vw); }
.fids-etl-drawer-title { display: flex; align-items: center; gap:0.5rem; }

.fids-etl-log {
  flex: 1; margin:0; overflow: auto;
  padding:1rem 1rem;
  font-family: var(--bi-font-mono); font-size: 0.875rem; line-height: 1.55;
  color: var(--ink-2); background: var(--surf-2);
  white-space: pre-wrap; word-break: break-word;
}

/* ── Responsivo: rola a grade horizontalmente em telas estreitas ── */
@media (max-width:991.98px) {
  .fids-col-headers, .fids-row { min-width: 51.25rem; }
  .card:has(#fids-table-body) { overflow-x: auto; }
}

/* ===== MERGED FROM static/css/obs-produtos-comex.css (P5 — page-local dissolve) ===== */
/* ══════════════════════════════════════════════════════════
   OBS-PRODUTOS-COMEX — Gerenciamento de Observações de Produto
   Surface/cards/header come from FCDS (.card, .card-hd, .lab,
   .grid). Only page-specific form/table/inline-edit rules live here.
   ══════════════════════════════════════════════════════════ */

.obs-page {
  padding:1.5rem;
}

/* ── Nova observação (form lives inside an FCDS .card) ── */
.obs-nova-form {
  display: flex;
  gap:0.5rem;
  align-items: flex-end;
  flex-wrap: wrap;
}
.obs-nova-field {
  display: flex;
  flex-direction: column;
  gap:0.25rem;
}
.obs-nova-field--obs {
  flex: 1;
  min-width: 12.5rem;
}
.obs-nova-label {
  font-size: 0.875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--ink-3);
}
/* .form-control-sm cobre borda/altura/foco; residual = largura fixa + mono (código de produto). */
.obs-nova-input {
  width: 10rem;
  font-family: var(--mono);
}
.obs-nova-textarea {
  width: 100%;
  font-size: 0.875rem;
  border: var(--bs-border-width) solid var(--line-3);
  border-radius: var(--bs-border-radius-sm);
  padding:0.25rem 0.5rem;
  resize: vertical;
  min-height: 3.25rem;
  outline: none;
  font-family: inherit;
  line-height: 1.4;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.obs-nova-textarea:focus {
  border-color: var(--acc);
  box-shadow: var(--ring);
}
.obs-nova-actions {
  display: flex;
  align-items: center;
  gap:0.5rem;
  padding-bottom:0;
}

.obs-nova-status {
  font-size: 0.875rem;
  font-family: var(--mono);
  color: var(--negative-text);
}
.obs-nova-status--ok {
  color: var(--positive-text);
}

/* ── Table ── */
/* .table + .table-hover do Bootstrap; aqui só o que é desta tela. */
table.obs-table { font-size: 0.875rem; }
table.obs-table thead th {
  background: var(--surf-2);
  border-bottom: 2px solid var(--line);
  padding:0.5rem 1rem;
  font-weight: 600;
  color: var(--ink-2);
  font-size: 0.875rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
}
table.obs-table td { padding:0.5rem 1rem; color: var(--ink); }
.obs-col-obs {
  width: 50%;
}

/* ── Cell content ── */
.obs-codigo {
  font-family: var(--mono);
  font-weight: 600;
  font-size: 0.875rem;
  color: var(--acc);
  white-space: nowrap;
}
.obs-meta {
  font-size: 0.875rem;
  color: var(--ink-3);
  white-space: nowrap;
}

/* ── Inline edit ── */
.obs-display {
  cursor: pointer;
  padding:0.25rem 0.25rem;
  border-radius: var(--bs-border-radius-sm);
  border: var(--bs-border-width) solid transparent;
  min-height: 1.6rem;
  word-break: break-word;
  line-height: 1.45;
  transition: border-color 0.15s, background 0.15s;
  position: relative;
}
.obs-display:hover {
  border-color: var(--line-3);
  background: var(--surf-2);
}
.obs-display:hover::after {
  content: '\f303';
  font-family: 'Font Awesome 6 Free';
  font-weight: 900;
  font-size: 0.875rem;
  color: var(--ink-4);
  position: absolute;
  top: 0.25rem;
  right: 0.3rem;
}
.obs-display--vazio {
  color: var(--ink-4);
  font-style: italic;
}
.obs-edit {
  display: none;
}
.obs-textarea {
  width: 100%;
  font-size: 0.875rem;
  border: var(--bs-border-width) solid var(--acc);
  border-radius: var(--bs-border-radius-sm);
  padding:0.25rem 0.5rem;
  resize: vertical;
  min-height: 3.25rem;
  outline: none;
  box-shadow: var(--ring);
  font-family: inherit;
  line-height: 1.4;
}
.obs-actions {
  display: flex;
  gap:0.25rem;
  margin-top:0.25rem;
}

.obs-status {
  font-size: 0.875rem;
  color: var(--negative-text);
  min-height: 0.9rem;
  font-family: var(--mono);
  margin-top:0.25rem;
}

/* ── Delete button ── */

/* ── States ── */
.obs-empty {
  padding:3rem 1.5rem;
  text-align: center;
  color: var(--ink-4);
  font-size: 0.875rem;
}
.obs-empty-icon {
  font-size: 1.5rem;
  display: block;
  margin-bottom:0.5rem;
}

/* Loading: shimmer skeleton bars (FCDS skeleton tokens) in place of a
   spinner, matching the project-wide .skeleton standard. */
/* .obs-loading / .obs-skeleton / shimmer removidos — obs-produtos usa o overlay
   Bootstrap unificado (carregando('obs-table-wrap')). */

/* ── Mobile (≤768px) ── */
@media (max-width: 768px) {
  .obs-page {
    padding:0;
  }
  table.obs-table {
    min-width: 35rem;
  }
  .obs-col-obs {
    width: auto;
    min-width: 12.5rem;
  }
  
}

/* ===== MERGED FROM static/css/processos-comex.css (P5 — page-local dissolve) ===== */
/* ============================================================
   Processos Comex — Listagem paginada via Conexos direto
   Page-local presentation. Tokens come from custom.css.
   ============================================================ */

.processos-page {
  color: var(--ink);
  /* Preenche a altura da viewport: sem faixa de espaço vazio sob o card. O
     corpo da tabela rola dentro do card (.pcx-table-wrapper), não a página. */
  display: flex;
  flex-direction: column;
  /* altura FIXA (não min-height): trava o card na viewport p/ o corpo da tabela
     rolar dentro dele. 68px = chrome acima (topbar+crumb); 28px = padding-bottom
     do .content. Abaixo de 560px de viewport vira auto (mobile/paisagem curta). */
  height: calc(100vh - 96px);
}
@media (max-height: 560px) { .processos-page { height: auto; } }
.processos-page > .grid { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.processos-page .pcx-card { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.processos-page .pcx-card > .pcx-table-wrapper { flex: 1 1 auto; min-height: 0; overflow: hidden; display: flex; flex-direction: column; }
/* Só o corpo da tabela (.datatable-scroll = 'rt') rola; toolbar (topo) e
   bottom (info+paginação) ficam fixos, sempre visíveis. */
.processos-page .pcx-table-wrapper .dataTables_wrapper { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
/* max-height:none anula o teto global `--bi-dt-scroll-cap` (min(560px,82dvh)),
   pensado p/ tabelas inline. Aqui o layout é full-height (height:calc(100vh-96px))
   e o corpo cresce por flex; sem isto o teto trava o scroll em ~434px e sobra uma
   faixa branca de ~40% da viewport abaixo da paginação. */
.processos-page .pcx-table-wrapper .datatable-scroll { flex: 1 1 auto; min-height: 0; overflow: auto; max-height: none; }

/* ── Página cuja LISTA é a tela ────────────────────────────────────────────
   A lista ocupa a janela inteira menos a topbar, rola POR DENTRO, e cabeçalho +
   linha de filtros ficam parados no topo dela.

   `height` (não `min-height`) é o ponto todo. O `.main` do app declara
   min-height:calc(100vh - 52px); com apenas um mínimo, um filho `flex:1;
   min-height:0` não tem altura definida contra a qual se dimensionar — ele cresce
   até o conteúdo, o scroller interno deixa de existir e o `position:sticky` do
   cabeçalho passa a se ancorar numa caixa que sobe junto com a página. Foi essa a
   causa do cabeçalho "não grudar". Com altura definida a cadeia fecha, o
   .datatable-scroll volta a ser o elemento que rola, e o th gruda nele — parado.

   Ativada por `{% block content_class %}content--altura-cheia{% endblock %}`. */
.main:has(> .content--altura-cheia) {
  height: calc(100dvh - 52px);   /* 52px = .topbar (3.25rem), fixa no topo */
  min-height: 0;
  overflow: hidden;              /* quem rola é a lista, não a página */
  display: flex;
  flex-direction: column;
}
.content--altura-cheia { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.content--altura-cheia > .page { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.content--altura-cheia .fcds-filters-host { flex: 0 0 auto; }
/* Tela de altura cheia não tem "moldura de página": o recuo do shell (16px em
   cima, 20px nas laterais, 24px embaixo do .page) empurrava o conteúdo para
   dentro e roubava 40px de altura — a barra de decisão terminava a 24px do
   fim da janela. Quem dá respiro aqui é o próprio conteúdo, que já tem os
   seus paddings (capa, corpo, rodapé). */
.content--altura-cheia { padding: 0; }
.content--altura-cheia > .page { padding: 0 !important; }
/* Exceção: o FUNIL não tem capa nem rodapé próprios para dar o recuo — quem
   segura a margem lá é a página. A tela do negócio fica colada porque cada
   faixa dela (capa, corpo, rodapé) já traz o seu. */
.content--altura-cheia > .page[data-pagina="crm"] {
  padding: 1rem 1.25rem 0 !important; }
.content--altura-cheia > .page > .grid { flex: 1 1 auto; min-height: 0; display: grid; }
.content--altura-cheia .grid > .card { min-height: 0; display: flex; flex-direction: column; }

/* O card cede o PADDING, não a superfície. Tirar `background` dele jogava as
   linhas direto no canvas (--surface-app #edf0f4) e a hairline de separação
   (--line #e6e8ec) sumia contra ele: a tabela ficava sem grade e sem contraste,
   e o campo Buscar deixava de parecer um campo. O contorno e o fundo ficam; some
   só o recuo interno, que é o que de fato devolve espaço aos dados. */
.content--altura-cheia .grid > .card { padding: 0; }
/* Com o card sem padding, quem afasta o conteúdo da borda é cada faixa. */
.content--altura-cheia .card-hd,
.content--altura-cheia .datatable-toolbar,
.content--altura-cheia .datatable-bottom { padding-inline: var(--bi-space-md); }
.content--altura-cheia .card-hd { padding-block: var(--bi-space-sm); }

/* Separação de linha um passo mais firme que a hairline padrão: são 13 colunas
   numéricas lidas na diagonal, e `--line-2` desaparece nessa densidade. */
.content--altura-cheia .tbl tbody td { border-bottom: 1px solid var(--line); }
/* Zebra por linha, com a paridade reiniciando a cada bloco de cliente (classe posta
   no draw, ver acompanhamento-inadimplencia.js — `nth-child` do CSS não serve porque
   os cabeçalhos de bloco entram na paridade e o cinza escorrega).
   A faixa usa o MESMO overlay do hover (`--bs-table-accent-bg`), um degrau abaixo
   dele: .035 aqui, .075 no hover. Enquanto era `background: var(--surf-2)` — hex
   opaco idêntico ao `--bi-bg-hover` do hover — o hover pintava a mesma cor que já
   estava lá e sumia em cima da faixa. Duas escalas separadas colidem; uma só, não.
   `:not(:hover)` é o que devolve a linha ao hover: esta regra tem `.content--altura-cheia`
   a mais e venceria a regra genérica de hover na especificidade. Fora de hover a faixa
   pinta; sob o cursor ela para de casar e o overlay .075 assume. */
.content--altura-cheia .tbl tbody tr.linha-alternada:not(:hover) > td { --bs-table-accent-bg: rgba(0, 0, 0, .035); }

/* Grade vertical. Mais clara (--line-2) que o separador de linha (--line) de
   propósito: a horizontal carrega a identidade da linha, a vertical é guia de
   coluna. No mesmo peso as duas competem e a tabela lê como gaiola.
   `:not(:last-child)` evita filete dobrado contra a borda do card — o DataTables
   tira do DOM as colunas ocultas, então o último visível é o último de fato.
   Só a 1ª linha do thead (os rótulos) leva grade: a 2ª é a dos filtros, onde cada
   controle já tem borda própria e o filete só somava traço em cima de traço. */
.content--altura-cheia .tbl thead tr:first-child th:not(:last-child),
.content--altura-cheia .tbl tbody td:not(:last-child) {
  border-right: 1px solid var(--line-2);
}
/* O cabeçalho de grupo atravessa a tabela inteira (colspan): filete vertical ali
   cortaria o nome do cliente ao meio. */
.content--altura-cheia .tbl tbody tr.dtrg-group th { border-right: 0 !important; }

/* Dinheiro e atraso são as duas colunas que decidem a ligação: alinhadas,
   tabulares e com peso. O resto da linha fica em tom secundário. */
.content--altura-cheia .tbl tbody td.tbl__numeric {
  font-variant-numeric: tabular-nums;
  font-weight: var(--bi-fw-semibold);
  color: var(--ink);
}

.content--altura-cheia .tbl-wrapper { flex: 1 1 auto; min-height: 0; overflow: hidden; display: flex; flex-direction: column; }
/* Só o corpo rola; toolbar (topo) e info+paginação (base) ficam sempre à vista. */
.content--altura-cheia .dataTables_wrapper { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.content--altura-cheia .datatable-scroll {
  flex: 1 1 auto; min-height: 0; max-height: none; overflow: auto;
}
/* Âncora do sticky volta a ser o .datatable-scroll (parado): topo zerado. */
.content--altura-cheia .datatable-scroll thead tr:first-child th { top: 0 !important; }
.content--altura-cheia .datatable-scroll thead tr:nth-child(2) th {
  top: var(--thead-linha1-altura, 0px) !important;
}

/* Tela baixa: volta a fluir, senão a lista não cabe junto da barra de filtros. */
@media (max-height: 560px) {
  .main:has(> .content--altura-cheia) { height: auto; overflow: visible; display: block; }
  .content--altura-cheia { display: block; }
  .content--altura-cheia .datatable-scroll { max-height: var(--bi-dt-scroll-cap); }
}

.pcx-summary { font-size: 0.875rem; white-space: nowrap; }

/* ── Table ── */
/* Layout/base da tabela vêm de .tbl + .stickcols (main.css). Aqui só os
   cosméticos específicos do Processos Comex. NÃO redeclarar border-collapse/width
   em .pcx-table: .stickcols exige border-collapse:separate p/ o freeze de coluna. */
.pcx-col-num { text-align: right; font-family: var(--bi-font-mono); }

.pcx-cell-detail {
  text-align: center;
  width: 2rem;
  color: var(--ink-3);
}
.pcx-cell-processo {
  font-family: var(--bi-font-mono);
  font-weight: 600;
  color: var(--acc);
}

/* ── Loading / Empty ── */
.pcx-table-wrapper { position: relative; }
.pcx-loading {
  position: absolute;
  inset: 0;
  z-index: 2;
  min-height: 18.75rem;   /* preenche mesmo com a tabela display:none (wrapper colapsado) */
  background: var(--surf);
  padding:var(--bi-space-sm, 1rem);
}
.pcx-empty {
  padding:3rem 1.5rem;
  text-align: center;
  color: var(--ink-2);
}
.pcx-empty-icon { font-size: 2.5rem; color: var(--ink-3); margin-bottom:0.5rem; }
.pcx-empty-title { font-family: var(--bi-font-display); font-size: 1.15rem; font-weight: 600; margin-bottom:0.25rem; }
.pcx-empty-sub { color: var(--ink-3); font-size: 0.875rem; }

/* ── Detail Modal content ── */
.pcx-detail-section {
  margin-bottom:1.5rem;
}
.pcx-detail-section-title {
  font-family: var(--bi-font-display);
  font-weight: 600;
  font-size: 1.05rem;
  margin-bottom:0.5rem;
  color: var(--acc);
  border-bottom: var(--bs-border-width) solid var(--line);
  padding-bottom:0.25rem;
}
.pcx-detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13.75rem, 1fr));
  gap:0.5rem 1rem;
}
.pcx-detail-field-label {
  font-family: var(--bi-font-mono);
  font-size: 0.875rem;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.pcx-detail-field-value {
  font-size: 1rem;
  color: var(--ink);
}
/* .table.table-sm do Bootstrap dá largura, colapso, padding e borda de linha. */
.pcx-detail-table { font-size: 0.875rem; }
.pcx-detail-table th, .pcx-detail-table td { text-align: left; }
.pcx-detail-table th {
  background: var(--surf-2);
  font-weight: 600;
  font-family: var(--bi-font-display);
}
.pcx-hist-lista { max-height: 16.25rem; overflow-y: auto; }
.pcx-hist__item { padding:0.5rem 0; border-bottom: var(--bs-border-width) solid var(--line); }
.pcx-hist__item:last-child { border-bottom: 0; }
.pcx-hist__cab { font-size: 0.875rem; margin-bottom:0.25rem; }
.pcx-hist__item--falha .pcx-hist__cab strong { color: var(--negative-text); }

/* ===== MERGED FROM static/css/tracking-comex.css (P5 — page-local dissolve) ===== */
/* =====================================================
   VARIÁVEIS CSS DINÂMICAS - Responsive ao sidebar
   ===================================================== */

:root {
    --sidebar-width: 14.0625rem;
    --sidebar-margin:0.5rem;
    --header-height: 3.5rem;
    --tracking-header-height: 4.375rem;

    /* =====================================================
       CANONICAL COLOR SOURCE (Stage 1 foundation)
       Single source of truth for category/status color on this page.
       Resolved in JS via getTrackingColor() (static/js/tracking-comex.js).
       NEVER hardcode hex in JS or templates — read these tokens instead.
       ===================================================== */

    /* Product-group identity → FCDS categorical tokens (--cat-*).
       13 group names collapse onto their original color families; each
       family gets ONE distinct, legible cat token (the label carries the
       finer identity). De-duplicates the colliding raw hex (was #E28702 ×3,
       #B42727 ×6). Stable map — reuse in markers, dots, badges (stages 2-5). */
    /* Cor por SEGMENTO do catálogo do admin. Os 13 "grupos" antigos já apontavam
       para 5 cores (todo o aço era --cat-8): a paleta sempre foi por segmento, só o
       código é que fingia treze. O sub-segmento é o texto do badge, não a cor. */
    --tcx-segmento-steel:       var(--cat-8);  /* STEEL — cordoalha, arames, fixadores… */
    --tcx-segmento-agro:        var(--cat-3);  /* AGRO */
    --tcx-segmento-nutritional: var(--cat-1);  /* NUTRITIONAL */
    --tcx-segmento-resin:       var(--cat-2);  /* RESIN */
    --tcx-segmento-wine:        var(--cat-2);  /* WINE */
    --tcx-segmento-trading:     var(--cat-2);  /* TRADING */
    --tcx-segmento-medical:     var(--cat-4);  /* MEDICAL */
    --tcx-segmento-outros:      var(--cat-6);  /* OUTROS */
    --tcx-segmento-fallback:    var(--ink-3);  /* segmento desconhecido → tinta neutra */

    /* Status identity → NEUTRAL (One-Command Rule: status counts/tiles stay
       neutral; identity is carried by the LABEL + optional small dot, not a
       per-status hue). All point at neutral ink here; a later stage may
       repoint a specific status to a --positive/--negative/--warning token
       ONLY if a real good/bad direction is declared. Replaces the rainbow
       palette (was #dc3545/#ffc107/#17a2b8/#28a745/#fd7e14/#20c997/#6f42c1/
       #e83e8c/#198754/#6c757d). */
    --tcx-status:               var(--ink-3);

    /* Map markers & route — meaning-carrying color (the map keeps semantic hue:
       line color = progress, markers/dots = unidade de negócio). Tokenized,
       never hardcoded hex. Buttons/status tiles stay neutral; only the map
       carries this color. */
    --tcx-marker-vessel:    var(--cat-1);    /* vessel bubble + traveled route = blue (progress "percorrido") */
    --tcx-route-pending:    var(--ink-4);    /* restante (gray dashed) */
    --tcx-marker-dest:      var(--cat-3);    /* arrival = green */
    --tcx-transship-passed: var(--negative); /* passed waypoint = red */
}

body.sb-sidenav-toggled {
    --sidebar-width: 0;
}

/* =====================================================
   FOCUS MODE - Destaque de elemento selecionado no mapa
   ===================================================== */

/* Focus mode is scoped under `#map.map-focus-mode` (id + class = high
   specificity), so dim/focus rules win the cascade WITHOUT a wall of
   !important. Leaflet does not set inline opacity/filter on markers, and for
   SVG paths an inline `stroke-opacity` style beats the presentation attribute —
   so those properties win on specificity alone. Only z-index / stroke-width,
   which Leaflet writes inline for positioning/rendering, retain !important. */

/* Elementos desabilitados no focus mode (dim every status tile while a
   process is focused on the map). Scoped under .tracking-comex-page so it
   wins on cascade without !important. */
.tracking-comex-page .tracking-badge.tracking-badge-disabled {
    opacity: 0.55;            /* keep dimmed badge text ≥3:1 (was 0.4, too faint) */
    filter: grayscale(100%);
    pointer-events: none;
    cursor: not-allowed;
}

/* =====================================================
   Marcadores e Polylines - Focus/Disabled (scoped, low-!important)
   ===================================================== */

/* Marcadores de navio - SEM transições (evita flicker) */
#map.map-focus-mode .leaflet-marker-icon.vessel-marker,
#map.map-focus-mode .leaflet-marker-icon[class*="vessel"] {
    transition: none;
    will-change: opacity;
}

/* Elementos desabilitados - com transição SUAVE para outros elementos */
#map.map-focus-mode .leaflet-marker-disabled:not(.vessel-marker):not([class*="vessel"]) {
    opacity: 0.3;
    filter: grayscale(60%);
    transition: opacity 0.2s ease, filter 0.2s ease;
}

/* Marcadores de navio desabilitados - SEM transição */
#map.map-focus-mode .leaflet-marker-disabled.vessel-marker,
#map.map-focus-mode .leaflet-marker-disabled[class*="vessel"] {
    opacity: 0.3;
    filter: grayscale(60%);
    transition: none;
}

#map.map-focus-mode .leaflet-polyline-disabled {
    opacity: 0.25;
    stroke-opacity: 0.25;
    transition: opacity 0.2s ease, stroke-opacity 0.2s ease;
}

#map.map-focus-mode .leaflet-popup-disabled {
    opacity: 0.4;
    pointer-events: none;
}

/* Elementos focados - aparecem INSTANTANEAMENTE, com anel de destaque ESTÁTICO
   (independente do pulso, então legível p/ reduced-motion). */
#map.map-focus-mode .leaflet-marker-focused {
    opacity: 1;
    filter: drop-shadow(0 0 0 2px var(--acc));
    z-index: 1000 !important;   /* Leaflet writes z-index inline → needs !important */
    transition: none;
}

/* Forçar visibilidade de marcadores focados */
#map.map-focus-mode .leaflet-marker-focused,
#map.map-focus-mode .leaflet-marker-focused .custom-div-icon,
#map.map-focus-mode .leaflet-marker-focused .vessel-marker-wrapper {
    display: block;
    visibility: visible;
}

#map.map-focus-mode .leaflet-polyline-focused {
    opacity: 1;
    stroke-opacity: 1;
    stroke-width: 4 !important;  /* Leaflet writes stroke-width inline → needs !important */
    z-index: 999 !important;
    transition: none;
}

/* Wrapper do marcador de navio - otimização de performance */
.vessel-marker-wrapper {
    will-change: opacity, transform;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
}

/* =====================================================
   Select2 e Modais
   ===================================================== */

.tracking-comex-page .select2-container { z-index: 1150 !important; }
.tracking-comex-page .select2-dropdown { z-index: 1151 !important; }

/* Acima do overlay de estado do mapa (.tcx-map-state 1200) e dos status-cards (1100),
   ainda muito abaixo do backdrop dos modais Comex (11900). Sem empate por ordem de DOM. */
body:has(.tracking-comex-page) #topbar { z-index: 1250; }

.tracking-modal {
    --bs-modal-zindex: 12000 !important;
    z-index: 12000 !important;
}

.tracking-modal .modal-dialog {
    position: fixed !important;
    left: calc(var(--sidebar-width) + var(--sidebar-margin) + 12px) !important;
    top: calc(var(--header-height) + var(--tracking-header-height) + 80px) !important;
    transform: none !important;
    margin:0 !important;
    max-width: 35rem !important;
    width: calc(100% - var(--sidebar-width) - calc(var(--sidebar-margin) * 2) - 24px) !important;
    max-height: calc(100vh - var(--header-height) - var(--tracking-header-height) - 100px) !important;
    transition: left 0.15s ease-in-out, width 0.15s ease-in-out, top 0.15s ease-in-out;
}

@media (min-width: 992px) {
    .tracking-modal .modal-dialog {
        left: calc(var(--sidebar-width) + var(--sidebar-margin) + 12px) !important;
        max-width: 35rem !important;
        top: calc(var(--header-height) + var(--tracking-header-height) + 80px) !important;
    }
}

.tracking-modal.fade .modal-dialog {
    transition: transform 0.3s ease-out, opacity 0.3s ease-out !important;
    transform: translateX(-100%) !important;
    opacity: 0;
}

.tracking-modal.show .modal-dialog {
    transform: translateX(0) !important;
    opacity: 1;
}

@media (max-width:991.98px) {
    .tracking-modal .modal-dialog {
        left: calc(var(--sidebar-width) + var(--sidebar-margin) + 12px) !important;
        max-width: 32.5rem !important;
        top: calc(var(--header-height) + var(--tracking-header-height) + 75px) !important;
    }
}

@media (max-width: 768px) {
    .tracking-modal .modal-dialog {
        left: calc(var(--sidebar-width) + 8px) !important;
        width: calc(100% - var(--sidebar-width) - 16px) !important;
        max-width: 30rem !important;
        top: calc(var(--header-height) + var(--tracking-header-height) + 70px) !important;
    }
    
    .tracking-comex-page .tracking-modal .modal-body { 
        max-height: calc(100vh - var(--header-height) - var(--tracking-header-height) - 140px);
    }
}

@media (max-width: 576px) {
    .tracking-modal .modal-dialog {
        left: 12px !important;
        width: calc(100% - 24px) !important;
        max-width: none !important;
        max-height: calc(100vh - var(--header-height) - 55px - 20px) !important;
        top: calc(var(--header-height) + 55px + 60px) !important;
    }
    
    .tracking-comex-page .tracking-modal .modal-body { 
        max-height: calc(100vh - var(--header-height) - 55px - 140px);
    }
}

/* =====================================================
   Produtos e Summary
   ===================================================== */

.process-products {
    display: grid;
    gap:0.25rem;
    margin-top:0.5rem;
}

/* Bordo/bg/radius/padding-base (+ layout em coluna) vêm de .card.card-body
   (Bootstrap), aplicado junto no JS — sem residual próprio. */

.process-product-name {
    font-weight: 600;
    color: var(--ink);
    font-size: 1rem;
}

/* Bordo/bg/radius/padding-base vêm de .card.card-body (Bootstrap), aplicado
   junto no JS; aqui só o residual: linha flex com quebra (labels+valores lado
   a lado, várias colunas) que o .card (coluna) não dá. */
.process-summary {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap:0.5rem 1rem;
    margin-bottom:0.5rem;
}

.process-summary-item {
    min-width: 8.75rem;
}

.process-summary-label {
    font-size: 0.875rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--ink-3);
}

.process-summary-value {
    font-weight: 600;
    color: var(--ink);
    font-size: 1rem;
}

/* Numeric summary value (FOB / Total / Itens / counts / USD / qty): Roboto
   (official numeral font, --mono) tabular, right-aligned so figures
   align and compare (Tabular Rule). The
   text labels (Encomendante/Exportador/Status…) keep the proportional value. */
.process-summary-value.is-num {
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
    text-align: right;
    letter-spacing: -0.01em;
}

/* Status-dot chip: small direction/neutral dot + neutral ink label, legible
   without hue (colorblind-safe). Dot hue supplied inline via --tcx-status-dot
   (defaults to neutral ink). */
.tcx-status-chip {
    display: inline-flex;
    align-items: center;
    gap:0.25rem;
    font-weight: 600;
    color: var(--ink);
    font-size: 1rem;
}
.tcx-status-chip::before {
    content: "";
    width: 0.4375rem;
    height: 0.4375rem;
    border-radius: 50%;
    background: var(--tcx-status-dot, var(--ink-3));
    flex: 0 0 auto;
}

/* FCDS inline warning note (replaces Bootstrap alert-warning). Subtle amber
   tint fill, AA-safe deep-amber text (via --color-indicator-warning-text, hoje
   apontando para --chart-alerta-text — mesma laranja do sistema de gráficos),
   single --line hairline, no left stripe, real FontAwesome glyph. */
.tcx-warn-note {
    display: flex;
    align-items: flex-start;
    gap:0.5rem;
    padding:0.5rem 0.5rem;
    margin-bottom:1rem;
    background: var(--warning-subtle);
    border: var(--bs-border-width) solid var(--line);
    border-radius: var(--r-sm);
    color: var(--color-indicator-warning-text);
    font-size: 0.875rem;
    line-height: 1.4;
}
.tcx-warn-note .tcx-warn-icon {
    color: var(--color-indicator-warning-text);
    margin-top:0;
    flex: 0 0 auto;
}

/* =====================================================
   Timeline / Progress bar do Navio (modal de detalhes)
   ===================================================== */
.process-timeline { margin-bottom:0.5rem; }
.process-timeline-top { font-size: 1rem; color: var(--ink-2); }
.process-timeline .timeline-origin,
.process-timeline .timeline-dest { max-width: 46%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Progress = MAGNITUDE → slate only (--acc); never group-hued. Track is a
   neutral --line rail. Width/left transitions are gated behind
   prefers-reduced-motion: no-preference so reduced-motion users get the final
   position instantly (no animated decoration). */
.timeline-track { position: relative; height: 1.25rem; }
.timeline-line { position: absolute; left: 0; top: 50%; height: 0.125rem; transform: translateY(-50%); border-radius: var(--bs-border-radius-sm); background: var(--line); width: 100%; }
.timeline-progress { position: absolute; left: 0; top: 50%; height: 0.125rem; transform: translateY(-50%); border-radius: var(--bs-border-radius-sm); background: var(--acc); }
.timeline-ship { position: absolute; top: 50%; transform: translate(-50%,-50%); z-index: 5; }
@media (prefers-reduced-motion: no-preference) {
    .timeline-progress { transition: width 200ms cubic-bezier(.2,.8,.2,1); }
    .timeline-ship { transition: left 200ms cubic-bezier(.2,.8,.2,1); }
}
.ship-icon { width: 1.375rem; height: 1.375rem; display: inline-flex; align-items: center; justify-content: center; background: var(--surf); border-radius: 50%; box-shadow: var(--sh1); border: var(--bs-border-width) solid var(--line); font-size: 0.875rem; color: var(--acc); }
.process-timeline-meta { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap:0.5rem; font-size: 0.875rem; color: var(--ink-3); }
.process-timeline-meta .timeline-meta-left,
.process-timeline-meta .timeline-meta-right { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 0.875rem; color: var(--ink-3); font-family: var(--mono); font-variant-numeric: tabular-nums; }
.process-timeline-meta .timeline-meta-center { text-align: center; font-weight: 600; color: var(--ink); }
.process-timeline .progress-percent { font-weight: 600; color: var(--ink); font-family: var(--mono); font-variant-numeric: tabular-nums; }
@media (max-width: 576px) {
    .process-timeline-meta { grid-template-columns: 1fr auto 1fr; gap:0.25rem; }
    .process-timeline-meta .timeline-meta-center { font-size: 1rem; }
}
@media (max-width: 576px) {
    .process-timeline .timeline-origin, .process-timeline .timeline-dest { max-width: 40%; }
}

/* =====================================================
   Modal Backdrop
   ===================================================== */

/* Backdrop: o do Bootstrap, sem override. O que morava aqui era
   `background-color: rgba(0,0,0,.25) !important`, que combinado com o
   `opacity:.5` do `.show` dava .125 efetivo — clareamento global, com
   `!important`, sem nenhum token do FCDS por trás. */

/* A elevação p/ z-11900 é SÓ da tracking-comex (backdrop acima do topbar-1200 e
   do mapa Leaflet). Escopada via body:has(.tracking-comex-page) p/ não vazar e
   soterrar os modais Bootstrap padrão (z-1055) nas demais telas. Só mexe no
   z-index — a regra .tracking-comex-modal-open .modal-backdrop (transparência)
   continua vencendo por não haver conflito de propriedade. */
body:has(.tracking-comex-page) .modal-backdrop {
    --bs-backdrop-zindex: 11900 !important;
    z-index: 11900 !important;
}

.tracking-comex-modal-open .modal-backdrop {
    background-color: transparent !important;
    opacity: 0 !important;
}

.tracking-comex-page .modal.show ~ .select2-container--open .select2-dropdown {
    z-index: 12500 !important;
}

/* =====================================================
   Header / toolbar (FCDS tokens, sem !important)
   ===================================================== */

/* ── Topbar actions do tracking (.tb-btn): variante sólida p/ ação primária
   (Atualizar) + estados disabled/active token-driven que o .tb-btn base não
   traz. Escopados por id/classe pois vivem no topbar FCDS (fora de
   .tracking-comex-page). ── */
#tcx-refresh-btn, #btn-reset-map,
#tracking-export-json, #tracking-export-csv { cursor: pointer; }
.tb-btn:active { background: var(--surf-3); border-color: var(--line-3); }
/* disabled token-driven (export até cache popular) */
.tb-btn:disabled, .tb-btn[disabled], .tb-btn[aria-disabled="true"] {
    opacity: .55; cursor: not-allowed;
    background: var(--surf-2); border-color: var(--line); color: var(--ink-4);
}
.tb-btn:disabled svg, .tb-btn[disabled] svg, .tb-btn[aria-disabled="true"] svg { color: var(--ink-4); }
/* variante sólida — ação primária da página (B2: brand-blue) */
.tb-btn--solid { background: var(--brand); border-color: var(--brand); color: var(--bi-text-on-accent); }
.tb-btn--solid svg { color: var(--bi-text-on-accent); }
.tb-btn--solid:hover, .tb-btn--solid.open { background: var(--brand-strong); border-color: var(--brand-strong); }
.tb-btn--solid:active { background: var(--brand-strong); border-color: var(--brand-strong); }
.tb-btn--solid:disabled, .tb-btn--solid[disabled], .tb-btn--solid[aria-disabled="true"] {
    background: var(--brand); border-color: var(--brand); color: var(--bi-text-on-accent);
}
.tb-btn--solid:disabled svg, .tb-btn--solid[disabled] svg, .tb-btn--solid[aria-disabled="true"] svg { color: var(--bi-text-on-accent); }
/* spinner do Atualizar durante reload */
@media (prefers-reduced-motion: no-preference) {
    .tb-btn.is-loading .tcx-refresh-icon { animation: tcx-spin .8s linear infinite; transform-origin: 50% 50%; }
}
@keyframes tcx-spin { to { transform: rotate(360deg); } }

.tracking-comex-page .tracking-header {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap:0.5rem;
    padding:0.5rem 1rem;
    margin:0;
    background: var(--surf);
    border-bottom: var(--bs-border-width) solid var(--line);
}
/* barra fina do corpo: só a busca Select2, ocupando a largura disponível */
.tracking-comex-page .tracking-header .process-search-wrapper {
    flex: 1 1 auto;
    max-width: 35rem;
}

/* ── Filtros no popover do topbar (fora de .tracking-comex-page → sem escopo de
   página; este CSS só carrega no tracking, então é seguro) ──
   Escopo/Via usam o vocabulário FCDS .optrow (.lab + .ck + .nm); "Com posição
   AIS" usa o .form-switch nativo do Bootstrap. Os <select> de Escopo/Via ficam
   escondidos (.tcx-state-select) como modelo de estado lido por
   _fetchTrackingData; o switch é o próprio input visível. */
.tcx-state-select, .tcx-state-check {
    position: absolute; width: 1px; height: 1px;
    overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
    white-space: nowrap; border: 0; padding:0; margin:-0;
}
.tcx-filter-group { margin-bottom:0.25rem; }
.tcx-filter-lab { padding:0.25rem 0.5rem 0; }
/* .optrow é botão (single-select por grupo); marca de seleção via aria-checked */
#tcx-filtros-pop .optrow[aria-checked="true"] .ck { background: var(--acc); border-color: var(--acc); }
#tcx-filtros-pop .optrow[aria-checked="true"] .ck svg { opacity: 1; }
#tcx-filtros-pop .popftog { display: flex; align-items: center; }
/* .form-switch nativo espalhado na linha: label à esquerda, switch à direita
   (neutraliza o padding-left/margin-left do .form-switch p/ layout space-between). */
#tcx-filtros-pop .popftog .form-check { width: 100%; display: flex; align-items: center; justify-content: space-between; padding-left: 0; margin: 0; }
#tcx-filtros-pop .popftog .form-check-input { margin: 0; float: none; }
#tcx-filtros-pop .popftog .form-check-label { margin: 0; }

/* (header__title / header-controls / header__check removidos — controles foram
   p/ o topbar na reskin Fase 2e; só a busca Select2 permanece em .tracking-header) */

/* Select da busca no toolbar — alinhar à altura dos tb-btn */
.tracking-comex-page .tracking-header .form-select-sm {
    width: auto;
    min-width: 8.125rem;
    height: 2.125rem;
}

/* Wrapper do search */
.tracking-comex-page .tracking-header .process-search-wrapper {
    display: flex;
    align-items: center;
    width: 30rem;
    min-width: 25rem;
    flex-shrink: 0;
}

/* Select2 dentro do toolbar */
.tracking-comex-page .tracking-header .select2-container {
    min-height: 2.125rem;
    display: block;
    width: 100% !important;
}

.tracking-comex-page .tracking-header .select2-selection,
.tracking-comex-page .tracking-header .select2-selection--single {
    height: 2.125rem;
    padding:0.25rem 0.5rem;
    display: flex;
    align-items: center;
    font-size: 0.875rem;
    line-height: 1.4;
    background-color: var(--surf-2);
    border: var(--bs-border-width) solid var(--line);
    border-radius: var(--r-sm);
    color: var(--ink-2);
}

.tracking-comex-page .tracking-header .select2-container--default .select2-selection--single .select2-selection__arrow {
    height: 100%;
    right: 8px;
    top: 50%;
    transform: translateY(-50%);
}

.tracking-comex-page .tracking-header .select2-container--default .select2-selection--single .select2-selection__rendered {
    line-height: 1.4;
    padding:0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--ink-2);
}

/* Dropdown do Select2 */
.tracking-comex-page .select2-dropdown .select2-search--dropdown .select2-search__field {
    width: 100%;
    padding:0.5rem 0.5rem;
    box-sizing: border-box;
    font-size: 1rem;
    border: var(--bs-border-width) solid var(--line);
    border-radius: var(--r-sm);
}

.tracking-comex-page .select2-results__option {
    padding:0.5rem 0.5rem;
    font-size: 0.875rem;
    transition: background-color 160ms ease, color 160ms ease;
}

.tracking-comex-page .select2-results__option--highlighted,
.tracking-comex-page .select2-results__option:hover {
    background-color: var(--acc-soft);
    color: var(--acc);
}

.tracking-comex-page .select2-container--open .select2-selection--single,
.tracking-comex-page .select2-container--focus .select2-selection--single {
    border-color: var(--acc);
    box-shadow: var(--ring);
    transition: box-shadow 180ms ease, border-color 180ms ease;
}

@media (prefers-reduced-motion: reduce) {
    .tracking-comex-page .select2-container--open .select2-selection--single,
    .tracking-comex-page .select2-container--focus .select2-selection--single { transition: none; }
}

/* Placeholder lê em contraste de corpo (--ink-3 ~4.7:1); o valor selecionado
   permanece em --ink-2 mais escuro (regra acima). */
.tracking-comex-page .select2-selection__placeholder {
    color: var(--ink-3);
}

/* Estado loading/disabled do search enquanto processosData resolve. A classe é
   posta no wrapper por tracking-comex.js; mostra um skeleton sobre o controle e
   bloqueia interação até os dados chegarem. */
/* .process-search is-loading skeleton removido — loading unificado (overlay Bootstrap). */

.tracking-comex-page .select2-dropdown {
    border: var(--bs-border-width) solid var(--line);
    border-radius: var(--bs-border-radius-lg);
    box-shadow: var(--sh-glass);
}

/* Responsive - Header */
@media (max-width: 576px) {
    .tracking-comex-page .tracking-header {
        flex-direction: column;
        align-items: stretch;
    }

    .tracking-comex-page .tracking-header .process-search-wrapper {
        width: 100%;
        min-width: 0;
        max-width: none;
        order: 3;
        margin-top:0.5rem;
    }
}

/* =====================================================
   Layout e Mapa
   ===================================================== */

.tracking-comex-page {
    height: calc(100vh - 56px) !important;
    display: flex;
    flex-direction: column;
}

.tracking-comex-page .d-flex.flex-column.h-100 > .tracking-row {
    flex: 1 1 auto;
    min-height: 0;
    /* Trap the map's stacking context: Leaflet panes (z-index up to ~700) and
       the .tcx-map-state overlay (z-index 1200) would otherwise bubble to the
       root and paint OVER the shell sidebar (z-index 30/60) and topbar. isolate
       contains them so the shell chrome always wins. */
    isolation: isolate;
}

/* (#layoutSidenav_content.tracking-comex-active removido — esse elemento/classe
   eram da shell SB-Admin antiga e nunca existem no FCDS; regras eram mortas.) */

.tracking-comex-page #map {
    width: 100%;
    height: 100%;
    border-radius: 0;
    box-shadow: none;
    /* Join the FCDS surface ladder: a 1px --line hairline separates the canvas
       from the worksheet/topbar instead of bleeding edge-to-edge. */
    border-top: var(--bs-border-width) solid var(--line);
}

/* Reskin Leaflet's default control chrome to FCDS tokens (was white boxes /
   #ccc borders / blue focus). */
.tracking-comex-page .leaflet-control-zoom a,
.tracking-comex-page .leaflet-control-attribution {
    background: var(--surf);
    border: var(--bs-border-width) solid var(--line);
    color: var(--ink-2);
}

.tracking-comex-page .leaflet-control-zoom a {
    border-radius: var(--r-sm);
    transition: background-color 0.16s ease, color 0.16s ease, border-color 0.16s ease;
}

.tracking-comex-page .leaflet-control-zoom a:hover {
    background: var(--acc-soft);
    border-color: var(--acc-line);
    color: var(--acc);
}

.tracking-comex-page .leaflet-control-zoom a:focus-visible {
    outline: none;
    box-shadow: var(--ring);
}

.tracking-comex-page .leaflet-control-attribution {
    border-radius: var(--r-xs);
}

.tracking-comex-page .leaflet-control-attribution a {
    color: var(--ink-2);
}

@media (prefers-reduced-motion: reduce) {
    .tracking-comex-page .leaflet-control-zoom a { transition: none; }
}

/* country-flag pin — chrome moved off inline styles to the surface ladder:
   --surf fill, 1px --surf hairline, one soft low-alpha lift (no heavy shadow). */
.tracking-comex-page .country-flag-marker {
    background: var(--surf);
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    border: var(--bs-border-width) solid var(--line);
    box-shadow: 0 1px 3px rgba(25, 28, 34, 0.18);
    cursor: pointer;
}

/* =====================================================
   Cards Overlay
   ===================================================== */

.tracking-comex-page #status-cards-container {
    position: absolute;
    top: 12px;
    left: calc(var(--sidebar-width) + var(--sidebar-margin));
    z-index: 1100;
    pointer-events: auto;
    transition: left 0.15s ease-in-out;
}

@media (max-width:767.98px) {
    .tracking-comex-page #status-cards-container {
        left: 8px !important;
        right: 8px;
        flex-wrap: wrap;
    }
}

/* Stage 1: #group-cards / #group-cards-container rules removed (dead code —
   renderGroupCards deleted; #group-cards never existed in the template). */
.tracking-comex-page #status-cards {
    display: flex;
    gap:0.5rem;
    align-items: stretch;
    background: var(--surf);
    border: var(--bs-border-width) solid var(--line);
    padding:0.25rem;
    border-radius: var(--r-xs);
    box-shadow: none;
    max-height: 60vh;
    overflow-x: auto;
    white-space: nowrap;
    pointer-events: auto;
}

.tracking-comex-page #status-cards > div {
    flex: 0 0 auto;
}

@media (max-width:767.98px) {
    .tracking-comex-page #status-cards { gap:0.25rem; padding:0.25rem; }
}

/* Skeleton dos status-cards enquanto _fetchTrackingData resolve. Reserva a
   mesma altura/box da faixa real (#status-cards) para não causar CLS quando os
   cards reais aparecem. */
/* .tcx-cards-skeleton / .tcx-skb-pill removidos — loading unificado (overlay Bootstrap). */

/* =====================================================
   Estados de página sobre o mapa (loading / vazio / erro)
   -----------------------------------------------------
   Nunca deixa o mapa silenciosamente em branco: distingue carregando, sem
   processos, e falha de fetch/parse. data-state alterna qual bloco é exibido.
   ===================================================== */
.tracking-comex-page .tcx-map-state {
    position: absolute;
    inset: 0;
    z-index: 1200;
    display: grid;
    place-items: center;
    padding:1rem;
    pointer-events: none;
}
/* Some quando há dados plotados (data-state="ready"). */
.tracking-comex-page .tcx-map-state[data-state="ready"] { display: none; }
.tracking-comex-page .tcx-map-state__card {
    pointer-events: auto;
    min-width: 15rem;
    max-width: 22.5rem;
    padding:1.5rem 1.5rem;
    gap:0.5rem;
    background: var(--surf);
    border: var(--bs-border-width) solid var(--line);
    border-radius: var(--r-sm);
    box-shadow: var(--sh2);
    text-align: center;
    color: var(--ink-2);
}
.tracking-comex-page .tcx-map-state__icon {
    width: 1.875rem;
    height: 1.875rem;
    color: var(--ink-3);
    margin-bottom:0.25rem;
}
.tracking-comex-page .tcx-map-state__msg {
    margin:0;
    font-size: 0.875rem;
    line-height: 1.45;
    color: var(--ink-2);
}
/* alterna blocos conforme data-state */
.tracking-comex-page .tcx-map-state__loading,
.tracking-comex-page .tcx-map-state__empty,
.tracking-comex-page .tcx-map-state__error { display: none; flex-direction: column; align-items: center; gap:0.5rem; }
.tracking-comex-page .tcx-map-state[data-state="loading"] .tcx-map-state__loading { display: flex; }
.tracking-comex-page .tcx-map-state[data-state="empty"]   .tcx-map-state__empty   { display: flex; }
.tracking-comex-page .tcx-map-state[data-state="error"]   .tcx-map-state__error   { display: flex; }
.tracking-comex-page .tcx-map-state__loading .tcx-map-state__msg { margin-top:0.25rem; color: var(--ink-3); }

/* =====================================================
   Marcadores e Tooltips
   ===================================================== */

.tracking-comex-page .custom-div-icon { background: transparent !important; border: none !important; }

.tracking-comex-page .leaflet-tooltip.custom-tooltip {
    background-color: var(--ink);
    color: var(--surf);
    border: none;
    border-radius: var(--bs-border-radius-sm);
    padding:0.25rem 0.5rem;
    font-size: 0.875rem;
    font-weight: 500;
    box-shadow: var(--sh2);
    min-width: 10rem;
    max-width: 22.5rem;
    white-space: normal;
    word-break: break-word;
    line-height: 1.2;
}

.tracking-comex-page .leaflet-tooltip.custom-tooltip::before { border-top-color: var(--ink); }

/* marker utilities consolidated (moved from inline templates).
   Depth = a 1px --surf hairline ring + ONE soft low-alpha lift. App-wide
   --sh1/--sh2 are `none` for worksheet cards, but a marker floats over the
   raster basemap and needs minimal separation from the tiles; --tcx-marker-sh
   centralizes that soft shadow (replaces the legacy `border:3px solid white` +
   `box-shadow:0 3px 10px rgba(0,0,0,.5)` heavy-shadow tell). */
:root { --tcx-marker-sh: 0 1px 3px rgba(25, 28, 34, 0.18); }
.pulse { animation: pulse 2s infinite; }
@keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.15); } }
@media (prefers-reduced-motion: reduce) {
    .pulse { animation: none; }
}

/* shared 32px round map bubble (origin/destination/vessel/consolidated) */
.custom-div-icon .consolidated-marker,
.consolidated-marker,
.custom-div-icon .destination-marker,
.destination-marker,
.custom-div-icon .vessel-marker,
.vessel-marker,
.port-marker {
    width: 2rem; height: 2rem; border-radius:50%;
    display:flex; align-items:center; justify-content:center;
    border:var(--bs-border-width) solid var(--surf);
    box-shadow:var(--tcx-marker-sh);
    cursor:pointer;
}

/* arrival = green (destination); origin = unidade de negócio (group color,
   supplied inline via --tcx-marker, fallback slate) */
.destination-marker,
.port-marker--destination { background: var(--tcx-marker-dest); }
.port-marker--origin { background: var(--tcx-marker, var(--acc)); }

.consolidated-count-badge { position:absolute; top:-8px; right:-8px; background:var(--acc); width: 1.5rem; height: 1.5rem; border-radius:50%; border:var(--bs-border-width) solid var(--surf); display:flex; align-items:center; justify-content:center; box-shadow:var(--tcx-marker-sh); }
/* count is magnitude → mono tabular ink-on-surf, never red (Tabular + One-Command) */
.consolidated-count-text { color:var(--surf); font-family:var(--mono); font-variant-numeric:tabular-nums; font-weight:700; font-size:0.875rem; }

/* per-process group identity dots over the vessel (categorical → cat token fill,
   supplied inline; chrome is a neutral --surf ring) */
.vessel-group-dot {
    width: 0.5rem; height: 0.5rem; border-radius:50%;
    border:var(--bs-border-width) solid var(--surf);
    box-shadow:var(--tcx-marker-sh);
}

/* transshipment dot: passed = solid red, pending = hollow gray ring.
   Differentiated by FILL (solid vs ring) AND hue — colorblind-safe + colorful. */
.transshipment-dot {
    width: 0.75rem; height: 0.75rem; border-radius:50%;
    box-shadow:var(--tcx-marker-sh);
}
.transshipment-dot.is-passed {
    background: var(--negative);
    border:var(--bs-border-width) solid var(--surf);
}
.transshipment-dot.is-pending {
    background: var(--surf);
    border:2px solid var(--ink-4);
}

/* =====================================================
   Badges
   ===================================================== */

/* FCDS number-first tile (status filter). Magnitude (count) is MONO ink and
   never hued; the status name is an --ink-3 label that carries identity.
   Background is the neutral surface ladder — no per-status hue. */
.tracking-badge {
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    gap:0;
    padding:0.25rem 0.5rem;
    border-radius: var(--r-xs);
    background: var(--surf);
    border: var(--bs-border-width) solid var(--line);
    cursor: pointer;
    transition: background-color 0.16s ease, border-color 0.16s ease;
    white-space: nowrap;
    margin:0;
}

.tracking-badge:hover {
    background: var(--acc-soft);
    border-color: var(--acc-line);
}

.tracking-badge:focus-visible {
    outline: none;
    box-shadow: var(--ring);
}

.tracking-badge:active {
    background: var(--surf-2);
}

.tracking-badge .badge-count {
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    font-size: 1.05rem;
    line-height: 1.05;
    color: var(--ink);
    letter-spacing: -0.01em;
}

.tracking-badge .badge-label {
    font-size: 0.875rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-3);
}

/* Real zero-count disabled state: dimmed + non-interactive. The 0 stays in
   strong --ink so it remains legible through the .55 opacity; only the label
   recedes to --ink-4. */
.tracking-badge.is-disabled {
    background: var(--surf-2);
    border-color: var(--line-2);
    opacity: 0.55;
    pointer-events: none;
    cursor: default;
}

.tracking-badge.is-disabled .badge-label {
    color: var(--ink-4);
}

@media (prefers-reduced-motion: reduce) {
    .tracking-badge { transition: none; }
}

.tracking-badges-container {
    display: flex;
    flex-wrap: wrap;
    padding:0 0;
    gap:0;
    background: transparent;
}

/* =====================================================
   Controles e Botões do Modal
   ===================================================== */

.tracking-comex-page .tracking-modal .modal-content .btn {
    font-size: 0.875rem;
    font-weight: 400 !important;
    padding:0.25rem 0.5rem !important;
}

/* "Detalhes" → FCDS slate ghost button (not Bootstrap primary blue). Full
   state set: default / hover / focus-visible / active. */
.tracking-comex-page .tracking-modal .process-details-btn {
    background: var(--surf);
    border: var(--bs-border-width) solid var(--acc-line);
    color: var(--acc-ink);
    border-radius: var(--r-sm);
    transition: background-color 0.16s ease, border-color 0.16s ease, color 0.16s ease;
}
.tracking-comex-page .tracking-modal .process-details-btn:hover {
    background: var(--acc-soft);
    border-color: var(--acc);
    color: var(--acc-ink);
}
.tracking-comex-page .tracking-modal .process-details-btn:focus-visible {
    outline: none;
    box-shadow: var(--ring);
    border-color: var(--acc);
}
.tracking-comex-page .tracking-modal .process-details-btn:active {
    background: var(--surf-2);
}
@media (prefers-reduced-motion: reduce) {
    .tracking-comex-page .tracking-modal .process-details-btn { transition: none; }
}

/* Hairline-separated process rows (replaces Bootstrap .list-group boxed cards):
   no per-item box, just a single --line bottom hairline. */
.tracking-comex-page .tracking-modal .process-row {
    padding:0.5rem 0;
    border-bottom: var(--bs-border-width) solid var(--line);
}
.tracking-comex-page .tracking-modal .process-row:first-child { padding-top:0; }
.tracking-comex-page .tracking-modal .process-row:last-child { border-bottom: none; padding-bottom:0; }
.tracking-comex-page .tracking-modal .process-row h6 { margin-bottom:0.25rem; }

/* =====================================================
   Popups Customizados
   ===================================================== */

/* =====================================================
   Modal Styles
   ===================================================== */

/* Depth = opaque --surf fill + flat --sh2 popover shadow + a single --line
   hairline. No backdrop-filter blur, no hard !important border (the
   .tracking-modal id+class scope wins on specificity). */
.tracking-comex-page .tracking-modal .modal-content {
    border-radius: var(--bs-border-radius-lg);
    box-shadow: var(--sh2);
    border: var(--bs-border-width) solid var(--line);
    background-color: var(--surf);
}

.tracking-comex-page .tracking-modal .modal-header {
    border-top-left-radius: 10px !important;
    border-top-right-radius: 10px !important;
    background: linear-gradient(135deg, var(--surf-2) 0%, var(--surf) 100%);
    border-bottom: var(--bs-border-width) solid var(--line);
    padding:1rem 1rem;
}

.tracking-comex-page .tracking-modal .modal-title {
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--ink);
}

.tracking-comex-page .tracking-modal .btn-close {
    padding:0.5rem;
    opacity: 0.6;
}

.tracking-comex-page .tracking-modal .btn-close:hover {
    opacity: 1;
}

.tracking-comex-page .tracking-modal .modal-footer {
    border-bottom-left-radius: 10px !important;
    border-bottom-right-radius: 10px !important;
    background-color: var(--surf-2);
    padding:0.5rem 1rem;
    border-top: var(--bs-border-width) solid var(--line);
}

.tracking-comex-page .tracking-modal .modal-body {
    max-height: calc(100vh - var(--header-height) - var(--tracking-header-height) - 160px);
    overflow-y: auto;
    overflow-x: hidden;
    padding:1rem 1rem;
}

.tracking-comex-page .tracking-modal .modal-body::-webkit-scrollbar {
    width: 0.5rem;
}

.tracking-comex-page .tracking-modal .modal-body::-webkit-scrollbar-track {
    background: var(--surf-2);
    border-radius: var(--bs-border-radius-sm);
}

.tracking-comex-page .tracking-modal .modal-body::-webkit-scrollbar-thumb {
    background: var(--line-3);
    border-radius: var(--bs-border-radius-sm);
}

.tracking-comex-page .tracking-modal .modal-body::-webkit-scrollbar-thumb:hover {
    background: var(--ink-4);
}

/* FCDS tab treatment — clean cascade, no !important. Bootstrap's .nav-tabs
   borders are neutralised once via `border:0;background:none`, then we draw a
   single transparent bottom border that becomes --acc on the active tab
   (active underline). Specificity (.tracking-comex-page .tracking-modal
   .nav-tabs .nav-link) wins against Bootstrap's .nav-tabs .nav-link without
   forcing. */
.tracking-comex-page .tracking-modal .nav-tabs {
    border-bottom: var(--bs-border-width) solid var(--line);
    margin-bottom:1rem;
}

.tracking-comex-page .tracking-modal .nav-tabs .nav-link {
    background: none;
    border: 0;
    border-bottom: 2px solid transparent;
    margin-bottom:-0;
    color: var(--ink-3);
    padding:0.5rem 0.5rem;
    font-weight: 500;
    font-size: 1rem;
    transition: color 0.16s ease, border-color 0.16s ease;
}

.tracking-comex-page .tracking-modal .nav-tabs .nav-link:hover {
    color: var(--ink-2);
    border-bottom-color: var(--line-3);
}

.tracking-comex-page .tracking-modal .nav-tabs .nav-link:focus-visible {
    outline: none;
    box-shadow: var(--ring);
    border-radius: var(--r-xs);
}

.tracking-comex-page .tracking-modal .nav-tabs .nav-link.active {
    color: var(--acc);
    border-bottom-color: var(--acc);
    font-weight: 600;
}

@media (prefers-reduced-motion: reduce) {
    .tracking-comex-page .tracking-modal .nav-tabs .nav-link { transition: none; }
}

.tracking-comex-page #countryProcessModal .nav-tabs {
    display: flex;
    flex-wrap: nowrap;
    gap:0.25rem;
    overflow-x: auto;
    overflow-y: hidden;
    padding-bottom:0.25rem;
    scrollbar-width: thin;
}

.tracking-comex-page #countryProcessModal .nav-tabs .nav-item {
    flex: 0 0 auto;
}

.tracking-comex-page #countryProcessModal .nav-tabs .nav-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap:0.25rem;
    width: auto;
    padding:0.25rem 0.5rem;
    font-size: 0.875rem;
    white-space: nowrap;
    text-align: center;
}

/* FCDS mono count pill on tabs (replaces Bootstrap badge bg-secondary). Neutral
   --acc-soft fill, mono tabular count in slate ink — never grey Bootstrap. */
.tracking-comex-page .tracking-modal .nav-tabs .tcx-tab-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.25rem;
    padding:0 0.5rem;
    margin-left:0.5rem;
    border-radius: var(--bs-border-radius-pill);
    background: var(--acc-soft);
    color: var(--acc-ink);
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    font-size: 0.875rem;
    line-height: 1.5;
}

.tracking-comex-page #countryProcessModal .modal-dialog {
    max-width: 32.5rem !important;
}

/* Bordo/bg/radius/padding-base vêm de .card.card-body (Bootstrap), aplicado
   junto no JS. cursor:pointer + hover elevado do bloco antigo foram removidos:
   este item é só informativo dentro do modal consolidado, sem handler de
   clique (afordância morta). Resta o espaçamento entre itens da lista. */
.tracking-comex-page .consolidated-process-item {
    margin-bottom:0.5rem;
}

.tracking-comex-page .consolidated-process-item:last-child {
    margin-bottom:0;
}

.tracking-comex-page .consolidated-process-item strong {
    font-size: 1rem;
}

.tracking-comex-page .consolidated-process-item div {
    font-size: 1rem;
    line-height: 1.5;
}

/* ===== MERGED FROM bi/static/bi/css/despesas_comex.css (P5) ===== */
/* ============================================================================
   Despesas Comex — pilot reference page (FCDS reference-quality refactor)

   Pilot-scoped ONLY. Every rule is namespaced under
   .page[data-pagina="despesas_comex"] so nothing here leaks to other pages
   or to the shared main.css / fcds/*.css layers. Loaded in {% block styles %}
   (after main.css, before statement-theme.css) — selectors carry the
   [data-pagina] attribute so they outrank statement-theme's lower-specificity
   rules without !important wherever possible.

   Goal: resolve the incoherences the audit found on this page —
     · the .content (gradient) vs .page (flat panel) surface seam,
     · KPI numbers not monospace (FCDS rule 3),
     · the 5-colour KPI "rainbow" (FCDS rule 1: one accent; rule 2: colour=meaning),
     · sub-12px filter labels,
     · filter strip / tab skin coherence.
   References: docs/planos/pilot-visual-audit-B.md, pilot-datatables-audit-C.md,
   pilot-color-audit-D.md.
   ========================================================================== */

/* ── 1. Surface seam ───────────────────────────────────────────────────────
   .content (shell) shows the body's 4-stop gradient over #edf0f4; .page
   painted a flat opaque #edf0f4 panel on top, masking the gradient inside the
   page while it stayed visible in the shell margins. Make the page transparent
   so the single body gradient is the one canvas under everything (system.md §9
   "one quiet gradient under everything"). Page-scoped; global .page untouched. */
.page[data-pagina="despesas_comex"] {
  background-color: transparent;
}

/* ── 2. Topbar timestamp ────────────────────────────────────────────────────
   Was inline style="font-size:0.875rem"; now a class on the same element.
   (KPI-band, filter-strip e length-select responsivo desta página foram
   canonizados: .kpi-band__secondary tabular-nums vive no componente global; os
   filtros migraram para os widgets colfilter canônicos; o length-select em mobile
   é tratado no componente .datatable compartilhado.) */
.df-timestamp {
  font-size: var(--bi-fs-caption, 0.875rem);
  font-variant-numeric: tabular-nums;
}

/* ===== DIAGNOSTICO (dp-*) ===== */
/* Diagnóstico de preenchimento — só o que NÃO é da permanência.
   Card, raias, KPIs e modais reusam custom.css (classes pp-*). */

.dp__escopo { color: var(--ink-2); }

/* A lista de processos preenche a altura restante do shell (.pp é flex column,
   altura fixa = 100vh - topbar) e ROLA sozinha. Antes o container herdava
   .pp__kanban, que é flex horizontal com overflow-y:hidden — feito para as raias
   rolarem lado a lado — e decepava a tabela alta por volta da 13ª linha: as 86
   linhas existiam no DOM mas só ~13 apareciam. overflow-x cobre telas estreitas. */
.dp__lista {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: auto;
}

/* Chip de sugestão do e-mail: `.card.border-start.border-success.border-3`
   (montarSugestao em diagnostico-preenchimento.js). Verde = resolvível, em
   contraste com o âmbar/vermelho da anomalia que o card responde; a faixa
   esquerda + `.card-body` bastam, sem CSS autoral. */

/* Tabela de processos. Cores do semáforo = as mesmas da permanência
   (custom.css), para que a régua de dias seja uma só na cabeça de
   quem lê as duas telas. */
.dp-tabela { font-size: 0.875rem; }
.dp-tabela th {
  font-size: 0.875rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--ink-3);
  font-weight: 600;
}
.dp-tabela tbody tr { cursor: pointer; }

.dp-modal__bl {
  padding:0.5rem 0;
  border-top: var(--bs-border-width) solid var(--line);
}
.dp-modal__bl-titulo { font-weight: 600; }
.dp-modal__bl-meta { font-size: 0.875rem; color: var(--ink-3); }
.dp-modal__anomalia {
  padding:0.5rem 0;
  border-top: var(--bs-border-width) solid var(--line);
}
.dp-modal__anomalia-detalhe { margin-top:0.25rem; color: var(--ink-2); }
.dp-modal__anomalia-bls { margin-top:0; font-size: 0.875rem; color: var(--ink-3); }
.dp-modal__evidencia { margin-top:0.25rem; }

/* ==========================================================================
   ESTOQUES — ícone de detalhe da grade
   Migrado do <style> inline de bi/templates/bi/estoques.html (regra dura: CSS
   autorado vive só aqui e em styles.css). As regras do antigo child-row de
   lotes (.estoque-lotes-scroll / .estoque-lotes) foram descartadas junto com o
   drill inline — o detalhe agora abre em modal.
   ========================================================================== */

.lote-caret {
  color: var(--ink-2);
  user-select: none;
  cursor: pointer;
}

/* ── Histórico de Preços — busca de produto ──────────────────────────────────
   A lista de sugestões é ancorada NO campo (overlay), não um bloco no fluxo:
   solta, ela aparecia descolada do input e empurrava a página a cada tecla. */
.hp-busca__lista {
    position: absolute;
    /* Colada no campo: o `+2px` daqui era o "espacinho" que fazia a lista parecer
       solta do input. Sem folga, campo e lista leem como UM controle. */
    top: 100%;
    left: 0;
    right: 0;
    /* ABAIXO da sidebar (`.side`, z-index 30) — a lista é conteúdo de página e não
       pode passar por cima do chrome do app quando a sidebar expande no hover.
       Acima do conteúdo comum da página, que não tem z-index. */
    z-index: 20;
    max-height: 20rem;
    overflow-y: auto;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .12);
    border: var(--bs-border-width) solid var(--line);
    background: var(--surf);
}
.hp-busca__lista .list-group-item.is-focused {
    background: var(--surf-2);
}

/* ── Histórico de Preços — pickers de mês (De/Até) ───────────────────────────
   Os dois campos são flatpickr com altInput: o input visível é criado pelo
   plugin e NÃO herda o width que ficava inline no <input type="month">. Largura
   travada aqui para o par De/Até não comer a linha do campo Produto. */
.hp-mes-input {
    width: 7rem;
    background-color: var(--surf);     /* readonly não pode parecer desabilitado */
    cursor: pointer;
}

/* ── Histórico de Preços — Buscar único (nível do produto) ───────────────────
   O gatilho de consulta desta tela é o botão ao lado do campo de produto. O
   Buscar do topbar (e o trigger mobile) ficam ocultos: mudar o período não pode
   fazer aparecer um segundo Buscar. O botão do campo pulsa quando há janela nova
   a aplicar (novo produto escolhido, ou período alterado). */
body.hp-buscar-unico #fcds-buscar,
body.hp-buscar-unico .btn-buscar-trigger { display: none !important; }

/* Topbar enxuta: só o período. O chip de Empresa (multi-empresa) fica oculto —
   remove o item do topbar sem mexer no ESCOPO: a empresa segue vindo do RBAC/URL,
   só some o controle. Segmento/Sub-seg já saem por `sem_segmentos` no include. */
body.hp-buscar-unico #fcds-empresa-wrap { display: none !important; }

/* Sem o aviso "Data alterada — clique em Buscar…" do shell: nesta tela quem sinaliza
   consulta pendente é o próprio botão do campo, que passa de `btn-outline-primary` a
   `btn-primary` (Bootstrap puro, sem CSS autoral — o pulso animado que morava aqui
   foi removido). O banner do topbar (que aparece com `body.fcds-pending`) seria um
   segundo aviso, apontando para o Buscar oculto. */
body.hp-buscar-unico #fcds-stale { display: none !important; }

/* ============================================================================
   Importar OF (Conexos → NF rascunho no Senior homolog) — tela oculta, F440GNE.
   Tudo escopado em + prefixo .iof-. Tokens FCDS.
   ============================================================================ */

.iof-panel{padding:0;overflow:hidden}
.iof-panel .card-hd{padding:1rem 1rem}
.iof-deprow{display:flex;align-items:center;gap:0.5rem;margin:0;
  font-size:0.875rem;color:var(--ink-3)}
.iof-deprow input{width: 4.375rem}

.iof-searchrow{padding:0.5rem 1rem;border-top:var(--bs-border-width) solid var(--line)}
.iof-list{max-height: 35rem;overflow-y:auto;border-top:var(--bs-border-width) solid var(--line)}

.iof-empty{padding:3rem 1rem;text-align:center;color:var(--ink-3)}
.iof-empty--err{color:var(--negative-text)}

.iof-doc__t{font-weight:600}
.iof-doc__sub{color:var(--ink-3);font-size:0.875rem;margin-top:0.25rem}
.iof-muted{color:var(--ink-3)}

.iof-sec{padding:1rem 1rem;border-top:var(--bs-border-width) solid var(--line)}
.iof-sec>h3{font-size:0.875rem;text-transform:uppercase;letter-spacing:.06em;
  color:var(--ink-3);font-weight:600;margin:0 0 0.5rem}
.iof-sec--muted>h3{color:var(--ink-4,var(--ink-3))}
.iof-fields{display:grid;
  grid-template-columns:repeat(auto-fill,minmax(11.25rem,1fr));gap:1rem 1rem}
.iof-f{display:flex;flex-direction:column;gap:0.25rem;min-width:0}
.iof-f__k{font-size:0.875rem;color:var(--ink-3);display:flex;align-items:center;gap:0.25rem}
.iof-f__v{font-weight:600;color:var(--ink);word-break:break-word}

/* itens: Bootstrap .table .table-sm (larg./bordas/padding). Só o cabeçalho
   uppercase-pequeno e o sub-texto de alíquota ficam custom (sem primitiva). */
.iof-items{font-size:0.875rem}
.iof-items th{font-size:0.875rem;text-transform:uppercase;
  letter-spacing:.04em;color:var(--ink-3)}
.iof-sub{color:var(--ink-3);font-size:0.875rem}

.iof-lote{display:flex;gap:1rem;align-items:flex-start;
  padding:1rem;border-radius:var(--r-sm);background:var(--surf-2);border:var(--bs-border-width) dashed var(--line-3);
  font-size:0.875rem;color:var(--ink-3)}
.iof-lote__ic{width: 1.875rem;height: 1.875rem;border-radius:var(--bs-border-radius-lg);background:var(--surf);
  border:var(--bs-border-width) solid var(--line-3);display:grid;place-items:center;flex:none;color:var(--ink-3)}
.iof-lote b{color:var(--ink-2)}

.iof-actionbar{display:flex;align-items:center;gap:1rem;flex-wrap:wrap;
  padding:1rem 1rem;border-top:var(--bs-border-width) solid var(--line)}
.iof-note{flex:1;min-width: 11.25rem;font-size:0.875rem;color:var(--ink-3)}
.iof-note b{color:var(--ink-2)}

.iof-result{display:flex;align-items:center;gap:0.5rem;
  padding:1rem 1rem;border-top:var(--bs-border-width) solid var(--line);font-size:0.875rem;color:var(--ink-2)}
.iof-result__ic{width: 1.875rem;height: 1.875rem;border-radius:50%;flex:none;
  display:grid;place-items:center;color:var(--bi-text-on-accent);font-weight:700}
.iof-result--loading{color:var(--ink-3)}
.iof-result--ok{background:var(--positive-subtle)}
.iof-result--ok .iof-result__ic{background:var(--positive)}
.iof-result--ok b{color:var(--positive-text)}
.iof-result--err{background:var(--negative-subtle)}
.iof-result--err .iof-result__ic{background:var(--negative)}
.iof-result--err b{color:var(--negative-text)}

/* corpo dos modais canônicos (biUtils.modalPadrao / Bootstrap) desta tela */
.iof-modal-sub{font-size:0.875rem;color:var(--ink-3);margin:0 0 0.5rem;padding-bottom:0.5rem;
  border-bottom:var(--bs-border-width) solid var(--line)}
.iof-json{margin:0;font-family:var(--mono);font-size:0.875rem;line-height:1.6;
  font-variant-numeric:tabular-nums;white-space:pre;overflow-x:auto;color:var(--ink-2)}
.iof-json .iof-jk{color:var(--brand-ink)}
.iof-json .iof-js{color:var(--positive-text)}
.iof-json .iof-jn{color:var(--cat-4)}
.iof-json .iof-jp{color:var(--ink-3)}
.iof-dup-list{margin:0.25rem 0 0.5rem;padding-left:1rem}
.iof-dup-list li{margin:0 0}

/* ── Histórico de Preços — controles compactos (produto + período no card) ───
   Produto e os dois campos de mês (De/Até) vivem no MESMO card, numa linha só.
   O produto cresce; os campos de mês têm largura fixa; Buscar alinha ao fim. */

/* ── Separação e faturamento ─────────────────────────────────────────────────
   A linha da tabela de itens é o alvo que troca o produto da etapa de lotes.
   Só o cursor entra aqui: a marcação da linha aberta é `.table-active` do
   Bootstrap e o anel de foco é o `:focus-visible` do Bootstrap — nada de
   destaque ou de foco autoral nesta tela. */
.sep-item-linha{cursor:pointer}
/* A marca da linha aberta é a classe `.table-active` do Bootstrap, mas a
   pintura dela mora em `.table > :not(caption) > * > *` — e a tabela desta
   tela é `.tbl`, não `.table`, então a classe entrava no DOM e não pintava
   nada (conferido ao vivo: background rgba(0,0,0,0) na linha marcada).
   Só se repete o seletor; a cor continua sendo a do Bootstrap — o token
   `--bs-table-active-bg` também só é declarado em `.table`, daí o fallback
   com o mesmo valor que o Bootstrap 5.2.3 lhe dá. */
.tbl > tbody > tr.table-active > td{background:var(--bs-table-active-bg,rgba(0,0,0,.1))}

/* ── Fila de pedidos da separação (escolher em QUAL pedido trabalhar) ─────────
   Onze colunas em 1.560 px, e a coluna da AÇÃO tem de ser uma delas. Medido
   antes: `Criado` saía cortada na borda direita e o botão Separar ficava FORA da
   tela — a fila oferecia trabalho que ninguém alcançava sem rolar de lado.
   `.cell-clip` genérico dá 22 rem, largo demais quando quatro colunas o usam
   (cliente, produto, comentário, vendedor). O truncamento em si é no JS, com o
   texto inteiro no `title`.

   E o cabeçalho no mesmo tom do resto da tela: caixa normal, miúdo, tinta fraca
   — o versalete espaçado do padrão FCDS empatava em peso com os badges de
   situação e urgência, que são o que a pessoa varre. Escopado à página; nenhuma
   outra tela muda. A superfície de trabalho é irmã deste bloco no template, não
   descendente, então não é alcançada por este seletor: quem a veste é `.pickbox`. */
/* AS COLUNAS SE AJUSTAM AO CONTEÚDO. O teto de 10rem foi calibrado quando a
   fila tinha ONZE colunas e quatro delas eram texto largo (cliente, produto,
   comentário, vendedor). Sobraram oito, e três daquelas quatro saíram — o teto
   fixo agora só serve para cortar nome de cliente numa tabela que tem espaço de
   sobra. `table-layout:auto` (já herdado) distribui pelo conteúdo; o
   truncamento continua existindo para o caso extremo, mas com um teto que
   respira e sem largura mínima que empurre as outras. */
/* LARGURA POR PAPEL, não uma trava só para todas. O teto único de 10rem
   cortava tudo igual — nome de cliente, produto e observação — num layout que
   já tinha espaço. Agora cada coluna de texto tem o teto do que ela precisa:

   - observação: é INSTRUÇÃO de quem vendeu ("ENTREGAR SÓ PELA MANHÃ",
     "FATURAR SOMENTE EM SETEMBRO"), lida antes de escolher o pedido — ganha o
     maior teto e quebra em até três linhas;
   - cliente: identifica, não instrui. Razão social de 50 caracteres não precisa
     caber inteira; o `title` guarda o resto;
   - financeiro: o motivo cabe em duas linhas curtas.

   `table-layout:auto` (herdado) distribui o resto pelo conteúdo. */
[data-pagina="separacao_faturamento"] .cell-clip{max-width:none}
[data-pagina="separacao_faturamento"] .tbl.dataTable td:nth-child(9){max-width:10rem}
/* O motivo do bloqueio para em DUAS linhas. Em tela estreita ele ia a quatro e
   levava a linha bloqueada a 111px — o dobro das outras, numa lista que se lê
   pela regularidade. Duas linhas mostram o motivo ("Limite de crédito do
   cliente"), que é o que manda falar com o comercial; a data e o resto ficam no
   `title` e na capa do pedido. */
[data-pagina="separacao_faturamento"] .sep-motivo{display:-webkit-box;
  -webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
[data-pagina="separacao_faturamento"] .tbl.dataTable td:nth-child(10) .cell-clip{
  max-width:26rem;white-space:normal;display:-webkit-box;-webkit-line-clamp:2;
  -webkit-box-orient:vertical;overflow:hidden}
/* ENTREGA EM UMA LINHA. A data e o selo do prazo cabiam em 147px numa coluna de
   144: quebravam por 3px, e essa quebra era o PISO de altura de toda linha da
   fila — 44px de conteúdo onde 26 bastavam. O `nowrap` aqui é de UMA coluna
   (tentei antes na tabela inteira e a rolagem lateral triplicou, de 210 para
   643px); com ela sem quebra, `table-layout:auto` tira os 25px que faltam da
   Observação, que tem 26rem de teto e sobra. */
[data-pagina="separacao_faturamento"] .tbl.dataTable td:nth-child(6){white-space:nowrap}
[data-pagina="separacao_faturamento"] .tbl.dataTable td:nth-child(3) .cell-clip{
  max-width:10rem}
/* PISOS DE LARGURA — SÓ ONDE HÁ LARGURA PARA REPARTIR.
   Com Entrega e Quantidade em uma linha, `table-layout:auto` passou a tirar
   píxeis de quem cede mais fácil: a Observação caiu de 323 para 154px (duas
   linhas onde não cabia uma ideia) e o motivo do bloqueio foi de duas para três
   linhas, levando a linha bloqueada a 95px. Um piso em cada uma corrige — mas
   piso em tela estreita vira ROLAGEM LATERAL, que é troca ruim: some justamente
   a Observação, a coluna que a pessoa lê antes de escolher o pedido. Medido em
   1440px sem a proteção da media query: a tabela pedia 1.505px num vão de 1.350.
   Daí a trava por viewport — acima de 1600px a régua fecha em 1.510px sem
   rolagem; abaixo, a tabela volta a ser fluida e quem cede é a largura, não a
   visibilidade. As alturas de linha (que é o que dá pedidos por tela) não
   dependem destes pisos: vêm do `nowrap` da Entrega, da quantidade em uma linha
   e do clamp de duas linhas — e valem em toda largura. */
/* Com folga de verdade na régua (medido: a 1600px ela fecha em 1.510px, sem um
   píxel sobrando), o nome do cliente volta a caber. 10rem é o teto que a tela
   estreita exige, não o que a larga merece. */
@media (min-width:1800px){
  [data-pagina="separacao_faturamento"] .tbl.dataTable td:nth-child(3) .cell-clip{
    max-width:14rem}
}
@media (min-width:1600px){
  [data-pagina="separacao_faturamento"] .tbl.dataTable td:nth-child(9){min-width:10rem}
  [data-pagina="separacao_faturamento"] .tbl.dataTable th:nth-child(9){min-width:10rem}
  [data-pagina="separacao_faturamento"] .tbl.dataTable td:nth-child(10),
  [data-pagina="separacao_faturamento"] .tbl.dataTable th:nth-child(10){min-width:13rem}
}

/* ── .detrow — LINHA DE DETALHE DE UMA TABELA (componente) ────────────────────
   O conteúdo que a linha truncada esconde, aberto embaixo dela. O corpo é
   desenhado por quem chama; aqui está a fita de rótulos, a célula do controle e
   o botão que gira. Casado com `row().child()` do DataTables — é a tabela que
   fecha a filha ao reordenar, filtrar e paginar. */
/* O controle é `.drill-plus`, a afordância canônica de abrir detalhe (mais ↔
   menos, glifo no `::before` do componente). A seta que girava aqui era
   invenção local: um segundo vocabulário de "abre isto" na mesma app. */
.detrow__cel{width:1%;padding-right:0}
/* A LINHA-FILHA não é uma linha de dados: não se lista, não reage ao mouse e não
   tem moldura. O DataTables cria o <tr> da filha sem classe, então ela caía nas
   regras de listra e de hover das outras linhas — e como o painel cinza tem
   fundo próprio, quem mudava de cor era só o PADDING da <td> em volta dele: uma
   moldura de 8 px que acendia e apagava conforme o cursor passava. Padding zero
   faz o painel preencher a célula, e o `box-shadow:none` desliga a listra e o
   realce (é por `box-shadow` inset que o Bootstrap pinta os dois).
   O `!important` do padding não é preferência: `.tbl.dataTable tbody td`
   já declara o dele com `!important`, e sem isto o zero é ignorado —
   medido no navegador, a moldura continuava lá. */
.tbl tbody tr.detrow__filha > td,
.tbl tbody tr.detrow__filha:hover > td{padding:0 !important;box-shadow:none;background:none}
/* Fundo BRANCO, como as linhas de dados: o painel é a continuação do pedido que
   está logo acima, não um bloco estranho encaixado na lista. O cinza que estava
   aqui competia com a listra da tabela e criava uma terceira cor de fundo. */
.detrow{display:grid;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));
  gap:.625rem 1.5rem;margin:0;padding:.75rem 1rem;background:var(--surf)}
.detrow__campo{min-width:0}
.detrow__campo dt{margin:0;font-size: var(--bi-fs-micro);font-weight:600;color:var(--ink-3)}
.detrow__campo dd{margin:.125rem 0 0;font-size: var(--bi-fs-compact);color:var(--ink)}
/* A faixa de medidas do topo separa-se da barra da tabela. */
/* A faixa de medidas é CONTEÚDO do cartão e precisa do recuo lateral que a
   regra global de coerência de página tira de toda `.page > section`
   (`padding-left/right:0 !important`, para a tabela poder encostar nas bordas).
   Sem isto a primeira medida nascia colada na borda esquerda e a última na
   direita — medido: a medida começava em x=69 num cartão que começa em x=68. A
   tabela SEGUE encostada, que é o que aquela regra existe para permitir. */
/* As medidas MORAM na barra da tabela (o JS as move para
   `.datatable-toolbar__left`, ao lado de Copiar e Colunas). Como faixa própria
   elas gastavam 56px de altura para dizer dois números, enquanto a barra ao
   lado tinha metade da largura vazia — duas faixas para uma leitura só. Aqui
   elas perdem a moldura de cartão e viram par rótulo/valor em linha: o mesmo
   texto, na altura que a barra já ocupava. */
[data-pagina="separacao_faturamento"] #sep-resumo{margin:0;gap:.25rem}
[data-pagina="separacao_faturamento"] #sep-resumo .measure{min-width:0;
  display:flex;align-items:baseline;gap:.375rem;padding:.125rem .5rem;
  background:none;border-color:transparent}
[data-pagina="separacao_faturamento"] #sep-resumo .measure dd{margin:0;font-size:.875rem}
/* A que pede atenção (bloqueados > 0) mantém o fundo de alerta — é a única que
   precisa saltar, e sem ela a barra ficaria com dois números iguais. */
[data-pagina="separacao_faturamento"] #sep-resumo .measure--alerta{
  background:var(--warning-subtle);border-color:var(--warning-border)}

/* QUANTIDADE EM UMA LINHA — estado à esquerda, número flush à direita. */
/* INLINE, não flex: num container flex o navegador descarta o nó de texto entre
   os dois spans, e o botão Copiar da barra levava "Não separado30.000 KG" para
   a área de transferência. Alinhamento pela direita e um recuo no rótulo dão o
   mesmo desenho preservando o espaço. */
[data-pagina="separacao_faturamento"] .sep-qtd{text-align:right;white-space:nowrap}
[data-pagina="separacao_faturamento"] .sep-qtd .sep-legenda{margin-right:.25rem}
/* TELA ESTREITA PAGA COM RECUO, NÃO COM ALTURA. Abaixo de 1400px a régua de dez
   colunas não fecha (medido: pedia 1.326px num vão de 1.276) e a saída óbvia
   seria deixar Entrega e Quantidade quebrarem de novo — mas isso devolve 12px
   de altura a TODAS as 72 linhas para acomodar duas. Apertar o recuo lateral
   das células devolve 8px por coluna, 80px na linha inteira, e não custa
   nenhuma altura: a tabela volta a caber e a densidade vale em toda largura. */
@media (max-width:1399px){
  [data-pagina="separacao_faturamento"] .tbl.dataTable td,
  [data-pagina="separacao_faturamento"] .tbl.dataTable th{
    padding-inline:.25rem !important}
}
[data-pagina="separacao_faturamento"] .sep-qtd .sep-legenda{font-size: var(--bi-fs-micro);letter-spacing:.03em}
/* Os dois botões da linha ficam com o recuo de um botão de GRADE, não de
   formulário: 159px para "Detalhes Separar" era largura de coluna de dados. O
   alvo de toque continua acima do mínimo (31px de altura, inalterado). */
[data-pagina="separacao_faturamento"] .tbl.dataTable td:nth-child(1) .btn{
  padding-inline:.5rem}

/* O RODAPÉ DA TABELA É UMA LINHA, não uma faixa. "1–72 de 72" mais um paginador
   de uma página só ocupavam 59px — mais que uma linha de pedido. O texto e os
   controles ficam (o contador é o que avisa quando um filtro escondeu gente);
   some o recuo que os cercava. */
[data-pagina="separacao_faturamento"] .datatable-bottom{padding-block:.25rem}
[data-pagina="separacao_faturamento"] .datatable-bottom .page-link{
  padding:.125rem .5rem;font-size: var(--bi-fs-compact)}
[data-pagina="separacao_faturamento"] .tbl thead th{text-transform:none;
  letter-spacing:0;font-size: var(--bi-fs-compact)}
/* A coluna da AÇÃO fica grudada na borda direita (componente `.stickcols` +
   `stick-r--1`, o mesmo das telas de matriz): são doze colunas num cartão de
   1.512 px, a tabela rola de lado, e o que saía de vista era justamente o botão
   — a pessoa via o pedido e não alcançava o trabalho dele sem rolar.
   Aqui só a largura: o resto (opacidade, listra, divisor, escada de z) já é do
   componente. Tentei antes um `position:sticky` local com `box-shadow` de
   divisor e caí exatamente na armadilha que o comentário do componente
   documenta: a listra do `.table-striped` é pintada com `box-shadow inset
   9999px`, que atropela o divisor e deixa a célula transparente em metade das
   linhas (medido: `background-color: rgba(0,0,0,0)` nas linhas `.odd`, com a
   data da coluna de trás aparecendo através do botão). */
[data-pagina="separacao_faturamento"] .tbl td.stick-r--1,
[data-pagina="separacao_faturamento"] .tbl th.stick-r--1{white-space:nowrap}

/* Alvo de toque do checkbox de lote. A caixa desenhada tem 14x14 px — metade
   do mínimo da WCAG 2.2 e impossível de acertar de luva num tablet do galpão.
   O <label> em volta alterna a caixa nativamente, então basta dimensioná-lo:
   44x44 px de área clicável com a caixa centrada e um pouco maior. */
.sep-alvo-toque{display:flex;align-items:center;justify-content:center;
  min-width:44px;min-height:44px;margin:0;cursor:pointer}
.sep-alvo-toque .form-check-input{width:1.5rem;height:1.5rem;margin:0;flex:none}

/* Depósito na linha do lote: código e nome em UMA linha. Quebrado em três
   ("1 ·" / "PLATINUM" / "LOG"), ele levava a linha de 40 para 72 px — a lista
   inteira perdia um terço das peças visíveis para escrever o mesmo depósito em
   toda linha. Nome longo é cortado com reticências; o valor inteiro fica no
   `title` da célula. */
.sep-lote-dep{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  max-width:11rem}

/* Barra de progresso da fila (separado × saldo). Fina de propósito: informa a
   proporção de relance sem competir com o número, que é o dado exato. O
   percentual vem pronto do backend (`progresso_pct`). */
.sep-progresso{height:.35rem;margin-top:.25rem}

/* Rodapé fixo do modal do pedido. Medido antes: um produto com 204 lotes dá
   `scrollHeight` 8.247 px numa janela de 779 px — dez telas de checkbox até o
   botão, que ficava DEPOIS da lista. Sticky dentro do `.modal-body` rolável põe
   a decisão sempre à mão. As margens negativas sangram o padding do corpo para
   a faixa ir de borda a borda, como um rodapé de modal de verdade. */
.sep-rodape{position:sticky;bottom:0;z-index:2;
  display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;
  margin:1rem -1rem -1rem;padding:.75rem 1rem;
  background:var(--surf);border-top:var(--bs-border-width) solid var(--line)}

/* Régua de peso — a peça de assinatura da tela e a única coisa dela que muda de
   cor. O pedido pede um número redondo (6.000 KG), o mundo entrega números
   tortos (1.748 + 1.579 + 1.702), e a pergunta que a pessoa faz o tempo todo é
   "o que marquei já cobre o pedido, e quanto passou?". Sem animação nenhuma:
   galpão, tablet, luva — a cor é o sinal inteiro, e por não se mover ela já
   respeita `prefers-reduced-motion`. A classificação (falta/coberto/passa) vem
   decidida do Python; aqui só se escolhe a cor de cada uma. */
.sep-regua{display:flex;align-items:baseline;gap:.5rem;flex-wrap:wrap;
  font-variant-numeric:tabular-nums}
.sep-regua__estado{font-weight:600;padding:.125rem .5rem;border-radius:var(--r-xs)}
.sep-regua--falta   .sep-regua__estado{background:var(--surf-3);color:var(--ink-2)}
.sep-regua--coberto .sep-regua__estado{background:var(--positive-subtle);color:var(--positive-text)}
.sep-regua--passa   .sep-regua__estado{background:var(--warning-subtle);color:var(--warning-text)}

/* ── .wsurface — SUPERFÍCIE DE TRABALHO (componente, não página) ─────────────
   Modo-tarefa em tela cheia: a lista de onde se veio some, e a tela inteira
   passa a ser a tarefa. Nasceu para a separação de pedidos, mas nada aqui sabe
   o que é um lote — serve qualquer fluxo em que a pessoa entra num registro,
   trabalha nele e sai (conferência, importação, fechamento).

   Por que não um modal: o modal é uma caixa por cima de uma lista, com duas
   barras de rolagem e um corpo que encolhe conforme o conteúdo cresce. Numa
   tarefa de galpão com 200 lotes isso é uma janelinha rolando dentro de outra.
   A superfície ocupa a altura útil e distribui: capa em cima, trilho de
   contexto à esquerda, trabalho no centro, decisão grudada embaixo. Cada painel
   rola por si; a página nunca rola.

   Estrutura:
     .wsurface > .wsurface__cap  (capa: quem é o registro)
               > .wsurface__body > .wsurface__rail  (contexto/navegação interna)
                                 > .wsurface__main  (o trabalho)
               > .wsurface__foot (medida + ação, sempre à vista) */
.wsurface{display:flex;flex-direction:column;gap:0;
  /* Altura FIXA, não mínima: é ela que faz o rodapé com a medida e a ação ficar
     sempre à vista. Com `min-height` a superfície crescia com a lista de lotes
     (11 lotes já passavam da dobra) e a decisão ia junto para o fim da página —
     exatamente o que o rodapé grudado existe para evitar. Quem rola é o painel
     de dentro. 52px = a topbar fixa (`.topbar`, 3.25rem), o mesmo literal que a
     coluna de conteúdo já desconta na linha 6677; não existe token de altura de
     topbar em `:root` e inventar um aqui criaria uma segunda verdade. */
  height:calc(100dvh - 52px - var(--content-pad-y) - var(--content-pad-b));
  background:var(--surf);border:var(--bs-border-width) solid var(--line);
  border-radius:var(--r);overflow:hidden}
/* A CAPA É UMA GRADE, não uma fila de blocos. Em flex, cada bloco aninhado
   media a própria largura e o que sobrava na linha ficava em branco: a linha do
   cliente acabava a 540px numa capa de 1.660 e as outras informações esperavam
   embaixo. Colunas de largura dinâmica (`auto-fill` + `minmax`) e cada
   informação como célula fazem a linha fechar sozinha, com a hierarquia dada
   pelo quanto cada uma ocupa: o cliente vale duas colunas, a data de entrega
   (que tem controle) duas, cada campo uma, e a advertência toma a sobra. */
/* A CAPA É UMA CAIXA DE FATOS ADENSADA.
   O formato continua o mesmo — rótulo miúdo em cima, valor embaixo —, o que
   muda é o quanto cada fato ocupa e como eles se arrumam. Antes: entrelinha de
   texto corrido, recuos de 1rem, colunas fixas e fileiras conforme sobrasse —
   uma ficha gastava 40px de altura para dizer "Carga · Carreta ou truque", e a
   capa ia a 364px.
   Agora a ficha tem 28px (rótulo em 11px/1.1, valor em 13px/1.2), o fluxo é por
   COLUNA sobre duas trilhas fixas — os fatos descem, viram a coluna e descem de
   novo, então quem se ajusta ao volume é o número de colunas, não a altura — e
   o cliente ocupa duas colunas de UMA fileira, não as duas: comendo as duas ele
   deixava um vão do tamanho dele embaixo do nome. */
.wsurface__cap{display:grid;
  /* 8 e 4 na régua de 12 do Bootstrap: os fatos com dois terços, a advertência
     com um. O voltar é trilha `auto` — tem largura de botão, não de coluna. */
  /* As fichas tomam a largura que PRECISAM e a advertência fica com o resto —
     não uma fatia fixa. Com 8fr/4fr as colunas de fato eram todas do mesmo
     tamanho, então "Cidade · JOINVILLE · SC" reservava tanto quanto "Frete ·
     CIF — frete por nossa conta" e sobrava um vão depois de cada valor curto,
     mais um vão maior antes da advertência. */
  /* 50/50: fichas e advertência com metade cada. Sem observação a regra abaixo
     colapsa para uma coluna só e as fichas tomam a capa inteira. */
  grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  align-items:stretch;gap:.375rem .875rem;
  padding:.5rem .875rem;border-bottom:var(--bs-border-width) solid var(--line);
  background:var(--surf-2)}
/* Sem observação não há segunda coluna: os fatos tomam a capa inteira. */
.wsurface__cap:has(> .wsurface__cap-obs:empty){grid-template-columns:minmax(0,1fr)}
/* AS FICHAS SE EMPACOTAM, NÃO SE ALINHAM EM COLUNAS. Numa grade de colunas, a
   coluna tem a largura da ficha MAIS LARGA dela: "Cliente · ALYA CONSTRUTORA
   S/A" esticava a coluna e deixava rastro branco depois de "Pedido · 20318",
   que está em cima. E `max-content` em todas as colunas estourava a capa em tela
   estreita — a advertência caía para o mínimo e era cortada.
   Empacotadas (flex com quebra), cada ficha mede o que o valor dela mede, elas
   enchem a linha até o fim e a seguinte recomeça. Não sobra rastro porque não
   há coluna a respeitar. */
.wsurface__cap-esq{display:flex;flex-wrap:wrap;align-content:flex-start;
  align-items:flex-start;justify-content:space-between;
  gap:.25rem 1.125rem;min-width:0}
/* A `<dl>` some como caixa para que cada ficha entre no empacotamento. Sem isto
   a fita inteira é UM item e não há o que empacotar. */
.wsurface__cap-esq > .wsurface__cap-campos{display:contents}
/* O cliente é ficha como as outras — mesmo rótulo miúdo, mesmo corpo de valor —
   só que com o dobro de LARGURA: a razão social tem 25 caracteres e numa coluna
   só ela quebraria em três linhas, esticando a fileira inteira. */

/* AS FICHAS SE ESPALHAM ATÉ AS DUAS BORDAS. Empacotadas só pelo tamanho do
   conteúdo, a última de cada fileira parava onde o texto dela acabava e o resto
   ficava em branco até a advertência — a faixa que estava circulada. Deixá-las
   CRESCER não resolve: a folga entra dentro da última ficha e o branco continua
   no mesmo lugar, só que dentro de uma caixa maior. Espalhando (`space-between`)
   a folga vira distância ENTRE as fichas, a primeira encosta na esquerda e a
   última na direita — não existe mais ponta livre. */
.wsurface__cap-campo{min-width:0;flex:0 1 auto}
.wsurface__cap-campo dt{font-size: var(--bi-fs-micro);line-height:1.1;text-transform:uppercase;
  letter-spacing:.02em;color:var(--ink-3);font-weight:600;margin:0}
.wsurface__cap-campo dd{margin:.0625rem 0 0;font-size: var(--bi-fs-compact);line-height:1.2;
  color:var(--ink);font-weight:500}
/* A entrega tem campo e botão; os dois cabem na largura de uma ficha. Ela nasceu
   em corpo de número (1,25rem) para sair do tamanho de filtro — numa grade em
   que cada fato vale uma célula, esse corpo obrigava a coluna a ser o dobro das
   vizinhas. */
/* A entrega tem campo e botão na MESMA linha do valor — empilhados, a ficha
   ficava mais alta que as vizinhas e a sobra virava faixa vazia sob elas. O
   botão virou ícone (o rótulo "Alterar" custava 55px numa fita onde cada ficha
   mede pouco mais de 100). */
.wsurface__cap-campo.sep-entrega dd{display:flex;align-items:center;gap:.25rem}
.wsurface__cap .sep-entrega__data{font-size: var(--bi-fs-compact);width:7rem;min-width:0;
  padding:.0625rem .25rem;height:auto;font-weight:600}
/* O `.ms-1` do botão vem do markup (herança do tempo em que ele ficava AO LADO
   do campo); empilhado, esse recuo o desalinhava do campo acima. */
.wsurface__cap .sep-entrega .btn{padding:.0625rem .375rem;font-size: var(--bi-fs-compact);
  margin-left:0 !important}
.wsurface__body{display:grid;grid-template-columns:minmax(15rem,20rem) minmax(0,1fr);
  flex:1;min-height:0}
.wsurface__rail{border-right:var(--bs-border-width) solid var(--line);
  overflow-y:auto;padding:.75rem}
/* Sem trilho, o trabalho toma a largura inteira. Sem esta regra a primeira
   trilha da grade continuaria reservada e sobraria uma coluna vazia de 15rem. */
.wsurface__body:has(> .wsurface__rail[hidden]){grid-template-columns:minmax(0,1fr)}
.wsurface__main{overflow-y:auto;padding:.75rem 1rem;min-width:0}
.wsurface__foot{position:sticky;bottom:0;z-index:2;
  display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;
  padding:.75rem 1rem;background:var(--surf);
  border-top:var(--bs-border-width) solid var(--line)}
/* O painel de confirmação EMPILHA: texto e previsão em cima, botões embaixo à
   direita. Como linha de rodapé, a previsão de 8 linhas crescia e os botões
   flutuavam no meio da lateral — era a "tela estranha" da foto do usuário. Com
   teto e rolagem própria, um pedido de 24 linhas não empurra a decisão para
   fora da tela. */
#sep-confirmacao{flex-direction:column;align-items:stretch;flex-wrap:nowrap;
  max-height:70vh;overflow:auto}
#sep-confirmacao > .d-flex{justify-content:flex-end}
/* Num tablet em pé o trilho vira uma faixa em cima do trabalho, não some:
   é ele que diz de qual item são as linhas do centro. */
@media (max-width:991.98px){
  .wsurface__body{grid-template-columns:minmax(0,1fr)}
  .wsurface__rail{border-right:0;border-bottom:var(--bs-border-width) solid var(--line);
    max-height:14rem}
}

/* Item selecionável do trilho — a versão em bloco da linha de tabela marcada.
   `aria-current` é quem manda: o estado visual segue o atributo que o leitor de
   tela já anuncia, em vez de uma classe paralela que pode divergir dele. */
.wsurface__item{display:block;width:100%;text-align:left;cursor:pointer;
  padding:.5rem .625rem;border:var(--bs-border-width) solid transparent;
  border-radius:var(--r-sm);background:none;color:inherit;margin-bottom:.25rem}
.wsurface__item:hover{background:var(--surf-2)}
.wsurface__item[aria-current="true"]{background:var(--acc-soft);
  border-color:var(--acc-line)}
/* As medidas dentro do cartão do item: mesmo componente, escala do trilho. A
   coluna tem ~300 px e a ficha padrão (7rem de largura mínima) só deixava duas
   por linha com folga nenhuma. Aqui elas encolhem para caber as três, e a
   margem de baixo sai porque quem separa os cartões é a margem do próprio
   cartão. */
.wsurface__item .measures{margin:0;gap:.25rem}
.wsurface__item .measure{min-width:0;flex:1 1 4.5rem;padding:.25rem .5rem}
.wsurface__item .measure__v{font-size: var(--bi-fs-compact)}
.wsurface__item[aria-current="true"] .measure{background:var(--surf)}
.wsurface__item[aria-current="true"] .measure--dest{background:var(--acc-soft)}

/* ── .fillbar — BARRA SEGMENTADA RUMO A UM ALVO (componente) ─────────────────
   Uma barra de progresso responde "quanto por cento". Esta responde "de que
   PARTES o total é feito": um segmento por parcela, cada um com a largura da
   sua contribuição. Na separação, cada segmento é uma bobina — e é assim que se
   enxerga que 20 t são treze bobinas e não um número. Serve igual para meta
   composta por vendedor, carteira por faixa, orçamento por rubrica.

   As larguras (`pct`), o traço do alvo (`alvo_pct`) e quem é excesso chegam
   calculados do backend. A escala é o maior entre alvo e total, então quando a
   seleção passa do alvo o traço cai antes do fim e o excesso aparece hachurado
   em vez de estourar o contêiner.

   Sem transição: galpão, tablet, luva — e por não se mover já respeita
   `prefers-reduced-motion` sem uma media query. */
/* Fina e em pílula, como no desenho aprovado: 20 px de altura davam a uma medida
   auxiliar o peso visual de um gráfico, competindo com o número exato que está
   logo abaixo dela. A barra responde "de quantas partes"; quem responde "quanto"
   é a legenda. */
.fillbar{position:relative;display:flex;height:.625rem;overflow:visible;
  background:var(--surf-3);border-radius:var(--r-full)}
.fillbar__seg{min-width:1px;background:var(--acc);
  border-right:1px solid var(--surf)}
.fillbar__seg:first-child{border-start-start-radius:var(--r-full);
  border-end-start-radius:var(--r-full)}
.fillbar__seg:last-child{border-right:0;
  border-start-end-radius:var(--r-full);border-end-end-radius:var(--r-full)}
.fillbar__seg--over{background:repeating-linear-gradient(45deg,
  var(--warning-text) 0 4px,var(--warning-subtle) 4px 8px)}
/* Traço do alvo: onde o pedido termina. Fica por cima dos segmentos e sobra 3 px
   para cada lado — numa barra de 10 px, um traço contido nela desaparece. */
.fillbar__mark{position:absolute;top:-3px;bottom:-3px;width:2px;margin-left:-1px;
  background:var(--ink);pointer-events:none}
.fillbar__mark::after{content:attr(data-rotulo);position:absolute;top:100%;
  left:0;transform:translateX(-50%);white-space:nowrap;
  font-size: var(--bi-fs-micro);color:var(--ink-3)}
/* Legenda da barra: números tabulares e o estado em pílula. A classificação
   (falta/coberto/passa) vem decidida do backend; aqui só se pinta cada uma. */
.fillbar-leg{display:flex;align-items:baseline;gap:.5rem;flex-wrap:wrap;
  font-variant-numeric:tabular-nums}
.fillbar-leg__estado{font-weight:600;padding:.125rem .5rem;border-radius:var(--r-xs)}
.fillbar-leg--falta   .fillbar-leg__estado{background:var(--surf-3);color:var(--ink-2)}
.fillbar-leg--coberto .fillbar-leg__estado{background:var(--positive-subtle);color:var(--positive-text)}
.fillbar-leg--passa   .fillbar-leg__estado{background:var(--warning-subtle);color:var(--warning-text)}

/* ── .stepbar — FAIXA DE PASSOS QUE INSTRUI (componente) ─────────────────────
   Não é um "stepper" decorativo com bolinhas numeradas: o TEXTO de cada passo
   muda com o estado, então a faixa responde "o que eu faço agora, e o que isto
   vai causar no registro" em vez de enumerar etapas. Numa tela que grava de
   forma irreversível num ERP, é ela que carrega a consequência em português
   antes de a pessoa clicar — o número sozinho não avisa nada.

   Serve qualquer fluxo de poucos passos onde a consequência importa mais que a
   contagem (separação, importação, fechamento). Nada aqui sabe o que é um lote.

   `data-ativo` / `data-feito` são atributos, não classes: quem escreve a faixa
   decide o estado num lugar só e o CSS lê exatamente o mesmo dado.

   As divisórias saem de `gap` sobre um fundo da cor da linha, não de
   `border-right` no passo: com `auto-fit` os passos podem quebrar em duas
   fileiras, e a borda lateral deixaria a fileira de baixo sem separador em cima
   (e o último da primeira fileira com uma borda sobrando). */
/* OS PASSOS PESAM IGUAL. O passo zero ("Voltar à fila") é um botão de largura
   própria; 1, 2 e 3 dividem em partes iguais o que sobra, cada um com título e
   frase. O passo ativo se distingue pela cor e pelo numeral, não por roubar
   largura dos vizinhos — uma faixa que muda de geometria a cada marcação faz o
   olho reprocessar a instrução inteira. */
.stepbar{display:flex;flex-wrap:wrap;
  gap:var(--bs-border-width);background:var(--line);
  border-bottom:var(--bs-border-width) solid var(--line)}
.stepbar__passo{display:flex;align-items:center;gap:.625rem;flex:1 1 0;
  min-width:0;padding:.5rem 1rem;background:var(--surf-2)}
.stepbar__voltar{flex:0 1 auto}
.stepbar__num{flex:none;display:flex;align-items:center;justify-content:center;
  width:1.375rem;height:1.375rem;border-radius:var(--r-full);
  background:var(--surf-3);color:var(--ink-3);
  font-size: var(--bi-fs-compact);font-weight:600;line-height:1}
/* UMA LINHA POR PASSO. Título em cima e descrição embaixo davam 80px de faixa
   permanente — duas linhas de instrução para três passos, dos quais só um está
   acontecendo. Título e descrição na MESMA linha, e o que não couber na fatia
   do passo é cortado com reticências (o texto inteiro fica no `title`). A faixa
   cai para 40px e os 40 que sobram vão para a lista de lotes, que é onde o
   trabalho acontece. */
.stepbar__txt{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.stepbar__txt b{font-size: var(--bi-fs-compact);font-weight:600;color:var(--ink)}
.stepbar__txt span{font-size: var(--bi-fs-compact);color:var(--ink-2);line-height:1.45}
.stepbar__txt span::before{content:" — "}
/* O passo ZERO: mesmo desenho dos outros, mas é botão. `.stepbar__voltar` não
   tem numeral — tem a seta —, e é o único da faixa que reage ao ponteiro. */
.stepbar__voltar{border:0;font:inherit;text-align:left;color:var(--acc);cursor:pointer}
.stepbar__voltar .stepbar__num{background:var(--acc-soft);color:var(--acc)}
.stepbar__voltar .stepbar__txt b{color:var(--acc)}
.stepbar__voltar:hover{background:var(--acc-soft)}
.stepbar__passo[data-ativo="1"]{background:var(--surf)}
.stepbar__passo[data-ativo="1"] .stepbar__num{background:var(--acc);color:#fff}
.stepbar__passo[data-feito="1"] .stepbar__num{background:var(--positive-text);color:#fff}
/* Passo que ainda não chegou: só o título recua de tinta, para o passo ativo
   ser o que salta sem que os outros virem texto ilegível. */
.stepbar__passo[data-ativo="0"][data-feito="0"] .stepbar__txt b{color:var(--ink-3)}

/* ── .pickbox — BLOCO DE ESCOLHA (componente) ────────────────────────────────
   O par "o que eu já escolhi" × "o que ainda há para escolher", cada um num
   bloco com cabeçalho e contagem próprios. Uma lista só, com as marcações
   espalhadas entre 200 linhas, obriga a reler a lista inteira para conferir a
   escolha; partida em dois, a conferência é o bloco de cima e nada mais.

   Nada aqui sabe o que é bobina: serve qualquer seleção dentro de um catálogo
   longo (notas de um lote, títulos de uma remessa, linhas de uma conferência). */
/* O par de blocos lado a lado numa tela larga, empilhado no tablet em pé.
   Empilhados sempre, uma escolha de 34 itens ocupa a tela e a lista de onde se
   escolhe nasce fora da dobra (medido: 700 px de profundidade). Lado a lado, o
   item sai de uma coluna e entra na outra à vista. */
.pickbox-par{display:grid;gap:1rem;grid-template-columns:minmax(0,1fr)}
@media (min-width:1200px){.pickbox-par{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}}
.pickbox{margin-bottom:1rem}
.pickbox__cab{display:flex;align-items:baseline;gap:.75rem;flex-wrap:wrap;
  margin-bottom:.375rem}
.pickbox__cont{font-size: var(--bi-fs-compact);color:var(--ink-3);font-variant-numeric:tabular-nums}
/* A dica de ordenação encosta na direita: é ajuda de uso, não título. */
.pickbox__dica{margin-left:auto;font-size: var(--bi-fs-compact);color:var(--ink-3)}
/* Vazio INSTRUTIVO — diz o que fazer, não só que está vazio. Tracejado para não
   se confundir com uma tabela de verdade que por acaso não tem linhas. */
.pickbox__vazio{border:var(--bs-border-width) dashed var(--line-3);
  border-radius:var(--r-sm);padding:.875rem;text-align:center;
  font-size:.875rem;color:var(--ink-3)}
/* O bloco dos escolhidos leva o fundo do acento nas linhas: é o que distingue
   "escolhido" de "livre" com a lista rolada. */
.pickbox--escolhidos tbody > tr > td{background:var(--acc-soft)}
/* Cada bloco rola por si, com altura limitada — é o que faz os dois caberem na
   mesma tela. Sem isto, uma escolha de 34 itens empurra a lista do que ainda há
   para escolher a 2.101 px de profundidade (medido), e o trabalho seguinte fica a
   duas telas de distância. O bloco dos escolhidos é mais baixo: ele existe para
   conferir a escolha, não para navegar nela. */
.pickbox__rolo{max-height:22rem;overflow:auto;
  border:var(--bs-border-width) solid var(--line);border-radius:var(--r-sm)}
/* AS LISTAS ESTICAM ATÉ O RODAPÉ. O teto de 22rem acima é o fallback das telas
   baixas e do empilhado; lado a lado (≥1200px), a altura vem da corrente de
   flex que desce do painel: o que sobrar entre o cabeçalho do produto e o
   rodapé é das listas — era a faixa morta que sobrava embaixo delas. Cada elo
   com `min-height:0`, senão o flex recusa encolher e a rolagem interna morre. */
/* O anúncio da fila alinha com o CONTEÚDO da tabela, não com a borda do
   cartão: a toolbar tem 16px de recuo interno, e o balão colado na borda
   parecia sangrar dos dois lados (queixa do usuário, duas vezes). */
#sep-anuncio .alert{margin-inline:1rem}
/* A margem do resultado só existe quando há resultado: o `mt-3` do Bootstrap
   (que é !important) contava 16px de faixa morta mesmo com o nó vazio. */
#sep-resultado:not(:empty){margin:1rem 0}
/* O resultado da data (aviso/erro/sucesso do salvar) nasce num <span> dentro da
   célula da capa: sem virar bloco com respiro próprio, o alert encosta no campo
   e na borda da célula. */
#sep-data-resultado:not(:empty){display:block;margin-top:.375rem}
/* O CÁLCULO NO BACKEND TEM CARA: enquanto a releitura do estoque corre, régua e
   passos apagam meio tom (o número visível é o ANTERIOR) e um girador aparece
   na ponta da régua. Some sozinho quando a resposta chega e tudo é reescrito. */
.sep-aguarda{opacity:.55;transition:opacity .15s}
#sep-medida.sep-aguarda::after{content:"";display:inline-block;
  width:.875rem;height:.875rem;margin-left:.5rem;vertical-align:-.125rem;
  border:2px solid var(--acc);border-right-color:transparent;
  border-radius:var(--r-full);animation:bi-spin .6s linear infinite}
@media (prefers-reduced-motion:reduce){
  #sep-medida.sep-aguarda::after{animation:none;border-right-color:var(--acc-soft)}
}
@media (min-width:1200px){
  .wsurface__main{display:flex;flex-direction:column}
  .wsurface__main #sep-lotes{display:flex;flex-direction:column;flex:1;min-height:0}
  .wsurface__main #sep-lotes-listas{flex:1;min-height:0}
  .wsurface__main .pickbox-par{height:100%;grid-template-rows:minmax(0,1fr)}
  .wsurface__main .pickbox{display:flex;flex-direction:column;min-height:0}
  .wsurface__main .pickbox__rolo{flex:1;min-height:0;max-height:none}
}
/* Cabeçalho que acompanha a rolagem do próprio bloco. Numa lista de 166 itens ele
   é mais que rótulo de coluna: é o único controle de ordenação, e rolar embora o
   tornava inalcançável sem voltar ao topo.
   `border-collapse:separate` é REQUISITO, não estética: com o `collapse` do `.tbl`
   o Chromium simplesmente ignora `sticky` em `th` (medido — o cabeçalho rolou
   junto, a 634 px acima do topo do painel). Mesmo motivo pelo qual `.dre-tabela`
   já faz isso neste arquivo. */
.pickbox .tbl{border-collapse:separate;border-spacing:0}
/* A coluna da CAIXINHA vem primeiro e é a mais estreita possível: é o controle
   de inclusão, e a pessoa varre a lista por ela. A segunda coluna (o código do
   lote) é a identidade do item e absorve toda a folga da tabela — sem isto
   (medido) a coluna do peso ficava com 522 px e o número nadava a 300 px do seu
   próprio cabeçalho. */
.pickbox thead th:first-child,.pickbox tbody td:first-child{width:1%;
  padding-right:0;white-space:nowrap}
.pickbox thead th:nth-child(2),.pickbox tbody td:nth-child(2){width:100%}
/* A caixinha alinhada ao centro da sua célula, sem esticar a linha rasa. */
.pickbox__marca{text-align:center;vertical-align:middle}
.pickbox__marca .form-check-input{margin:0;cursor:pointer}
/* A linha inteira responde à marcação — o fundo já distingue os dois blocos, mas
   dentro do bloco de escolhidas a caixinha marcada é o que confirma "esta entra". */
.pickbox tbody tr:has(.form-check-input:checked){background:var(--acc-soft)}
/* O campo numérico é `display:block` com largura fixa (Bootstrap), e `text-align`
   não move caixa de bloco — `margin-left:auto` é o que o encosta no fim da coluna,
   embaixo do cabeçalho dela. Escopado ao `.pickbox`: o mesmo `.inp-qty` é usado
   dentro de linhas flex noutros lugares, onde `auto` empurraria para o lado errado. */
.pickbox td > .inp-qty{margin-left:auto}
/* Densidade e tom de instrumento, portados do mockup aprovado. Duas diferenças
   deliberadas do `.tbl` padrão do app, e só dentro do `.pickbox`:
   - cabeçalho em caixa NORMAL, sem letter-spacing, miúdo e em tinta fraca. O
     versalete espaçado do padrão grita numa tabela de 200 linhas onde o
     cabeçalho é permanente (é `sticky`) e o que importa são os números.
   - linhas mais rasas. A 32 px por linha caberiam 6 bobinas na área do bloco; a
     26 px cabem 8, e é lista de escolher, não de ler.
   Fora do `.pickbox` o padrão do FCDS segue intacto — nenhuma outra tela muda. */
.pickbox .tbl{font-size:.875rem}
.pickbox .tbl thead th{text-transform:none;letter-spacing:0;font-size: var(--bi-fs-compact);
  border-bottom:var(--bs-border-width) solid var(--line-3);
  padding:.375rem .625rem}
.pickbox .tbl tbody td{padding:.25rem .625rem}
/* O código do item não quebra em duas linhas: "COR3075/22H-MO110225-150768 A"
   quebrado desalinha a linha inteira das vizinhas, e truncar um código de lote é
   pior que rolar — é ele que a pessoa confere contra a etiqueta da bobina. Quando
   não couber, o bloco rola de lado (`.pickbox__rolo` já é `overflow:auto`). */
.pickbox tbody td:nth-child(2){white-space:nowrap}
/* Campo dentro de linha rasa: o `form-control-sm` do Bootstrap ainda tem 31 px de
   altura e esticava a linha da bobina escolhida em 8 px sobre as demais. */
.pickbox .inp-qty{padding-block:.125rem;height:auto}

/* ── .sep-estado — O PEDIDO COMO ESTÁ HOJE, na coluna de contexto ────────────
   A tabela vive numa coluna de ~300 px e é de LEITURA, não de trabalho: nada
   nela pode ser cortado, ou ela deixa de responder à única pergunta que existe
   para fazer ("como está o pedido?"). `table-layout:fixed` + `width:100%` fazem
   as duas colunas dividirem a largura disponível em vez de exigirem a largura do
   conteúdo — medido: sem isto a coluna da quantidade saía da caixa e mostrava
   "1", "28", "250" no lugar de "1.771 KG". */
.sep-estado .tbl{table-layout:fixed;width:100%;font-size: var(--bi-fs-compact)}
.sep-estado .tbl th,.sep-estado .tbl td{padding:.375rem .5rem}
.sep-estado .tbl thead th{text-transform:none;letter-spacing:0;font-size: var(--bi-fs-micro)}
/* O código da bobina é longo e aqui pode quebrar: nesta coluna ele é referência
   de leitura, não o campo que se confere contra a etiqueta (esse está na lista
   de escolha, onde não quebra). */
.sep-estado .tbl td{white-space:normal;overflow-wrap:anywhere}
.sep-estado .badge{margin-top:.125rem}

/* ── .sep-entrega / .sep-obs — O QUE A CAPA NÃO DIZ E O GALPÃO PRECISA ───────
   A data de entrega decide a ordem do trabalho e estava do tamanho de um filtro,
   ao lado de um botão escrito "Salvar". A observação do pedido é INSTRUÇÃO de
   quem vendeu para quem carrega ("ENTREGAR SÓ PELA MANHÃ", o cronograma inteiro)
   e estava em `small` cinza no pé da coluna. As duas sobem de patamar: a data em
   corpo de número, a observação em corpo de leitura. */
.sep-entrega__data{font-size:1.25rem;font-weight:600;font-variant-numeric:tabular-nums;
  padding:.25rem .5rem;height:auto;width:auto}
.sep-obs p:last-child{margin-bottom:0}
.sep-obs{font-size:.875rem}

/* ── .measures — AS MEDIDAS DE UM REGISTRO, EM FICHAS (componente) ───────────
   Os números que decidem o trabalho, um por ficha, com a ficha do ALVO em
   acento. Era uma fita de `<dt>/<dd>` do mesmo tamanho para tudo: pedido,
   separado e saldo pesavam igual, e o saldo — o único número que a pessoa
   precisa cobrir com bobinas — não se destacava de nada.
   `--dest` marca a medida que é o alvo do trabalho, nunca "a mais importante do
   ponto de vista do negócio": quem escolhe é quem monta a tela. */
.measures{display:flex;gap:.5rem;flex-wrap:wrap;margin:0 0 .75rem}
.measure{min-width:7rem;padding:.375rem .75rem;background:var(--surf-2);
  border:var(--bs-border-width) solid var(--line);border-radius:var(--r-sm)}
.measure dt,.measure__k{margin:0;font-size: var(--bi-fs-micro);font-weight:600;color:var(--ink-3)}
.measure dd,.measure__v{margin:.0625rem 0 0;font-size:1rem;font-weight:600;
  color:var(--ink);font-variant-numeric:tabular-nums}
.measure--dest{background:var(--acc-soft);border-color:var(--acc-line)}
.measure--dest dd,.measure--dest .measure__v{color:var(--acc-ink)}
/* `--alerta` é a medida que PEDE ATENÇÃO quando não é zero (pedidos atrasados,
   pedidos bloqueados). Distinta de `--dest`, que é o alvo do trabalho: uma diz
   "é isto que você tem de cobrir", a outra "olhe para isto". */
.measure--alerta{background:var(--warning-subtle);
  border-color:color-mix(in srgb,var(--warning) 34%,transparent)}
.measure--alerta dd,.measure--alerta .measure__v{color:var(--warning-text)}

/* ── .nota — RECADO QUE EXPLICA (componente) ─────────────────────────────────
   O `.alert` do Bootstrap é feito para interromper: fundo saturado, tinta da
   própria cor, peso de anúncio. Isto é para EXPLICAR uma regra de negócio no
   lugar onde ela morde — tinta normal (legível em bloco de 3 linhas), fundo
   discreto, e a cor só na borda e no título. Numa tela que grava sem volta, a
   pessoa tem de LER o recado; um `.alert` amarelo de quatro linhas é o que se
   aprende a pular. */
.nota{padding:.625rem .8125rem;margin-bottom:.875rem;
  border:var(--bs-border-width) solid var(--line);border-radius:var(--r-sm);
  background:var(--surf-2);font-size:.875rem;line-height:1.6;color:var(--ink)}
.nota__t{display:block;font-weight:600;margin-bottom:.125rem}
.nota--info{background:var(--acc-soft);border-color:var(--acc-line)}
.nota--info .nota__t{color:var(--acc-ink)}
.nota--aviso{background:var(--warning-subtle);
  border-color:color-mix(in srgb,var(--warning) 34%,transparent)}
.nota--aviso .nota__t{color:var(--warning-text)}
.nota--risco{background:var(--negative-subtle);
  border-color:color-mix(in srgb,var(--negative) 34%,transparent)}
.nota--risco .nota__t{color:var(--negative-text)}

/* ── .chglist — O QUE VAI MUDAR NO REGISTRO (componente) ─────────────────────
   Uma linha por alteração, tingida pelo tipo dela, e o total antes → depois no
   pé. Substitui duas tabelas lado a lado ("como está" × "como fica"): medido, um
   pedido de 35 rolos gerava 40 linhas de tabela em duas colunas — 700 px de
   conferência antes de a pessoa chegar ao trabalho. A informação é a mesma,
   porque cada linha do depois já vem classificada em nova/alterada/intacta pelo
   backend: a cor diz o que a segunda tabela dizia por comparação. */
.chglist{display:flex;flex-direction:column;gap:.125rem}
.chg{display:grid;grid-template-columns:2.5rem minmax(0,1fr) auto;gap:.5rem;
  align-items:baseline;padding:.3125rem .625rem;border-radius:var(--r-sm);
  font-size:.875rem;background:var(--surf-2)}
.chg__seq{font-size: var(--bi-fs-compact);color:var(--ink-3);font-variant-numeric:tabular-nums}
.chg__lote{color:var(--ink-2);font-size: var(--bi-fs-compact);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chg__kg{font-weight:600;font-variant-numeric:tabular-nums;text-align:right}
.chg__et{display:block;font-size: var(--bi-fs-micro);font-weight:600;color:var(--ink-3);
  text-transform:uppercase;letter-spacing:.03em}
/* "sem lote" é rótulo de estado, como as etiquetas — mesma caixa alta. */
.chg--nova .chg__lote{text-transform:uppercase;font-size: var(--bi-fs-compact)}
.chg--nova{background:var(--positive-subtle)}
.chg--nova .chg__et{color:var(--positive-text)}
.chg--alterada{background:var(--acc-soft)}
.chg--alterada .chg__et{color:var(--acc-ink)}
/* A linha que a separação cancela. Tachada porque cancelar é só de ida: o
   Senior não desfaz, e a quantidade riscada diz isso sem precisar de legenda. */
.chg--cancelada{background:var(--negative-subtle)}
.chg--cancelada .chg__et{color:var(--negative-text)}
.chg--cancelada .chg__lote,.chg--cancelada .chg__kg{text-decoration:line-through}
.chg__tot{display:flex;justify-content:space-between;gap:.625rem;
  margin-top:.625rem;padding-top:.625rem;
  border-top:var(--bs-border-width) solid var(--line);
  font-size:.875rem;color:var(--ink-2)}
.chg__tot strong{color:var(--ink);font-variant-numeric:tabular-nums}
.pickbox thead th{position:sticky;top:0;z-index:1;
  background:var(--surf-2);box-shadow:inset 0 -1px 0 var(--line-3)}

/* ── .th-ord — CABEÇALHO QUE ORDENA A COLUNA (componente) ────────────────────
   Clique troca o critério, invertendo o sentido se já era ele; shift+clique
   acrescenta um segundo critério como desempate, e aí cada seta ganha o número
   da sua prioridade. `aria-sort` é o que o leitor de tela anuncia — e é o mesmo
   atributo que o CSS lê para pintar, então áudio e tela não podem divergir.

   Para tabelas montadas à mão (`.tbl`). Quem usa DataTables já ganha o
   ordenador do plugin e não precisa disto. */
.th-ord{cursor:pointer;user-select:none}
.th-ord:hover{background:var(--surf-2)}
.th-ord[aria-sort]:not([aria-sort="none"]){color:var(--acc-ink)}
.th-ord__seta{margin-left:.25rem;font-size: var(--bi-fs-compact);opacity:.45}
.th-ord__seta--on{opacity:1}
.th-ord__seta sup{font-size:.65em;margin-left:.0625rem}

/* O utilitário `.rail--danger|warning|positive` (filete de cor na borda esquerda
   da linha) FOI REMOVIDO por pedido do usuário. Ele existia para dar à fila de
   pedidos um sinal de urgência legível de longe, mas repetia em cor o que a
   coluna Urgência diz em palavra — e com 119 dos 121 pedidos atrasados a lista
   inteira ficava vermelha: uma marca que vale para todos não distingue ninguém.
   A fila tinha o único consumidor; sem ele o CSS ficaria morto. Se um dia
   alguma tela precisar do padrão, o histórico do git tem a implementação (e o
   porquê de ser `::before` posicionado e não `box-shadow: inset`, que o zebrado
   do Bootstrap 5.2 apagava nas linhas pares). */

/* ── .cell-clip — CÉLULA QUE NÃO DEIXA A TABELA CRESCER (utilitário) ─────────
   Um texto longo numa célula (uma observação de pedido com 300 caracteres)
   empurra as colunas seguintes para fora da tela. Com `text-truncate` do
   Bootstrap junto, a célula mostra o começo e o resto vive no `title`. */
.cell-clip{max-width:22rem}

/* ── .inp-qty — CAMPO NUMÉRICO DENTRO DE CÉLULA (utilitário) ─────────────────
   Quantidade editável numa tabela: estreito, alinhado à direita, tabular, e sem
   as setas do `number` (que roubam 1rem da largura e disparam com a rolagem do
   dedo). O `inputmode` é o que traz o teclado numérico no tablet. */
.inp-qty{width:7.5rem;text-align:right;font-variant-numeric:tabular-nums}
.inp-qty::-webkit-outer-spin-button,
.inp-qty::-webkit-inner-spin-button{appearance:none;margin:0}
.inp-qty[type=number]{appearance:textfield;-moz-appearance:textfield}

/* ── Skip link do shell ──────────────────────────────────────────────────────
   Primeiro focável do documento. Fora do foco fica acima da borda da janela
   (nunca `display:none`, que o tiraria da ordem de tabulação e o mataria);
   ao receber foco de teclado desce para o canto e vira um botão comum.
   Medido antes dele: 86 Tabs até o primeiro elemento do conteúdo. */
.skip{position:fixed;top:-4rem;left:.75rem;z-index:2000;
  padding:.5rem .875rem;border-radius:.5rem;
  background:var(--brand);color:#fff;text-decoration:none;font-weight:600}
.skip:focus-visible{top:.75rem}
/* O contêiner de conteúdo só é focável para receber o salto — sem anel. */
.content:focus{outline:none}

/* ── Separação · a linha do tempo do produto no pedido ───────────────────────
   Só LEITURA. Era uma lista de rádios para escolher em qual parte se trabalha,
   e ela morreu junto com o recorte por linha: o pool de separação é o produto,
   e no pedido 19880 essa lista tinha 24 rádios para escolher um. O que sobra é
   o que ela sempre respondeu bem — "o que tem neste produto": o que falta
   separar, o que já está com lote, o que virou nota, o que foi cancelado.

   Uma coluna só: o painel tem 400px. Viva em tinta cheia, histórico em tinta
   fraca; a quantidade à direita, alinhada, porque é ela que distingue uma parte
   da outra quando duas têm o mesmo estado. */
.sep-item-cab{display:flex;align-items:center;justify-content:space-between;
  gap:.5rem 1rem;flex-wrap:wrap}
.sep-item-cab .min-w-0{min-width:0}
/* Nome, código e entrega na MESMA linha de base; os controles da lista
   (filtro, depósito, histórico) fecham a faixa à direita. */
.sep-item-cab__id{display:flex;align-items:baseline;gap:.5rem;flex-wrap:wrap}
.sep-item-cab__acoes{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;
  margin-left:auto}
.sep-partes{margin-top:.5rem;background:var(--surf-2);border-radius:var(--radius);
  padding:.5rem .625rem}
.sep-partes__cab{font-size: var(--bi-fs-micro);text-transform:uppercase;letter-spacing:.05em;
  color:var(--ink-2);font-weight:600;margin:0 0 .25rem}
.sep-partes__lista{list-style:none;margin:0 0 1rem;padding:0;
  display:grid;grid-template-columns:1fr;gap:.125rem}
.sep-parte{display:flex;align-items:baseline;justify-content:space-between;
  gap:.75rem;padding:.0625rem 0;min-width:0}
.sep-parte__txt{font-size: var(--bi-fs-compact);min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.sep-parte__q{font-size: var(--bi-fs-compact);color:var(--ink-2);flex:none}
.sep-parte--atual .sep-parte__txt{font-weight:600;color:var(--ink)}
.sep-parte--historico .sep-parte__txt,
.sep-parte--historico .sep-parte__q{color:var(--ink-3)}
.sep-hist__t{font-size: var(--bi-fs-micro);text-transform:uppercase;letter-spacing:.05em;
  color:var(--ink-2);font-weight:600;margin:0 0 .25rem}
/* A linha do tempo do pedido: data | evento | quantidade, um evento por linha,
   em ordem cronológica. O fio à esquerda liga os eventos — é o que diz "isto é
   uma sequência" sem escrever a palavra. O "hoje" fecha em acento. */
.sep-tempo{list-style:none;margin:0 0 1.25rem;padding:0}
.sep-tempo__ev{display:flex;align-items:baseline;gap:.625rem;
  padding:.375rem 0 .375rem .875rem;position:relative;
  border-left:2px solid var(--line)}
.sep-tempo__ev::before{content:"";position:absolute;left:-5px;top:.8em;
  width:8px;height:8px;border-radius:var(--r-full);
  background:var(--surf);border:2px solid var(--ink-3)}
.sep-tempo__ev[data-tipo="nota"]::before{background:var(--positive-text);
  border-color:var(--positive-text)}
.sep-tempo__ev[data-tipo="hoje"]{border-left-color:transparent}
.sep-tempo__ev[data-tipo="hoje"]::before{background:var(--acc);border-color:var(--acc)}
.sep-tempo__data{flex:none;width:5.25rem;font-size: var(--bi-fs-compact);color:var(--ink-3)}
.sep-tempo__meio{min-width:0;flex:1 1 auto;display:flex;flex-direction:column}
.sep-tempo__t{font-size: var(--bi-fs-compact);font-weight:600;color:var(--ink)}
.sep-tempo__ev[data-tipo="hoje"] .sep-tempo__t{color:var(--acc)}
.sep-tempo__d{font-size: var(--bi-fs-compact);color:var(--ink-2)}
.sep-tempo__q{flex:none;font-size: var(--bi-fs-compact);font-weight:600;color:var(--ink)}

/* Separação · a observação do pedido na capa, em balão.
   Ela é INSTRUÇÃO de quem vendeu para quem carrega ("ENTREGAR SÓ PELA MANHÃ",
   "PEDIDO REFERENTE A NF QUE FOI ESTORNADA"). Em fita de dt/dd lia como mais um
   campo; o balão devolve o destaque que ela tinha. */
/* UM PARÁGRAFO NÃO É UM CAMPO. Em `flex:1 1 22rem;max-width:34rem` ela entrava
   na fita como mais um item — 544px de largura por 189 de altura — e esticava a
   LINHA INTEIRA para 266px, deixando um vão embaixo de todos os pares curtos: a
   capa ia a 364px, 43% da superfície, para um cabeçalho. Com `flex-basis:100%`
   ela cai na própria linha, ocupa a largura toda e o mesmo texto cabe em duas
   linhas em vez de cinco. */
/* A observação ocupa a SOBRA da fita, não uma fileira própria. Ela nasceu com
   `max-width:34rem`: 544px num vão de 1.478, o que a empurrava para cinco linhas
   e esticava a fita inteira para 266px. Depois foi para `flex-basis:100%` — uma
   fileira só dela, três linhas, com o lado direito da fita de campos vazio. Sem
   teto de largura ela fica NA MESMA fileira dos campos, consome o espaço que
   sobrava à direita deles e a capa cabe na altura de um bloco só.
   `flex-start` no alinhamento porque a fita alinha por `baseline`, e um bloco de
   várias linhas ao lado de pares de uma linha empurrava todos para baixo.
   Entrelinha de leitura, não de aviso curto: o `line-height:1.6` de `.nota` é
   feito para UMA frase. Vai nesta regra, não na `.sep-obs` solta — aquela vem
   ANTES de `.nota` no arquivo e, com a mesma especificidade, perdia calada. */
/* A advertência ocupa a faixa que sobrava à DIREITA DO CLIENTE, na primeira
   linha da capa; a fita de campos desce para a segunda, inteira. Medido no
   20318 a 1713px: com o balão dentro da fita, a fita ficava larga demais para
   caber ao lado do nome, descia junto e a primeira linha ia vazia de ponta a
   ponta — capa de 211px. Com o balão como irmão, capa de 164px.
   Entrelinha de leitura, não de aviso curto: o `line-height:1.6` de `.nota` é
   feito para UMA frase. Vai nesta regra, não na `.sep-obs` solta — aquela vem
   ANTES de `.nota` no arquivo e, com a mesma especificidade, perdia calada. */
/* A ADVERTÊNCIA MANDA NA ALTURA. Ela leva 2/5 da largura e o texto dela decide
   quantas linhas a capa tem; os campos se acomodam nos 3/5 restantes, em
   quantas fileiras couberem. Tentei antes fazê-la absorver a sobra de uma
   fileira (`grid-column:auto/-1`, depois `span 8`): com um lado auto a grade dá
   span 1 e o balão virava uma coluna magra de 40 linhas na ponta (capa de
   712px); com span fixo, a capa oscilava entre 205 e 270px conforme a janela,
   porque o span não sabe quantas colunas sobraram. */
.wsurface__cap-obs{min-width:0}
.wsurface__cap-obs:empty{display:none}
/* A ADVERTÊNCIA ROLA DENTRO DA ALTURA QUE A CAPA TEM. Quem manda na altura são
   as duas fileiras de campos; o parágrafo se encaixa nelas e o excedente vem
   pelo arrastar. `position:absolute` é o que tira a altura dele da conta da
   grade — com `max-height` em rem o número seria chute, e sobraria faixa vazia
   quando o texto fosse curto ou corte quando a capa fosse alta. O piso existe
   para o balão não virar uma tarja de duas linhas num pedido de poucos campos. */
/* NA MESMA ALTURA DA CAPA: quem manda são os campos — o balão acompanha a
   fileira deles, nem um pixel a mais, e o texto excedente rola por dentro. O
   piso de 5.5rem que existia aqui era o que deixava o balão MAIS ALTO que os
   fatos ao lado, com a borda dele caindo abaixo da última fileira. */
.wsurface__cap-obs{position:relative}
.wsurface__cap-obs .sep-obs{position:absolute;inset:0;overflow:auto}
.wsurface__cap-obs:empty{display:none}
.wsurface__cap-obs .sep-obs{margin:0;line-height:1.45}
.wsurface__cap-campos .sep-obs p{margin-bottom:.125rem}
.wsurface__cap-campo.sep-entrega dd{display:flex;align-items:center;gap:.25rem;flex-wrap:wrap}
/* A data cabe numa célula da capa. Ela nasceu em corpo de número (1,25rem) para
   sair do tamanho de filtro; numa grade de doze onde cada campo vale uma célula,
   esse corpo obrigava a coluna a ser o dobro das vizinhas. Corpo de valor, como
   os outros campos, com o peso mantendo o destaque. */
.wsurface__cap .sep-entrega__data{font-size:.875rem;max-width:100%;min-width:0;
  padding-inline:.25rem}
.wsurface__cap .sep-entrega .btn{padding-inline:.375rem}
.wsurface__cap .sep-entrega dd{gap:.25rem .375rem}

/* Separação · a legenda da coluna "Não separado".
   Caixa alta com tracking: é rótulo do número acima, não frase — a mesma
   gramática dos rótulos de medida do topo. Sem isso ela competia em peso com o
   valor que deveria explicar. */
.sep-legenda{font-size: var(--bi-fs-micro);text-transform:uppercase;letter-spacing:.05em;
  color:var(--ink-2);line-height:1.3}

/* ═══════════════════════════════════════════════════════════════════════════
   DISTRIBUIÇÃO DO FATURAMENTO  (/distribuicao-faturamento/)
   Barra empilhada por cliente + matriz cliente × mês.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Altura fixa e generosa: é ela que compra faixa visível para os clientes do
   meio do ranking. Medido — com 20 nomeados numa área de ~430px a menor faixa
   fica em 1,79px; abaixo disso deixa de ser clicável. */

/* A legenda é o que transforma "um tom de azul" em "o cliente X": com 20 blocos
   a rampa de um tom só não distingue vizinhos, e a identidade passa a vir daqui,
   do hover e do clique. Grid de colunas fluidas para caber 20 nomes sem virar
   parede de texto. */
.df-legenda{
  display:grid; grid-template-columns:repeat(auto-fill, minmax(250px, 1fr));
  gap:2px 14px; margin-top:.75rem; padding-top:.75rem;
  border-top:1px solid var(--line); max-height:190px; overflow-y:auto;
}
.df-legenda__item{
  display:flex; align-items:center; gap:.45rem; width:100%; text-align:left;
  font-size: var(--bi-fs-compact); color:var(--ink-2); background:none; border:0;
  padding:.2rem .25rem; border-radius:var(--r-sm); cursor:pointer;
}
.df-legenda__item:hover:not(:disabled){ background:var(--surf-2); color:var(--ink); }
.df-legenda__item:disabled{ cursor:default; }
.df-legenda__item:focus-visible{ outline:2px solid var(--chart-azul); outline-offset:1px; }
.df-legenda__item[aria-pressed="true"]{
  background:color-mix(in srgb, var(--chart-azul) 12%, var(--surf));
  color:var(--ink); font-weight:600;
}
.df-legenda__cor{ flex:none; width:13px; height:11px; border-radius:2px; }
.df-legenda__cor--outros{
  background:color-mix(in srgb, var(--chart-azul) 11%, var(--surf));
  border:1px solid color-mix(in srgb, var(--chart-azul) 28%, var(--surf));
}
.df-legenda__nome{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.df-legenda__pct{ flex:none; margin-left:auto; color:var(--ink-3); font-variant-numeric:tabular-nums; }

/* Drill-down do mês: a pizza e sua legenda, e nada mais. O ranking completo já
   está na matriz da página; repeti-lo aqui era a mesma tabela duas vezes. */
.df-drill{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.15fr); gap:22px;
  align-items:center; }
@media (max-width:720px){ .df-drill{ grid-template-columns:minmax(0,1fr); } }
.df-drill__pizza{ position:relative; height:300px; }
.df-drill__legenda{ list-style:none; margin:0; padding:0; display:grid; gap:1px; }
.df-drill__legenda li{ display:grid; grid-template-columns:auto minmax(0,1fr) auto auto;
  align-items:center; gap:.5rem; padding:.3rem .35rem; border-radius:var(--r-sm);
  font-size: var(--bi-fs-compact); }
.df-drill__legenda li:nth-child(odd){ background:var(--surf-2); }
.df-drill__cor{ width:11px; height:11px; border-radius:2px; flex:none; }
.df-drill__nome{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--ink-2); }
/* Valor e % nunca quebram: "R$ 1,858M" partido no meio deixa de ser número. */
.df-drill__valor{ white-space:nowrap; font-weight:600; }
.df-drill__pct{ white-space:nowrap; color:var(--ink-3); min-width:3.2rem; text-align:right; }

/* Mês clicável: o cabeçalho é a porta do drill, e precisa parecer uma. */
.df-mes{ cursor:pointer; }
.df-mes:hover{ color:var(--chart-azul); text-decoration:underline; }
.df-mes:focus-visible{ outline:2px solid var(--chart-azul); outline-offset:-2px; }

/* Cabeçalho de família marcável (colfilterMulti `grupoMarcavel`): pesa mais que o
   item e recua os filhos, para a hierarquia família ▸ produto ser lida de relance. */
.colfilter-multi__grupo{ font-weight:600; text-transform:uppercase; font-size: var(--bi-fs-micro);
  letter-spacing:.04em; margin-top:.35rem; }
.colfilter-multi__filho{ padding-left:1.5rem; }

/* Coluna de identificação congelada enquanto os meses rolam na horizontal.
   Sem isso, rolar até dez/26 deixa a linha órfã: números sem dono. */
.tbl-scroll--freeze-col .tbl-freeze{
  position:sticky; left:0; z-index:3; background:var(--surf);
  border-right:1px solid var(--line);
  min-width:230px; max-width:230px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.tbl-scroll--freeze-col thead .tbl-freeze,
.tbl-scroll--freeze-col tfoot .tbl-freeze{ z-index:4; background:var(--surf-2); }
.tbl-scroll--freeze-col tbody tr:hover .tbl-freeze{ background:var(--surf-2); }
.tbl-scroll--freeze-col tbody tr.table-active .tbl-freeze{ font-weight:600; }
.tbl-scroll--freeze-col tfoot td{ position:sticky; bottom:0; background:var(--surf-2); }
.tbl-scroll--freeze-col tbody tr{ cursor:pointer; }
.tbl-scroll--freeze-col tbody tr:focus-visible{ outline:2px solid var(--chart-azul); outline-offset:-2px; }

/* ============================================================
   CRM — DOCUMENTO DA PROPOSTA (impressão / PDF WeasyPrint)
   Réplica do layout da proposta comercial do Ploomes (gabarito:
   proposta 16.900-0, docs/planos/crm.md). Renderizado por
   bi/templates/bi/crm_proposta_pdf.html; mesmo HTML no preview
   e no PDF (weasyprint.CSS deste arquivo). Prefixo .prop-.
   ============================================================ */
@page {
  size: A4;
  margin: 30mm 12mm 40mm 12mm;
  @top-left { content: element(prop-cab); }
  @bottom-center { content: element(prop-rodape); }
}
.prop-doc{ font-family:'DejaVu Sans', Arial, sans-serif; font-size:8.5pt;
  color:#212529; line-height:1.32; }
.prop-cab{ position:running(prop-cab); display:flex;
  justify-content:space-between; align-items:flex-end; width:186mm; }
/* A logo do documento original ocupa quase um terço da faixa; 40mm a
   deixavam do tamanho de um selo. A arte tem 4626px de largura, então
   ampliar não perde nitidez. */
.prop-logo-img{ width:58mm; }
.prop-emp{ font-size:8pt; text-align:right; line-height:1.5; }
.prop-emp b{ font-size:8.5pt; }
.prop-faixa{ display:flex; justify-content:space-between; background:#4a4a4c;
  color:#fff; font-weight:700; font-size:9.5pt; padding:1.5mm 3mm; margin-bottom:2mm; }
/* Explicação do painel de condições quando ele abre sozinho. Fundo do acento
   em vez de cinza: cinza é a cor de quem não quer ser lido, e esta frase
   existe justamente para ser lida. */
[data-pagina="crm-deal"] .crm-aviso-suave{
  background: var(--crm-acento-fundo); border: 1px solid #d3e2d9;
  border-radius: 8px; padding: .7rem .9rem; margin: 0 0 1rem;
  font-size: var(--bi-fs-compact); color: var(--crm-tinta-2); line-height: 1.5; }

/* ---------------------------------------------------------------------------
   Vocabulário do CRM que o Bootstrap não cobre. Existe porque estilo inline
   NÃO se usa aqui (regra do dono) e porque inline vence a folha: a regra que
   eu escrevi para o bloco de embalagem no telefone foi ignorada por um
   `justify-content` inline que estava no elemento. O que o Bootstrap cobre
   exatamente (mt-1, d-block, ms-auto, align-items-end…) usa o Bootstrap; o
   que não cobre está aqui, com nome.
   --------------------------------------------------------------------------- */
/* Larguras de campo dos formulários de cadastro. São medidas do CONTEÚDO
   (UF tem 2 letras, CEP tem 8 dígitos), por isso nome do campo e não número. */
[data-pagina^="crm"] .crm-campo-uf { flex: 0 0 4rem; }
[data-pagina^="crm"] .crm-campo-numero { flex: 0 0 5rem; }
[data-pagina^="crm"] .crm-campo-cep { flex: 0 0 7.5rem; }
[data-pagina^="crm"] .crm-campo-9 { flex: 0 1 9rem; }
[data-pagina^="crm"] .crm-campo-10 { flex: 0 0 10rem; }
[data-pagina^="crm"] .crm-campo-11 { flex: 0 1 11rem; }
/* Lupa escondida (cliente pessoa física, que não tem consulta pública) deixa
   o campo como último da linha — e o Bootstrap só arredonda a ponta direita do
   que é `:last-child`. Com `display:none` o botão continua sendo o último
   filho, então o canto ficava quadrado, encostado em nada. */
[data-pagina^="crm"] .input-group > .form-control:has(+ .crm-oculto) {
  border-top-right-radius: var(--bs-border-radius);
  border-bottom-right-radius: var(--bs-border-radius); }
[data-pagina^="crm"] .crm-campo-12 { flex: 0 1 12rem; }
[data-pagina^="crm"] .crm-campo-13 { flex: 0 1 13rem; }
[data-pagina^="crm"] .crm-largura-16 { max-width: 16rem; }
[data-pagina^="crm"] .crm-largura-20 { max-width: 20rem; }
/* Pílula que é botão (o chip da embalagem reabre o bloco): mesma aparência de
   pílula, comportamento de botão. */
.crm-pilula-botao { border: 0; cursor: pointer; }
/* Botão dentro de linha de tabela ou de cabeçalho de painel: aperta o padding
   sem virar outro componente. */
.crm-btn-compacto { padding: .25rem .5rem; }
/* Total do rodapé — o número que se lê de longe. */
[data-pagina="crm-deal"] .crm-numero-grande { font-size: 1.35rem; font-weight: 700; }
[data-pagina^="crm"] .crm-separador { margin: 1.5rem 0 1rem; }
[data-pagina^="crm"] .crm-recuo { margin: .25rem 0 0 1rem; }
[data-pagina^="crm"] .crm-linha-lista { padding: .5rem 0;
  border-top: 1px solid var(--crm-borda); }
.min-w-0 { min-width: 0; }
/* Largura dos painéis laterais, por peso do conteúdo. */
.crm-oc--estreita { --bs-offcanvas-width: 22rem; }
.crm-oc--media { --bs-offcanvas-width: 26rem; }
.crm-oc--larga { --bs-offcanvas-width: 30rem; }
/* Campo obrigatório. O asterisco é do RÓTULO, não do campo: quem lê a tela
   procura na etiqueta, e leitor de tela anuncia o `aria-required` do input
   sem tropeçar num caractere solto. A régua é a do SERVIDOR — só recebe
   estrela o que ele de fato recusa vazio. */
.crm-obrigatorio::after { content: " *"; color: var(--crm-erro, #b3261e);
  font-weight: 700; }

/* Revisar mostra o documento inteiro: largura de papel, não de formulário. */
.crm-oc--documento { --bs-offcanvas-width: min(52rem, 96vw); }
[data-pagina="crm-deal"] .crm-oc-documento { padding: 0; display: flex; }
[data-pagina="crm-deal"] .crm-documento-previa { flex: 1; width: 100%;
  border: 0; background: #e9ecef; }
/* Espera do documento: ocupa o lugar do papel enquanto ele é gerado. Fundo
   igual ao do quadro para a troca não piscar de cor. */
[data-pagina="crm-deal"] .crm-documento-espera { flex: 1; display: flex;
  flex-direction: column; align-items: center; justify-content: center;
  gap: .75rem; background: #e9ecef; color: var(--crm-tinta-2, #6c757d);
  font-size: .875rem; }
[data-pagina="crm-deal"] .crm-documento-espera.crm-oculto { display: none; }

/* Roteiro da proposta: os passos, acionáveis. Diferente do trilho de etapas
   (indicador, não se clica), aqui cada passo LEVA ao lugar onde se resolve o
   que falta. O que está pronto fica discreto; o passo da vez é o único com
   peso — a tela responde "e agora?" sem ninguém perguntar.

   O respiro é do PRÓPRIO bloco (padding), não margem, e só EM CIMA: embaixo
   quem separa é o padding do corpo, que já vale 1,25rem. Somar os dois dava
   1px acima contra 36px abaixo — o roteiro nascia colado no trilho de etapas
   e solto do trabalho. */
[data-pagina="crm-deal"] .crm-roteiro{ display: flex; flex-wrap: wrap;
  gap: .4rem; margin: 0; padding-block: 1.25rem 0; flex: 0 0 auto; }
[data-pagina="crm-deal"] .crm-roteiro__passo{ display: flex; align-items: center;
  gap: .5rem; flex: 1 1 12rem; text-align: left; cursor: pointer;
  background: var(--crm-superficie); border: 1px solid var(--crm-borda);
  border-radius: 8px; padding: .5rem .7rem; color: var(--crm-tinta-2);
  font-size: .8125rem; transition: border-color .15s ease, background .15s ease; }
[data-pagina="crm-deal"] .crm-roteiro__passo:hover{ border-color: var(--crm-acento); }
[data-pagina="crm-deal"] .crm-roteiro__n{ display: inline-flex;
  align-items: center; justify-content: center; flex: 0 0 1.4rem; height: 1.4rem;
  border-radius: 50%; background: #eaeeec; color: var(--crm-tinta-2);
  font-size: .75rem; font-weight: 700; }
[data-pagina="crm-deal"] .crm-roteiro__rot{ display: block; font-weight: 600;
  color: var(--crm-tinta); }
[data-pagina="crm-deal"] .crm-roteiro__falta{ display: block; font-size: .75rem;
  color: var(--crm-tinta-2); }
[data-pagina="crm-deal"] .crm-roteiro__passo--ok .crm-roteiro__n{
  background: var(--crm-acento); color: #fff; }
[data-pagina="crm-deal"] .crm-roteiro__passo--agora{
  border-color: var(--crm-acento); background: var(--crm-acento-fundo); }
[data-pagina="crm-deal"] .crm-roteiro__passo--agora .crm-roteiro__n{
  background: var(--crm-acento); color: #fff; }

/* Título do negócio: a primeira coisa depois da faixa preta, centralizado.
   É a linha que diz de QUE cotação se trata, e o cliente costuma ter mais de
   uma na mesa. Um ponto acima do corpo — chama sem gritar. */
.prop-obra{ font-size:9.5pt; font-weight:700; text-align:center;
  margin:0 0 2.5mm; }
.prop-vend{ font-size:8pt; margin-bottom:2.5mm; line-height:1.55; }
/* Quatro linhas empilhadas, como no documento real — em fita elas viravam
   uma linha só e o nome do empreendimento colava no telefone. */
.prop-vend > div{ display:block; }
.prop-tabela{ width:100%; border-collapse:collapse; font-size:8.5pt;
  /* fixed: sem isto as larguras abaixo são só sugestão e o navegador dá à
     coluna Produto o que sobra dos cabeçalhos longos ("Disponibilidade"),
     quebrando a descrição em três linhas. */
  table-layout:fixed; }
.prop-tabela th{ background:#e3e3e5; text-align:center; font-size:7.2pt;
  /* Respiro lateral curto: sao ate nove colunas em 186mm, e cada milimetro
     aqui decide se "Conteudo" cabe numa linha ou parte no meio. */
  font-weight:700; padding:2mm .8mm; border:.5pt solid #b9b9be;
  /* Cabeçalho de PALAVRA ÚNICA numa coluna estreita não quebra sozinho: ele
     transborda por cima da coluna vizinha, e foi assim que "Embalagem" saiu
     colado em "Conteúdo" na proposta da Sandra. Com isto ele parte. */
  /* `break-word` e NAO `anywhere`: o segundo parte dentro da palavra mesmo
     quando ela caberia inteira na linha seguinte, e escrevia "Valor por
     bobi-na". Este so parte quando a palavra sozinha nao cabe. */
  overflow-wrap:break-word; }
/* Larguras por CLASSE (não por nth-child: a coluna de previsão é condicional
   e os índices dançariam). Sem elas o código rouba espaço da descrição e
   "FOUR CORDOALHA CP 190 RB 9,5MM" quebra em duas linhas.
   São 186mm úteis (A4 menos 12mm de margem de cada lado); o que sobra depois
   destas nove vai para Produto, a única que precisa crescer. Cada número aqui
   foi medido contra um valor real, não estimado — em 24mm "R$ 125.000,00"
   quebrava entre o "R$" e o valor, e em 18mm a palavra "Quantidade" partia no
   meio ("Quantidad / e"). */
   Os dois totais (s/ e c/ IPI) cabem porque o "R$" saiu das células e foi
   para o cabeçalho: cada coluna de dinheiro devolveu ~5mm, e são quatro. */
.prop-tabela .c-item{ width:7mm; }
.prop-tabela .c-cod{ width:21mm; }
.prop-tabela .c-disp{ width:19mm; }
.prop-tabela .c-emb{ width:16mm; }
.prop-tabela .c-cont{ width:17mm; }
.prop-tabela .c-qtd{ width:19mm; }
.prop-tabela .c-preco{ width:14mm; }
.prop-tabela .c-vol{ width:17mm; }
.prop-tabela .c-total{ width:18mm; }
/* Com a coluna de previsão são ONZE colunas em 186mm, e aí não existe
   milímetro para tirar de vizinho: apertar a de dinheiro quebra o valor,
   apertar a do produto empilha a descrição em oito linhas. A tabela inteira
   encolhe um ponto — o papel continua legível e todas as colunas respiram de
   novo. Antes eu trocava uma quebra por outra a cada ajuste. */
.prop-tabela--densa{ font-size:7.8pt; }
.prop-tabela--densa th{ font-size:6.6pt; padding:1.6mm .6mm; }
.prop-tabela--densa td{ padding:1.2mm 1.4mm; }
/* Medido no papel, não estimado: em 14mm o código de 8 dígitos partia em duas
   linhas ("300300 / 02") e em 12mm o cabeçalho "Volumes" virava "Volume / s".
   O que sobra depois destas dez vai para Produto, a única que cresce. */
.prop-tabela--densa .c-item{ width:6mm; }
.prop-tabela--densa .c-cod{ width:19mm; }
.prop-tabela--densa .c-disp{ width:16mm; }
.prop-tabela--densa .c-emb{ width:14mm; }
.prop-tabela--densa .c-cont{ width:15mm; }
.prop-tabela--densa .c-qtd{ width:17mm; }
.prop-tabela--densa .c-preco{ width:13mm; }
.prop-tabela--densa .c-vol{ width:15mm; }
.prop-tabela--densa .c-total{ width:16mm; }
/* Célula de número e de código respiram menos nas laterais que a de texto —
   é onde cada milímetro decide se o valor cabe numa linha só. */
.prop-tabela td.num, .prop-tabela td.ctr{
  padding-left:1.2mm; padding-right:1.2mm; }
/* Quebra SÓ na disponibilidade, que é texto livre de até 40 caracteres
   ("logo após o carnaval") e transbordava por cima da descrição do produto.
   Nas outras células centradas o mesmo `break-word` partia o código do
   produto ("300300 / 02") e a data ("20/09/202 / 6"): ali o conteúdo tem
   tamanho conhecido e a coluna é dimensionada para ele. */
.prop-tabela td.c-disp{ overflow-wrap:break-word; }
/* O código é uma palavra só, sem espaço onde quebrar: com 14 caracteres ele
   transbordava POR CIMA da coluna vizinha (na proposta 10 ele invadia a linha
   da previsão). `anywhere` e não `break-word` porque aqui não existe "próxima
   linha melhor" — ou parte no meio, ou vaza. */
.prop-tabela td.c-cod{ overflow-wrap:anywhere; }
/* Grade fechada: linha entre TODOS os campos, não só entre as linhas. Com
   sete colunas de número, a borda vertical é o que separa "3.000" de
   "15.000" sem o leitor precisar mirar o cabeçalho. */
.prop-tabela td{ padding:1.4mm 2mm; border:.5pt solid #cfcfd2;
  vertical-align:top; }
/* Numero NAO leva nowrap: com 4.200.000 PC ou R$ 1.260.000,00 o nowrap nao
   aperta nada, ele TRANSBORDA por cima da coluna vizinha. Sem ele a celula
   quebra no unico espaco que existe ("R$" numa linha, o valor na outra), que
   e feio uma vez a cada mil propostas e legivel sempre. */
.prop-tabela .num{ text-align:right; font-variant-numeric:tabular-nums; }
.prop-tabela .ctr{ text-align:center; }
.prop-totais{ width:100%; border-collapse:collapse; font-size:8.5pt;
  margin-bottom:3mm; }
.prop-totais td{ padding:1.2mm 2mm; border:.5pt solid #d8d8dc; }
.prop-totais tr:nth-child(odd) td{ background:#ececee; }
.prop-totais .rot{ text-align:right; font-weight:700; }
.prop-totais .num{ text-align:right; font-variant-numeric:tabular-nums;
  width:30mm; }
.prop-sec{ font-size:8.5pt; font-weight:700; border-bottom:1.5pt solid #9b1c2e;
  padding-bottom:.8mm; margin:2.5mm 0 1.5mm; }
.prop-grade{ width:100%; border-collapse:collapse; font-size:8.5pt; }
/* A ficha de faturamento ganha só a linha horizontal: fechar a grade aqui
   transformaria oito pares rótulo/valor num formulário de imposto. */
.prop-grade td{ padding:1.1mm 2mm; vertical-align:top;
  border-bottom:.5pt solid #e4e4e8; }
.prop-grade .rot{ font-weight:700; white-space:nowrap; width:34mm; }
/* Observação escrita PELO VENDEDOR: fundo amarelo, como quem passa marca-texto
   no papel. É a única linha do documento que não é padrão — nasce da conversa
   daquele negócio ("consulte nossas condições especiais para…") — e em itálico
   preto ela se perdia entre a EC 87 e as condições gerais, que o cliente já
   nem lê. O amarelo é o que faz o olho parar ali. */
.prop-obs-destaque{ font-style:italic; font-weight:700; font-size:8.5pt;
  margin:1mm 0; background:#fff3a3; padding:1.5mm 2mm;
  white-space:pre-wrap; }
.prop-obs{ font-size:6.8pt; color:#343a40; line-height:1.35;
  white-space:pre-wrap; }
.prop-cond{ font-size:7.5pt; line-height:1.4; }
/* O rodapé sangra 6mm de cada lado da caixa de texto: são sete fotos de
   produto com legenda, e em 186mm as legendas ficavam ilegíveis. A arte tem
   2048px de largura — aguenta a ampliação. */
.prop-rodape{ position:running(prop-rodape); width:198mm; margin-left:-6mm; }
.prop-rodape img{ width:198mm; height:auto; }
/* Marca d'água da revisão superada. `position:fixed` no WeasyPrint repete em
   TODAS as páginas — é o mecanismo de marca d'água, não um bug. Fica atrás do
   conteúdo (z-index negativo) para não atrapalhar a leitura dos números. */
.prop-marca{ position:fixed; top:45%; left:0; right:0; z-index:-1;
  text-align:center; transform:rotate(-24deg); pointer-events:none;
  color:rgba(155,28,46,.16); }
.prop-marca__tit{ display:block; font-size:30pt; font-weight:700;
  letter-spacing:.06em; line-height:1; white-space:nowrap; }
.prop-marca__sub{ display:block; font-size:13pt; font-weight:700;
  letter-spacing:.12em; margin-top:3mm; }

/* ============================================================
   OCUPADO — sinal global de ação em andamento (biUtils.ocupado)
   Barra fina no topo enquanto uma escrita está no ar. Diferente do
   esqueleto de carregamento: o conteúdo continua à vista, só não
   aceita clique — assim ninguém dispara a mesma ação duas vezes.
   ============================================================ */
.bi-ocupado {
  position: fixed; top: 0; left: 0; right: 0; height: 3px;
  z-index: 2000; pointer-events: none;
  background: linear-gradient(90deg,
    transparent 0%, var(--crm-acento, #1d4d38) 45%,
    var(--crm-acento, #1d4d38) 55%, transparent 100%);
  background-size: 240% 100%;
  animation: bi-ocupado-desliza 1.1s ease-in-out infinite;
}
@keyframes bi-ocupado-desliza {
  from { background-position: 120% 0; }
  to   { background-position: -20% 0; }
}
/* enquanto trabalha, a página não aceita novo clique (o cursor conta por quê) */
body.bi-ocupado-ativo { cursor: progress; }
body.bi-ocupado-ativo main, body.bi-ocupado-ativo .offcanvas {
  pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
  .bi-ocupado { animation: none; background: var(--crm-acento, #1d4d38); }
}

/* ============================================================
   CRM — DO ZERO (v3): A RAMPA DO FUNIL
   Telas /crm/ e /crm/deal/. Sistema próprio, sem chrome nem
   utilitários Bootstrap (a mecânica do offcanvas fica; o vestido é
   daqui). Tema claro. Assinatura: UM verde em QUATRO profundidades,
   uma por etapa — a cor codifica o avanço do deal (Prospecção clara
   → Fechamento profundo). Cabeçalho de estação é bloco sólido no
   tom da etapa; o stepper do deal usa a mesma rampa; dinheiro e CTA
   ficam no verde profundo. Tudo escopado por
   [data-pagina="crm"|"crm-deal"].
   ============================================================ */
[data-pagina="crm"], [data-pagina="crm-deal"] {
  --crm-fundo: #f4f6f5;
  --crm-superficie: #ffffff;
  --crm-tinta: #171a18;
  --crm-tinta-2: #4e544f;
  --crm-tinta-3: #6d746f;
  --crm-borda: #e2e6e3;
  --crm-borda-forte: #cfd5d1;
  /* rampa do funil: um verde, quatro profundidades (todas ≥4.5:1 com branco) */
  --crm-tom-1: #4f7a67;
  --crm-tom-2: #3f6b57;
  --crm-tom-3: #2e5c47;
  --crm-tom-4: #1d4d38;
  --crm-acento: var(--crm-tom-4);
  --crm-acento-fundo: #e9f2ec;
  --crm-ok: #157f3c;  --crm-ok-fundo: #ecfdf3;
  --crm-avi: #b45309; --crm-avi-fundo: #fffaeb;
  --crm-mal: #b42318; --crm-mal-fundo: #fef3f2;
  /* Contêiner: nem tudo melhora esticando. Acima disto a linha de comando
     abria 1.400px de vão entre a busca e as medidas, e a tabela de itens
     dava 665px só para a descrição do produto. */
  --crm-largura-max: 110rem;
  /* Teto da coluna do funil. 272px é o piso do Trello (menor largura que
     ainda cabe título + valor + dois metadados) e ~352px é onde o card ainda
     lê como card. Nenhum kanban do mercado estica card além disso. */
  --crm-coluna-max: 22rem;
  --crm-raio: 10px;
  --crm-sombra: 0 1px 2px rgba(23, 26, 24, .05);
  --crm-sombra-2: 0 6px 20px rgba(23, 26, 24, .09);
  background: var(--crm-fundo);
  color: var(--crm-tinta);
  /* A altura vem do shell (`content--altura-cheia`): a tela ocupa a janela e
     quem rola é a coluna / o corpo do negócio, nunca a página. */
  min-height: 0;
}
/* cada raia do funil e cada etapa do stepper carregam o próprio tom */
[data-pagina="crm"] .crm-raia { --tom: var(--crm-tom-4); }
[data-pagina="crm"] .crm-raia[data-raia="prospeccao"] { --tom: var(--crm-tom-1); }
[data-pagina="crm"] .crm-raia[data-raia="negociacao"] { --tom: var(--crm-tom-2); }
[data-pagina="crm"] .crm-raia[data-raia="reserva"]    { --tom: var(--crm-tom-3); }
[data-pagina="crm"] .crm-raia[data-raia="finalizado"] { --tom: var(--crm-tom-4); }
[data-pagina="crm-deal"] .crm-etapa:nth-child(1) { --tom: var(--crm-tom-1); }
[data-pagina="crm-deal"] .crm-etapa:nth-child(2) { --tom: var(--crm-tom-2); }
[data-pagina="crm-deal"] .crm-etapa:nth-child(3) { --tom: var(--crm-tom-3); }
[data-pagina="crm-deal"] .crm-etapa:nth-child(4) { --tom: var(--crm-tom-4); }

/* --- primitivas de layout (o que os utilitários do Bootstrap faziam) --- */
[data-pagina="crm"] .crm-linha, [data-pagina="crm-deal"] .crm-linha {
  display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }
[data-pagina="crm"] .crm-cresce, [data-pagina="crm-deal"] .crm-cresce { flex: 1 1 auto; }
[data-pagina="crm"] .crm-oculto, [data-pagina="crm-deal"] .crm-oculto { display: none !important; }

/* --- tipografia --- */
.crm-rotulo { font-size: var(--bi-fs-micro); font-weight: 400; color: var(--crm-tinta-3);
  letter-spacing: .01em; }
.crm-numero { font-variant-numeric: tabular-nums lining-nums;
  font-weight: 600; letter-spacing: -.015em; }
/* TÍTULO DE SEÇÃO — caixa alta. Toda a interface já rotula em caixa alta
   (etapa, coluna de tabela, campo da capa); o título do painel era o único
   em caixa mista, o que fazia ele parecer conteúdo em vez de estrutura.
   Caixa alta pede tracking positivo e peso maior para não fechar. */
.crm-titulo { font-size: var(--bi-fs-compact); font-weight: 700; text-transform: uppercase;
  letter-spacing: .08em; color: var(--crm-tinta); }
/* PERGUNTA — a faixa de confirmação faz uma pergunta em frase inteira, e
   frase inteira em caixa alta lê-se pior (e grita). Fica em caixa mista. */
.crm-pergunta { font-size: 1.02rem; font-weight: 600; letter-spacing: -.01em;
  color: var(--crm-tinta); }
.crm-etiqueta { font-size: var(--bi-fs-micro); font-weight: 600; color: var(--crm-tinta-3);
  text-transform: uppercase; letter-spacing: .1em; }
/* Etiqueta usada como rótulo de campo é sempre bloco com respiro embaixo —
   isso estava repetido em 14 `style=` inline nos dois formulários. */
[data-pagina="crm"] label.crm-etiqueta,
[data-pagina="crm-deal"] label.crm-etiqueta { display: block; margin-bottom: .3rem; }
.crm-forte { font-weight: 600; letter-spacing: -.01em; }

/* --- superfícies --- */
/* UMA superfície de card no CRM. `.crm-painel` é o mesmo cartão com recuo
   interno — eram duas declarações idênticas que já divergiam por descuido. */
.crm-cartao, .crm-painel { background: var(--crm-superficie);
  border: 1px solid var(--crm-borda); border-radius: var(--crm-raio);
  box-shadow: var(--crm-sombra); }
.crm-painel { padding: 1rem 1.15rem; }

/* --- selos de estado (cantos 6px: selo, não cápsula) --- */
.crm-pilula { display: inline-flex; align-items: center; gap: .3rem;
  padding: .1rem .45rem; border-radius: 6px; font-size: var(--bi-fs-micro);
  font-weight: 500; white-space: nowrap; }
.crm-pilula--ok     { background: var(--crm-ok-fundo);     color: var(--crm-ok); }
.crm-pilula--aviso  { background: var(--crm-avi-fundo);    color: var(--crm-avi); }
.crm-pilula--erro   { background: var(--crm-mal-fundo);    color: var(--crm-mal); }
.crm-pilula--acento { background: var(--crm-acento-fundo); color: var(--crm-acento); }
.crm-pilula--neutra { background: #eaeeec; color: var(--crm-tinta-2); }
/* A borda entra PARA DENTRO: sem descontar o 1px, a única pílula com traço
   ficava 2px mais alta que as vizinhas e o alinhamento da linha dançava. */
.crm-pilula--tracejada { background: transparent;
  border: 1px dashed var(--crm-borda-forte); color: var(--crm-tinta-2);
  padding: calc(.1rem - 1px) calc(.45rem - 1px); }

/* --- controles --- */
[data-pagina="crm"] .form-control, [data-pagina="crm"] .form-select,
[data-pagina="crm-deal"] .form-control, [data-pagina="crm-deal"] .form-select {
  background-color: var(--crm-superficie); border: 1px solid var(--crm-borda);
  border-radius: 8px; color: var(--crm-tinta); font-size: .9rem;
  transition: border-color .15s ease, box-shadow .15s ease; }
[data-pagina="crm"] .form-control::placeholder,
[data-pagina="crm-deal"] .form-control::placeholder { color: var(--crm-tinta-3); }
[data-pagina="crm"] .form-control:focus, [data-pagina="crm"] .form-select:focus,
[data-pagina="crm-deal"] .form-control:focus, [data-pagina="crm-deal"] .form-select:focus {
  border-color: var(--crm-tinta); box-shadow: 0 0 0 3px rgba(26, 26, 30, .08); }
[data-pagina="crm"] .form-select, [data-pagina="crm-deal"] .form-select {
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%2374747d' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round' d='M2.5 4.5 6 8l3.5-3.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right .7rem center;
  background-size: 12px; }
[data-pagina="crm"] .form-check-input:checked,
[data-pagina="crm-deal"] .form-check-input:checked {
  background-color: var(--crm-tinta); border-color: var(--crm-tinta); }
[data-pagina="crm"] .form-check-input:focus,
[data-pagina="crm-deal"] .form-check-input:focus {
  border-color: var(--crm-tinta); box-shadow: 0 0 0 3px rgba(26, 26, 30, .08); }
[data-pagina="crm"] .form-label, [data-pagina="crm-deal"] .form-label {
  font-size: var(--bi-fs-compact); font-weight: 500; margin-bottom: .3rem; }
[data-pagina="crm"] .form-text, [data-pagina="crm-deal"] .form-text {
  font-size: var(--bi-fs-compact); color: var(--crm-tinta-3); }

/* busca com lupa dentro do campo */
[data-pagina="crm"] .crm-busca { position: relative; }
[data-pagina="crm"] .crm-busca > i { position: absolute; left: .8rem; top: 50%;
  transform: translateY(-50%); color: var(--crm-tinta-3); font-size: var(--bi-fs-compact);
  pointer-events: none; }
[data-pagina="crm"] .crm-busca > .form-control { padding-left: 2.1rem; }

/* --- botões --- */
/* text-decoration explícito: "Ligar" é um <a href="tel:"> com cara de botão,
   e sem isto herdava o sublinhado de link. */
.crm-btn { display: inline-flex; align-items: center; justify-content: center;
  gap: .4rem; background: var(--crm-acento); color: #fff;
  border: 1px solid var(--crm-acento); border-radius: 8px;
  padding: .3rem .7rem; font-size: var(--bi-fs-compact); font-weight: 500; text-decoration: none;
  transition: opacity .15s ease; cursor: pointer; }
.crm-btn:hover { opacity: .84; color: #fff; text-decoration: none; }
.crm-btn:focus-visible { outline: 2px solid var(--crm-acento); outline-offset: 2px; }
.crm-btn:disabled { opacity: .45; cursor: default; }
/* Ação secundária na COR DA MARCA. Era texto cinza com borda cinza-clara —
   a mesma receita de um botão desativado —, e os vendedores relataram não
   enxergar que era clicável. Verde no texto e na borda põe na mesma família
   do primário sem acrescentar mais um bloco sólido à tela; "Cancelar" e
   companhia foram para o `.crm-btn-3`, que é o peso que um cancelar merece. */
.crm-btn-2 { display: inline-flex; align-items: center; justify-content: center;
  gap: .4rem; background: var(--crm-superficie); color: var(--crm-acento);
  border: 1px solid var(--crm-acento); border-radius: 8px;
  padding: .3rem .7rem; font-size: var(--bi-fs-compact); font-weight: 600; text-decoration: none;
  transition: background .15s ease, color .15s ease; cursor: pointer; }
.crm-btn-2:hover { background: var(--crm-acento-fundo); color: var(--crm-acento);
  text-decoration: none; }
.crm-btn-2:focus-visible { outline: 2px solid var(--crm-acento); outline-offset: 2px; }
.crm-btn-2:disabled { opacity: .45; cursor: default; }
/* Mesmo botão, cor de desfazer. "Remover embalagem" era texto fantasma ao
   lado do contorno verde de "Salvar embalagem": duas ações do mesmo bloco
   com dois pesos diferentes, e a de desfazer parecendo legenda. Mesmo
   contorno, vermelho — par legível, e o vermelho já diz que ela apaga. */
.crm-btn-2--perigo { color: var(--crm-mal); border-color: var(--crm-mal); }
.crm-btn-2--perigo:hover { background: var(--crm-mal-fundo); color: var(--crm-mal); }
/* Especificidade alta de propósito: o anel de foco genérico do deal é
   `[data-pagina]`-qualificado e ganharia de um seletor de classe só. */
[data-pagina="crm-deal"] .crm-btn-2--perigo:focus-visible,
[data-pagina="crm"] .crm-btn-2--perigo:focus-visible {
  outline: 2px solid var(--crm-mal); outline-offset: 2px; }
/* min-height 24px = WCAG 2.2 SC 2.5.8 (AA). Media 23px antes — abaixo do
   mínimo, e são ações reais (trocar produto, editar embalagem, remover). */
.crm-btn-3 { display: inline-flex; align-items: center; gap: .3rem;
  min-height: 24px;
  background: none; border: 0; padding: .15rem .3rem; border-radius: 6px;
  font-size: var(--bi-fs-compact); font-weight: 500; color: var(--crm-tinta-2);
  cursor: pointer; transition: color .15s ease, background .15s ease; }
.crm-btn-3:hover { color: var(--crm-tinta); background: #eaeeec; }
/* Ganhar e Perder são o MESMO botão com outra cor: herdam a base do .crm-btn
   e só trocam o que os distingue. As diferenças de 0,02rem de fonte e 0,15rem
   de padding que existiam aqui eram acidente, não decisão. */
.crm-btn-ganhar, .crm-btn-perder { display: inline-flex; align-items: center;
  justify-content: center; gap: .4rem; border-radius: 8px;
  padding: .3rem .7rem; font-size: var(--bi-fs-compact); font-weight: 500;
  transition: opacity .15s ease, background .15s ease; cursor: pointer; }
.crm-btn-ganhar { background: var(--crm-ok); color: #fff;
  border: 1px solid var(--crm-ok); font-weight: 600; }
.crm-btn-ganhar:hover { opacity: .85; color: #fff; }
.crm-btn-perder { background: transparent; color: var(--crm-mal);
  border: 1px solid transparent; }
.crm-btn-perder:hover { background: var(--crm-mal-fundo); color: var(--crm-mal); }
.crm-btn-ganhar:disabled, .crm-btn-perder:disabled { opacity: .45; cursor: default; }

/* Foco visível em TODA ação — antes só quatro seletores tinham, e Ganhar,
   Perder e Enviar proposta (as irreversíveis) estavam entre os que não. */
[data-pagina="crm"] .crm-btn-2:focus-visible,
[data-pagina="crm"] .crm-btn-3:focus-visible,
[data-pagina="crm"] .crm-cartao__acao:focus-visible,
[data-pagina="crm"] .crm-raia__cabo:focus-visible,
[data-pagina="crm"] .crm-lista__item:focus-visible,
[data-pagina="crm-deal"] .crm-btn-2:focus-visible,
[data-pagina="crm-deal"] .crm-btn-3:focus-visible,
[data-pagina="crm-deal"] .crm-btn-ganhar:focus-visible,
[data-pagina="crm-deal"] .crm-btn-perder:focus-visible,
[data-pagina="crm-deal"] .crm-lista__item:focus-visible {
  outline: 2px solid var(--crm-acento); outline-offset: 2px; }

/* Anel de foco dos campos: 8% de preto era invisível na prática. */
[data-pagina="crm"] .form-control:focus, [data-pagina="crm"] .form-select:focus,
[data-pagina="crm-deal"] .form-control:focus, [data-pagina="crm-deal"] .form-select:focus {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--crm-acento) 28%, transparent); }

/* --- medidas (painel de instrumento na linha de comando) --- */
.crm-medidas { display: flex; flex-wrap: wrap; margin: 0; }
.crm-medidas .crm-medida { display: flex; flex-direction: column; gap: .06rem;
  padding: 0 1.35rem; border-left: 1px solid var(--crm-borda); }
.crm-medidas .crm-medida:first-child { border-left: 0; padding-left: 0; }
.crm-medidas .crm-medida dt { font-size: var(--bi-fs-micro); font-weight: 600;
  color: var(--crm-tinta-3); text-transform: uppercase; letter-spacing: .1em; }
.crm-medidas .crm-medida dd { margin: 0; font-size: 1.12rem; line-height: 1.15;
  font-variant-numeric: tabular-nums; font-weight: 700; letter-spacing: -.02em; }
@media (max-width: 991.98px) {
  [data-pagina="crm"] .crm-medidas { display: none; }
}

/* ------------------------------------------------------------
   FUNIL — board em grid, estações com TRILHO DE SEGMENTOS
   ------------------------------------------------------------ */
/* O board tem QUATRO etapas fixas — não dá para usar largura sobrando criando
   coluna nova. E card largo não é card melhor: em 2560px cada um passava de
   580px para três linhas de texto, virando caixa esticada com metade vazia.
   A coluna ganha um teto e a sobra vira margem; acima de 1600px a sobra vira
   o painel de follow-ups à direita, que antes empurrava o board para baixo. */
[data-pagina="crm"] .crm-board { display: grid; gap: 1rem;
  grid-template-columns: repeat(4, minmax(0, var(--crm-coluna-max)));
  /* O contêiner já tem a largura exata das quatro colunas, então alinhar ao
     início mantém board e barra de comando na mesma vertical. */
  /* `align-content` PRECISA esticar: com `start` a linha da grade empacota no
     topo e a coluna nunca ganha altura — logo, nunca rola. Era metade da causa
     do board de 226px numa tela de 929px (a outra metade é o `align-items` da
     .crm-tela, logo abaixo). */
  justify-content: start; align-content: stretch; min-height: 0; }
@media (max-width: 1199.98px) {
  /* O teto vale aqui também: em duas colunas a 1199px o card chegava a
     528px — pior que no layout de quatro. */
  [data-pagina="crm"] .crm-board {
    grid-template-columns: repeat(2, minmax(0, var(--crm-coluna-max))); }
}
@media (max-width: 767.98px) {
  [data-pagina="crm"] .crm-board { grid-template-columns: minmax(0, 1fr); gap: .65rem; }
}


/* A tela do funil: board + follow-ups. Até 1599px eles se empilham (o painel
   só existe quando há compromisso, então não rouba espaço à toa); daí para
   cima o painel vira a coluna da direita, ocupando a sobra que o board não
   usa. */
/* Contêiner das duas telas — a linha de comando e o board dividem o mesmo
   limite, senão as medidas fogem para o canto e o board fica sozinho no meio. */
/* O funil não usa o contêiner geral: ele tem a largura NATURAL das quatro
   colunas (4 × 22rem + 3 gaps). Assim a barra de comando e o board terminam
   no mesmo lugar — board centrado com a barra esticada ficava torto. */
[data-pagina="crm"] .crm-comando,
[data-pagina="crm"] .crm-tela {
  max-width: calc(4 * var(--crm-coluna-max) + 3rem);
  margin-inline: auto; width: 100%; }
/* Acima de 1600px cabe a faixa do painel de follow-ups. A largura NÃO pode
   depender de o painel estar visível: a busca filtra os follow-ups no backend,
   então o painel some no meio da digitação e o board inteiro mudava de tamanho
   a cada tecla (1760px→1456px, card de 328px→352px). A faixa fica reservada
   sempre; sem compromisso pendente ela é só margem. */
@media (min-width: 1360px) {
  [data-pagina="crm"] .crm-tela,
  [data-pagina="crm"] .crm-comando {
    max-width: min(var(--crm-largura-max),
                   calc(4 * var(--crm-coluna-max) + 3rem + 25rem)); }
}

[data-pagina="crm"] .crm-tela { display: grid; gap: 1rem;
  grid-template-columns: minmax(0, 1fr); align-items: stretch; }
/* A partir de 1360px o feed de ações vira a coluna da direita. Abaixo disso
   ele se empilha: em 1199px a faixa deixaria as raias com 190px, estreitas
   demais para o card do negócio.
   Faixa FIXA, e não "só quando há compromisso": a busca filtra os follow-ups
   no backend, então o painel sumia no meio da digitação e o board inteiro
   mudava de tamanho a cada tecla. */
@media (min-width: 1360px) {
  [data-pagina="crm"] .crm-tela {
    grid-template-columns: minmax(0, 1fr) minmax(15rem, 19rem); }
}
@media (min-width: 1600px) {
  [data-pagina="crm"] .crm-tela {
    grid-template-columns: minmax(0, 1fr) minmax(18rem, 24rem); }
}

/* laje contida com os cards: leve tintura do tom da etapa */
[data-pagina="crm"] .crm-coluna {
  background: color-mix(in srgb, var(--tom) 7%, #fff); border-radius: 12px;
  padding: .6rem; display: flex; flex-direction: column; gap: .6rem;
  min-height: 13rem; }
/* Painel sem nada a listar: para de esticar até o rodapé. */
[data-pagina="crm"] .crm-painel--hug { align-self: start; }

/* Busca sem nenhum resultado: uma faixa no lugar do board inteiro. Ocupa as
   quatro trilhas para não deslocar a grade, e não estica: o vazio não merece
   a altura da tela. */
[data-pagina="crm"] .crm-board__vazio { grid-column: 1 / -1; align-self: start;
  background: var(--crm-superficie); border: 1px dashed var(--crm-borda);
  border-radius: 12px; padding: 2rem 1rem; text-align: center;
  color: var(--crm-tinta-2); font-size: .9rem; }
[data-pagina="crm"] .crm-coluna__vazio { flex: 1; display: flex;
  align-items: center; justify-content: center; color: var(--crm-tinta-3);
  font-size: var(--bi-fs-compact); padding: 1rem; text-align: center; }

/* card do deal */
[data-pagina="crm"] .crm-coluna .crm-cartao { overflow: hidden;
  transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease; }
[data-pagina="crm"] .crm-coluna .crm-cartao:hover {
  border-color: var(--crm-borda-forte); box-shadow: var(--crm-sombra-2);
  transform: translateY(-1px); }
[data-pagina="crm"] .crm-cartao__corpo { display: block; padding: .8rem .9rem;
  color: inherit; text-decoration: none; }
[data-pagina="crm"] .crm-cartao__corpo:hover { color: inherit; }
[data-pagina="crm"] .crm-cartao__corpo:focus-visible {
  outline: 2px solid var(--crm-acento); outline-offset: -2px; }
[data-pagina="crm"] .crm-cartao__nome { font-size: .92rem; font-weight: 600;
  letter-spacing: -.01em; line-height: 1.25; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
[data-pagina="crm"] .crm-cartao__selos { display: flex; flex-wrap: wrap;
  gap: .25rem; margin-top: .3rem; }
[data-pagina="crm"] .crm-cartao__valor { font-size: 1.05rem; font-weight: 700;
  font-variant-numeric: tabular-nums; letter-spacing: -.02em; margin-top: .5rem;
  color: var(--tom); }
[data-pagina="crm"] .crm-cartao__rodape { display: flex; align-items: center;
  gap: .5rem; border-top: 1px solid var(--crm-borda); padding: .4rem .9rem; }
[data-pagina="crm"] .crm-cartao__acao { margin-left: auto; border: 0;
  background: none; color: var(--crm-acento); font-size: var(--bi-fs-compact);
  font-weight: 600; cursor: pointer; padding: .15rem .3rem; border-radius: 6px;
  min-height: 24px; }
[data-pagina="crm"] .crm-cartao__acao:hover { background: var(--crm-acento-fundo); }
.crm-avatar { width: 1.45rem; height: 1.45rem; border-radius: 50%; flex: none;
  background: #e2e2e6; color: var(--crm-tinta-2); display: inline-flex;
  align-items: center; justify-content: center; font-size: var(--bi-fs-micro);
  font-weight: 600; letter-spacing: .02em; }

/* UM cabeçalho por raia — o bloco sólido no tom da etapa. Era declarado duas
   vezes com os MESMOS três dados: `.crm-estacao` da tabuleta larga e
   `.crm-raia__cabo` do telefone. Agora é o mesmo elemento: no telefone ele
   também colapsa a raia (daí ser <button>), na tabuleta é só o rótulo. */
[data-pagina="crm"] .crm-raia__cabo { display: flex; align-items: center;
  gap: .5rem; width: 100%; appearance: none; text-align: left;
  background: var(--tom); color: #fff; border: 0; border-radius: 8px;
  padding: .5rem .75rem; margin-bottom: .55rem; cursor: default; }
[data-pagina="crm"] .crm-raia__nome { font-size: var(--bi-fs-micro); font-weight: 700;
  color: #fff; text-transform: uppercase; letter-spacing: .1em; }
[data-pagina="crm"] .crm-raia__conta { font-size: var(--bi-fs-micro); font-weight: 600;
  color: #fff; font-variant-numeric: tabular-nums;
  border: 1px solid rgba(255, 255, 255, .55); border-radius: 999px;
  padding: 0 .38rem; line-height: 1.4; }
[data-pagina="crm"] .crm-raia__soma { margin-left: auto; font-size: var(--bi-fs-compact);
  font-weight: 700; color: #fff;
  font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
/* o chevron é do colapso, que só existe no telefone */
[data-pagina="crm"] .crm-raia__cabo .fa-chevron-down { display: none; }
@media (max-width: 767.98px) {
  [data-pagina="crm"] .crm-raia__cabo { cursor: pointer; margin-bottom: 0; }
  [data-pagina="crm"] .crm-raia__cabo .fa-chevron-down {
    display: inline-block; margin-left: .5rem; transition: transform .15s ease; }
  [data-pagina="crm"] .crm-raia__cabo[aria-expanded="true"] .fa-chevron-down {
    transform: rotate(180deg); }
  [data-pagina="crm"] .crm-raia__corpo { display: none; }
  [data-pagina="crm"] .crm-raia--aberta .crm-raia__corpo { display: block;
    margin-top: .55rem; }
}

/* --- follow-ups --- */
[data-pagina="crm"] .crm-fups li { display: flex; flex-wrap: wrap;
  align-items: center; gap: .5rem; padding: .45rem 0; }
/* A lane das ações não pode parecer uma etapa: as raias são lajes tintadas
   com o tom da etapa e cabeçalho de contagem/valor; esta é papel em branco
   com contorno tracejado e um relógio no título. */
[data-pagina="crm"] .crm-fups-lane { background: #fff; border-style: dashed;
  border-color: var(--crm-borda-forte); }
[data-pagina="crm"] .crm-fups-lane #crm-fups-tit { display: inline-flex;
  align-items: center; gap: .4rem; }
[data-pagina="crm"] .crm-fups li + li { border-top: 1px solid var(--crm-borda); }

/* ------------------------------------------------------------
   DEAL — página própria: capa, trilho, corpo (rail + main),
   rodapé de decisão grudado. Sem wsurface.
   ------------------------------------------------------------ */
[data-pagina="crm-deal"] .crm-pagina { display: flex; flex-direction: column;
  gap: 0; min-height: 0; flex: 1 1 auto; }
/* A capa é a grade de 12 do Bootstrap (row/col, montada no JS). Nenhuma regra
   de layout aqui: as larguras são das colunas, e o CSS cuida só do que o
   Bootstrap não tem — a pele da faixa, o nome do cliente e o resumo. */
[data-pagina="crm-deal"] .crm-capa { background: var(--crm-superficie);
  border-bottom: 1px solid var(--crm-borda); padding-block: .5rem .45rem; }
[data-pagina="crm-deal"] .crm-capa .crm-etiqueta { display: block;
  margin-bottom: .2rem; }
/* Campo com botão colado (contato + Ligar): o select cede, o botão não —
   sem `nowrap` o select tomava a coluna inteira e o Ligar caía para a linha
   de baixo, esticando a capa em 40px. */
[data-pagina="crm-deal"] .crm-capa .crm-linha { flex-wrap: nowrap; }
[data-pagina="crm-deal"] .crm-capa .crm-linha > .form-select { min-width: 0; }
[data-pagina="crm-deal"] .crm-capa .crm-linha > .crm-btn-2 { white-space: nowrap; }
/* Resumo do que está guardado no painel de detalhes: leitura, não campo. Em
   duas linhas e não uma — numa linha só ele cortava "validade 14/08/20…". */
[data-pagina="crm-deal"] .crm-resumo { font-size: .875rem;
  color: var(--crm-tinta-2); display: -webkit-box; -webkit-line-clamp: 2;
  -webkit-box-orient: vertical; overflow: hidden; }
/* Prévia da assinatura no painel de envio: papel, não campo — fundo branco,
   contorno leve e a arte encolhida para caber nos 30rem do painel. */
[data-pagina="crm-deal"] .crm-assinatura-previa { background: #fff;
  border: 1px solid var(--crm-borda); border-radius: 8px;
  padding: .7rem .8rem; overflow-x: auto; }
[data-pagina="crm-deal"] .crm-assinatura-previa img { max-width: 100%;
  height: auto; }
[data-pagina="crm-deal"] .crm-assinatura-previa p { margin: 0 0 .5rem; }
/* Formulário do painel lateral: uma coluna, campos empilhados. Em duas
   colunas num painel de 26rem nenhum campo caberia inteiro. */
[data-pagina="crm-deal"] .crm-form-lista { display: grid; gap: .85rem;
  margin: 0; }
[data-pagina="crm-deal"] .crm-form-lista dt { font-size: var(--bi-fs-micro);
  font-weight: 600; color: var(--crm-tinta-3); text-transform: uppercase;
  letter-spacing: .1em; }
[data-pagina="crm-deal"] .crm-form-lista dd { margin: .25rem 0 0; }
/* Título de bloco dentro do painel: separa o que vai para o pedido do que
   sai impresso. Linha em cima, e nenhuma no primeiro. */
[data-pagina="crm-deal"] .crm-form-grupo { padding-top: .85rem;
  border-top: 1px solid var(--crm-borda); }
[data-pagina="crm-deal"] .crm-form-grupo:first-child { padding-top: 0;
  border-top: 0; }
[data-pagina="crm-deal"] .crm-form-lista .form-control,
[data-pagina="crm-deal"] .crm-form-lista .form-select,
[data-pagina="crm-deal"] .crm-form-lista .crm-combo { width: 100%; }
[data-pagina="crm-deal"] .crm-form-lista textarea.form-control {
  min-height: 5.5rem; resize: vertical; }
[data-pagina="crm-deal"] .crm-conta-nome { font-size: 1.15rem; font-weight: 700;
  letter-spacing: -.02em; }
[data-pagina="crm-deal"] .crm-capa-obs:empty { display: none; }
[data-pagina="crm-deal"] .crm-capa-obs { margin-top: .6rem; }

/* stepper: pastilhas na mesma rampa do funil — feitas tintadas,
   a atual sólida no tom da etapa */
[data-pagina="crm-deal"] .crm-etapas { display: flex; align-items: stretch;
  gap: .5rem; padding-block: .6rem;
  background: var(--crm-superficie); border-bottom: 1px solid var(--crm-borda);
  overflow-x: auto; }
[data-pagina="crm-deal"] .crm-etapa { --tom: var(--crm-tom-4);
  flex: 1 1 0; min-width: 6.5rem;
  display: flex; align-items: center; justify-content: center; border: 0;
  background: #eef1ef; padding: .5rem .7rem; border-radius: 8px;
  font-size: var(--bi-fs-micro); font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--crm-tinta-3);
  white-space: nowrap; }
/* Etapa é INDICADOR, não botão: sem cursor de clique, sem hover. Feita e
   futura precisam se distinguir — antes eram o mesmo cinza. */
[data-pagina="crm-deal"] .crm-etapa.feita {
  background: color-mix(in srgb, var(--tom) 10%, #fff); color: var(--tom); }
[data-pagina="crm-deal"] .crm-etapa.futura {
  background: transparent; border: 1px dashed var(--crm-borda);
  color: var(--crm-tinta-3); }
[data-pagina="crm-deal"] .crm-etapa.atual { background: var(--tom); color: #fff; }
[data-pagina="crm-deal"] .crm-etapa.atual .crm-etapa__dias {
  color: rgba(255, 255, 255, .85); }

/* corpo: trilho de contexto + trabalho */
/* O trilho era 17rem fixo enquanto a tabela ia a 2.100px — a descrição do
   produto sozinha ficava com 665px. Agora o trilho acompanha um pouco e o
   corpo respeita o contêiner. */
/* O acompanhamento deixou de ser contexto e virou a NEGOCIAÇÃO inteira
   (rodadas + conversas na mesma linha), então ganhou largura: 20rem apertava
   uma rodada com valor e ação em três linhas. A tabela de itens continua no
   centro porque é campo de trabalho — é nela que se digita. */
[data-pagina="crm-deal"] .crm-corpo { display: grid;
  grid-template-columns: minmax(20rem, 25rem) minmax(0, 1fr); gap: 1.25rem;
  padding: 1.25rem; align-items: start; flex: 1;
  max-width: var(--crm-largura-max); margin-inline: auto; width: 100%; }
/* A faixa (fundo branco, borda) continua atravessando a tela — é ela que
   separa as camadas —, mas o CONTEÚDO respeita o mesmo contêiner do corpo.
   Sem isto, em 2560px o seletor de representante ficava com 1.000px e o
   "Pedido no Senior" ia parar a um palmo da borda, longe do resto. */
[data-pagina="crm-deal"] .crm-capa,
[data-pagina="crm-deal"] .crm-etapas,
[data-pagina="crm-deal"] .crm-roteiro,
[data-pagina="crm-deal"] .crm-rodape {
  padding-inline: max(1.25rem, calc((100% - var(--crm-largura-max)) / 2)); }
/* Montando a proposta, o acompanhamento sai: a tabela de itens é a superfície
   de trabalho e ganha a tela inteira. A conversa com o cliente volta a
   importar antes (prospecção) e depois (proposta pronta) — durante, ela só
   estreita a coluna em que se digita. */
[data-pagina="crm-deal"] .crm-corpo--montando { grid-template-columns: minmax(0, 1fr); }
[data-pagina="crm-deal"] .crm-corpo--montando .crm-trilho { display: none; }
@media (max-width: 991.98px) {
  [data-pagina="crm-deal"] .crm-corpo { grid-template-columns: minmax(0, 1fr);
    padding: .8rem; gap: .8rem; }
}
/* Acompanhamento: superfície própria, cabeçalho que não rola e a lista
   rolando por dentro. Antes era texto solto sobre o canvas, ao lado de cards —
   parecia sobra de layout, e a lista empurrava a página inteira. */
[data-pagina="crm-deal"] .crm-trilho { position: sticky; top: 0;
  align-self: stretch; min-height: 0; max-height: 100%;
  display: flex; flex-direction: column;
  background: var(--crm-superficie); border: 1px solid var(--crm-borda);
  border-radius: var(--crm-raio); box-shadow: var(--crm-sombra);
  padding: .9rem 1rem; }
[data-pagina="crm-deal"] .crm-trilho > .crm-linha { flex: 0 0 auto; }
[data-pagina="crm-deal"] .crm-tempo { flex: 1 1 auto; min-height: 0;
  overflow-y: auto; padding-right: .2rem; }
/* Ações da proposta em linha, dentro do card dela. Quebra em duas linhas
   quando não couber. (A fita de revisões morreu: as rodadas vivem na linha
   do tempo, junto das conversas que as provocaram.) */
[data-pagina="crm-deal"] .crm-proposta-acoes { flex-wrap: wrap; gap: .4rem; }
@media (max-width: 991.98px) {
  [data-pagina="crm-deal"] .crm-trilho { position: static; }
}

/* ações da proposta no trilho: lista quieta */
/* próximo passo: a única superfície tingida */
[data-pagina="crm-deal"] .crm-passo { background: var(--crm-acento-fundo);
  border: 1px solid #d3e2d9; border-radius: var(--crm-raio);
  padding: .55rem .9rem; display: flex; flex-wrap: wrap; align-items: center;
  gap: .35rem 1rem; margin-bottom: 1rem; }
[data-pagina="crm-deal"] .crm-passo__etiqueta { font-size: var(--bi-fs-micro);
  font-weight: 700; color: var(--crm-acento); text-transform: uppercase;
  letter-spacing: .08em; flex: none; }
[data-pagina="crm-deal"] .crm-passo__texto { flex: 1 1 14rem; font-size: .9rem;
  color: var(--crm-tinta); }
/* Silêncio que passou do limiar: a faixa troca de tom. Verde é "está tudo no
   trilho"; aqui não está — a proposta está parada na mão do cliente. */
[data-pagina="crm-deal"] .crm-passo[data-cobrando] { background: var(--crm-mal-fundo);
  border-color: color-mix(in srgb, var(--crm-mal) 25%, #fff); }

/* A rodada da negociação tem PESO na linha do tempo: é o marco que passa a
   bola. Conversa é texto corrido; rodada é linha com valor e PDF. */
[data-pagina="crm-deal"] .crm-tempo__rodada { display: flex; align-items: center;
  flex-wrap: wrap; gap: .3rem .6rem; margin: .1rem 0 .2rem; }
[data-pagina="crm-deal"] .crm-tempo--rodada .crm-tempo__no {
  background: var(--crm-acento); box-shadow: 0 0 0 3px var(--crm-acento-fundo); }

/* tabela de itens */
.crm-tabela { width: 100%; border-collapse: collapse; }
.crm-tabela th { font-size: var(--bi-fs-micro); font-weight: 600; color: var(--crm-tinta-3);
  text-transform: uppercase; letter-spacing: .1em; text-align: left;
  padding: .5rem .75rem; border-bottom: 1px solid var(--crm-borda); }
.crm-tabela td { padding: .7rem .75rem; border-bottom: 1px solid var(--crm-borda);
  vertical-align: top; font-size: .9rem; }
.crm-tabela tbody tr:last-child td { border-bottom: 0; }
.crm-tabela .num { text-align: right; font-variant-numeric: tabular-nums; }
.crm-tabela .num .form-control, .crm-tabela .num .form-select {
  max-width: 7.5rem; margin-left: auto; }
.crm-tabela [data-embalagem] { white-space: nowrap; }
.crm-tabela tfoot td { border-top: 1px solid var(--crm-borda-forte);
  border-bottom: 0; font-variant-numeric: tabular-nums; }
.crm-sublinha td { background: transparent; padding-top: 0; }
[data-pagina="crm-deal"] .crm-embal { border: 1px solid #d3e2d9;
  background: var(--crm-acento-fundo); border-radius: 8px;
  padding: .7rem .9rem; margin: .1rem 0 .35rem; }
/* Campo decidido pelo cadastro, não pela proposta (cordoalha em bobina). O
   `disabled` do Bootstrap não muda o fundo dentro do bloco tingido, então o
   campo parecia editável e o clique parecia falha da tela. Cinza e cursor de
   "não vai" dizem que a decisão foi tomada em outro lugar. */
[data-pagina="crm-deal"] .crm-embal .form-select:disabled {
  background-color: #eceff0; color: var(--crm-tinta-2);
  border-color: var(--crm-borda); cursor: not-allowed; }
/* Três campos e o botão de desfazer: o botão é do tamanho do que escreve, e
   a largura sobra para quem se digita. */
[data-pagina="crm-deal"] .crm-grade-form { display: grid;
  grid-template-columns: repeat(3, minmax(7rem, 1fr)) auto; gap: .6rem;
  align-items: end; }
@media (max-width: 767.98px) {
  [data-pagina="crm-deal"] .crm-grade-form {
    grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Os dois botões não cabem numa célula de 135px: "Remover embalagem"
     transbordava por cima do campo do peso. No telefone eles tomam a linha
     inteira e ficam à esquerda, na ordem em que se lê. */
  [data-pagina="crm-deal"] .crm-grade-form > div:last-child {
    grid-column: 1 / -1; flex-wrap: wrap; }
}

/* timeline com fio: o fio nasce no marcador e vai até o próximo, e a última
   entrada não puxa fio para o vazio. */
.crm-tempo { list-style: none; margin: 0; padding: 0; }
.crm-tempo li { display: grid; grid-template-columns: .55rem 1fr;
  gap: .7rem; padding-bottom: .95rem; position: relative; }
.crm-tempo li:not(:last-child)::before { content: ''; position: absolute;
  left: calc(.275rem - .5px); top: 1.05rem; bottom: -.05rem; width: 1px;
  background: var(--crm-borda); }
.crm-tempo li.crm-tempo--solto { display: block; }
.crm-tempo li.crm-tempo--solto::before { display: none; }
.crm-tempo .crm-tempo__no { width: .55rem; height: .55rem; border-radius: 50%;
  background: var(--crm-superficie); border: 2px solid var(--crm-borda-forte);
  margin-top: .42rem; box-sizing: border-box; }
/* Compromisso futuro é o único cheio: ele é o que ainda pede ação. */
.crm-tempo li.crm-tempo--futuro .crm-tempo__no { background: var(--crm-acento);
  border-color: var(--crm-acento); }
.crm-tempo .crm-tempo__quando { font-size: var(--bi-fs-micro); font-weight: 500;
  color: var(--crm-tinta-3); }
.crm-tempo .crm-tempo__texto { font-size: .9rem; margin-top: .05rem; }
.crm-tempo .crm-tempo__quem { font-size: var(--bi-fs-micro); color: var(--crm-tinta-3);
  margin-top: .1rem; }

/* rodapé de decisão grudado */
[data-pagina="crm-deal"] .crm-rodape { position: sticky; bottom: 0; z-index: 20;
  background: var(--crm-superficie); border-top: 1px solid var(--crm-borda);
  padding-block: .7rem; display: flex; flex-wrap: wrap; align-items: center;
  gap: .6rem 1rem; }
[data-pagina="crm-deal"] .crm-rodape__acoes { margin-left: auto; display: flex;
  flex-wrap: wrap; align-items: center; gap: .5rem; }
/* o total do deal fecha a rampa: verde profundo */
[data-pagina="crm-deal"] .crm-rodape #dl-total { color: var(--crm-acento); }

/* --- avisos --- */
.crm-aviso { background: var(--crm-superficie); border: 1px solid var(--crm-borda);
  border-radius: 8px; padding: .65rem .9rem; font-size: .88rem;
  display: flex; gap: .6rem; align-items: flex-start; margin-bottom: .75rem; }
.crm-aviso--ok   { border-color: #b7e2c5; background: var(--crm-ok-fundo); }
.crm-aviso--avi  { border-color: #f0d9a7; background: var(--crm-avi-fundo); }
.crm-aviso--erro { border-color: #f2c6c0; background: var(--crm-mal-fundo); }

/* --- estados vazios --- */
.crm-vazio { color: var(--crm-tinta-3); font-size: var(--bi-fs-compact); padding: 1.2rem .5rem; }

/* --- listas de sugestão (autocomplete) --- */
[data-pagina="crm"] .crm-lista, [data-pagina="crm-deal"] .crm-lista {
  background: var(--crm-superficie); border: 1px solid var(--crm-borda);
  border-radius: 10px; box-shadow: var(--crm-sombra-2); overflow: hidden;
  overflow-y: auto; }
[data-pagina="crm"] .crm-lista__item, [data-pagina="crm-deal"] .crm-lista__item {
  display: block; width: 100%; text-align: left; background: none; border: 0;
  border-bottom: 1px solid var(--crm-borda); padding: .6rem .85rem;
  font-size: .88rem; color: var(--crm-tinta); cursor: pointer; }
[data-pagina="crm"] .crm-lista__item:last-child,
[data-pagina="crm-deal"] .crm-lista__item:last-child { border-bottom: 0; }
[data-pagina="crm"] .crm-lista__item:hover,
[data-pagina="crm"] .crm-lista__item:focus,
[data-pagina="crm-deal"] .crm-lista__item:hover,
[data-pagina="crm-deal"] .crm-lista__item:focus { background: var(--crm-fundo); }
[data-pagina="crm"] .crm-lista--flutua, [data-pagina="crm-deal"] .crm-lista--flutua {
  position: absolute; left: 0; right: 0; z-index: 1060; max-height: 16rem; }

/* --- offcanvas: painel do sistema --- */
[data-pagina="crm"] .offcanvas, [data-pagina="crm-deal"] .offcanvas {
  border-left: 0; box-shadow: -12px 0 48px rgba(26, 26, 30, .16); }
[data-pagina="crm"] .offcanvas-header, [data-pagina="crm-deal"] .offcanvas-header {
  padding: 1rem 1.25rem; }
[data-pagina="crm"] .offcanvas-body, [data-pagina="crm-deal"] .offcanvas-body {
  padding: 1rem 1.25rem; }
[data-pagina="crm"] .crm-oc-rodape, [data-pagina="crm-deal"] .crm-oc-rodape {
  display: flex; gap: .6rem; padding: .9rem 1.25rem;
  border-top: 1px solid var(--crm-borda); }
[data-pagina="crm"] .crm-oc-rodape > *, [data-pagina="crm-deal"] .crm-oc-rodape > * {
  flex: 1 1 0; }
[data-pagina="crm"] .btn-close, [data-pagina="crm-deal"] .btn-close {
  opacity: .55; transition: opacity .15s ease; }
[data-pagina="crm"] .btn-close:hover, [data-pagina="crm-deal"] .btn-close:hover {
  opacity: 1; }
[data-pagina="crm"] .btn-close:focus, [data-pagina="crm-deal"] .btn-close:focus {
  box-shadow: 0 0 0 3px rgba(26, 26, 30, .12); opacity: 1; }

/* --- toque e movimento --- */
@media (pointer: coarse) {
  [data-pagina="crm"] .crm-btn, [data-pagina="crm"] .crm-btn-2,
  [data-pagina="crm"] .form-control, [data-pagina="crm"] .form-select,
  [data-pagina="crm-deal"] .crm-btn, [data-pagina="crm-deal"] .crm-btn-2,
  [data-pagina="crm-deal"] .crm-btn-ganhar, [data-pagina="crm-deal"] .crm-btn-perder,
  [data-pagina="crm-deal"] .form-control, [data-pagina="crm-deal"] .form-select {
    min-height: 2.75rem; }
  /* Estes tinham ficado de fora e são ação de verdade (trocar produto,
     editar embalagem, remover) — 20px de altura no dedo não se acerta. */
  [data-pagina="crm"] .crm-btn-3, [data-pagina="crm-deal"] .crm-btn-3,
}
@media (prefers-reduced-motion: reduce) {
  [data-pagina="crm"] *, [data-pagina="crm-deal"] * { transition: none !important; }
}

/* colunas de apoio da tabela: somem em telas menores */
@media (max-width: 767.98px) {
  [data-pagina="crm-deal"] .crm-col-md { display: none; }
}
@media (max-width: 991.98px) {
  [data-pagina="crm-deal"] .crm-col-lg { display: none; }
}
[data-pagina="crm-deal"] .crm-tabela .num .form-control { text-align: right; }

/* ------------------------------------------------------------
   TELEFONE — densidade: sem altura mínima fantasma no funil,
   capa do deal em grade compacta, stepper enxuto, trilho da
   proposta DEPOIS do trabalho principal.
   ------------------------------------------------------------ */
@media (max-width: 767.98px) {
  /* funil: a laje encolhe até o conteúdo — nada de ar fantasma */
  [data-pagina="crm"] .crm-coluna { min-height: 0; }
  [data-pagina="crm"] .crm-raia__cabo { padding: .55rem .6rem; }

  /* capa do deal: as colunas do Bootstrap já empilham (col-12); aqui só a
     densidade — e os dois botões de editar dividem a linha em vez de sair
     pela borda. */
  [data-pagina="crm-deal"] .crm-capa { padding: .7rem .8rem .6rem; }
  [data-pagina="crm-deal"] .crm-capa .row > .col-auto:last-child { flex: 1 1 100%; }
  [data-pagina="crm-deal"] .crm-capa .row > .col-auto:last-child > .crm-btn {
    flex: 1 1 0; justify-content: center; }
  [data-pagina="crm-deal"] .crm-conta-nome { font-size: 1.02rem; }

  /* stepper: as 4 pastilhas cabem na tela — some o contador de dias */
  [data-pagina="crm-deal"] .crm-etapas { gap: .3rem; padding: .5rem .8rem; }
  [data-pagina="crm-deal"] .crm-etapa { min-width: 0; padding: .45rem .3rem;
    font-size: var(--bi-fs-micro); letter-spacing: .04em; }
  [data-pagina="crm-deal"] .crm-etapa__dias { display: none; }

  /* corpo: trabalho primeiro, trilho da proposta depois */
  [data-pagina="crm-deal"] .crm-corpo { padding: .8rem; gap: .8rem; }
  [data-pagina="crm-deal"] .crm-trilho { order: 2; }
  [data-pagina="crm-deal"] .crm-painel { padding: .85rem .8rem; }
  [data-pagina="crm-deal"] .crm-rodape { padding: .6rem .8rem; }

  /* iOS: input com fonte < 16px dispara ZOOM automático ao focar — o
     zoom desloca o rodapé sticky pro meio da tela e o conteúdo vaza
     por trás. 1rem = 16px mata o zoom na raiz. */
  [data-pagina="crm"] .form-control, [data-pagina="crm"] .form-select,
  [data-pagina="crm-deal"] .form-control, [data-pagina="crm-deal"] .form-select {
    font-size: 1rem; }

  /* tabela de itens: células e inputs mais enxutos pro TOTAL caber */
  [data-pagina="crm-deal"] .crm-tabela th { padding: .45rem .3rem; }
  [data-pagina="crm-deal"] .crm-tabela td { padding: .55rem .3rem;
    font-size: var(--bi-fs-compact); }
  [data-pagina="crm-deal"] .crm-tabela td:empty { padding: 0; }
  [data-pagina="crm-deal"] .crm-tabela .num .form-control,
  [data-pagina="crm-deal"] .crm-tabela .num .form-select { max-width: 5.4rem; }
  /* descrição do produto não vira parágrafo: 2 linhas e reticências */
  [data-pagina="crm-deal"] .crm-tabela td .crm-rotulo { display: -webkit-box;
    -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

  /* teclado aberto (edição de item) esconde o rodapé de decisão —
     classe posta pelo JS no focusin/focusout da tabela */
  [data-pagina="crm-deal"] .crm-rodape--editando { display: none; }

  /* Rodapé de decisão no telefone: FIXO, não sticky. O sticky depende da
     altura do container, e no Safari do iPhone essa altura muda quando a
     barra de URL recolhe — o banner "descolava" e ficava no meio da rolagem.
     Fixo + safe-area encosta na borda de baixo sempre; a página ganha um
     colchão do mesmo tamanho pra última linha não ficar por baixo dele. */
  [data-pagina="crm-deal"] .crm-rodape {
    position: fixed; left: 0; right: 0; bottom: 0;
    padding-bottom: calc(.6rem + env(safe-area-inset-bottom, 0px));
    box-shadow: 0 -1px 12px rgba(23, 26, 24, .1); }
  [data-pagina="crm-deal"] .crm-pagina {
    padding-bottom: calc(7rem + env(safe-area-inset-bottom, 0px)); }
  /* a faixa de confirmação toma o lugar do rodapé — mesma âncora */
  [data-pagina="crm-deal"] #dl-confirmacao { align-items: flex-start; }
  [data-pagina="crm-deal"] #dl-confirmacao .crm-rodape__acoes { width: 100%; }
  [data-pagina="crm-deal"] #dl-confirmacao .crm-rodape__acoes > * { flex: 1 1 0; }

  /* no telefone o painel é folha de tela cheia */
  [data-pagina="crm"] .offcanvas, [data-pagina="crm-deal"] .offcanvas {
    --bs-offcanvas-width: 100%; }
}

/* OFFCANVAS FECHADO NÃO PODE FICAR ESTACIONADO FORA DA TELA (toque).
   O Bootstrap guarda o painel com `translateX(100%)`: um box da largura
   da tela parado logo à direita dela. O Safari do iPhone/iPad conta esse
   box na largura do conteúdo ao calcular a escala INICIAL — a página abre
   com zoom-out e aceita arrastar de lado. (No Chromium o `overflow-x:
   clip` do html mascara o sintoma, por isso não aparecia nas medições.)
   Até 1199px o painel não usa transform: aparece e some por opacidade.
   No desktop (≥1200px, sem escala automática) o slide lateral fica. */
@media (max-width: 1199.98px) {
  [data-pagina="crm"] .offcanvas, [data-pagina="crm-deal"] .offcanvas {
    transform: none !important;
    transition: opacity .2s ease; opacity: 1; }
  [data-pagina="crm"] .offcanvas:not(.show):not(.showing),
  [data-pagina="crm-deal"] .offcanvas:not(.show):not(.showing) { opacity: 0; }
}

/* deal frio: parado na etapa acima do limiar (classificado no backend) —
   o card inteiro esquenta pro âmbar, escaneável descendo a raia */
[data-pagina="crm"] .crm-cartao--frio { border-color: #ecc94b66;
  background: #fffdf4; }
[data-pagina="crm"] .crm-cartao--frio .crm-cartao__rodape {
  border-top-color: #f0e6c0; }
/* dias na etapa atual, no trilho do deal */
[data-pagina="crm-deal"] .crm-etapa__dias { font-weight: 500;
  color: var(--crm-tinta-3); text-transform: none; letter-spacing: 0; }

/* ------------------------------------------------------------
   A TELA CABE NA JANELA (ambas as páginas do CRM).
   O shell dá a altura (`content--altura-cheia`: .main com height fixa e
   overflow hidden). Aqui só se diz QUEM rola: no funil, cada coluna do
   kanban; no negócio, o corpo. A página em si nunca rola — perder a barra
   de comando e o rodapé de decisão ao rolar era o custo de deixar rolar.
   ------------------------------------------------------------ */
[data-pagina="crm"] .crm-tela { flex: 1 1 auto; min-height: 0; }
[data-pagina="crm"] .crm-comando { flex: 0 0 auto; }

/* Só a partir de md o board é grade de colunas — abaixo disso as raias
   são um acordeão e quem rola é a tela inteira. */
@media (min-width: 768px) {
  [data-pagina="crm"] .crm-board { min-height: 0; align-items: stretch; }
  [data-pagina="crm"] .crm-raia { display: flex; flex-direction: column;
    min-height: 0; }
  [data-pagina="crm"] .crm-raia__corpo { display: flex; flex-direction: column;
    min-height: 0; flex: 1 1 auto; }
  [data-pagina="crm"] .crm-coluna { flex: 1 1 auto; min-height: 0;
    overflow-y: auto; }
  /* Card NÃO encolhe. Sem isto a coluna flex espreme os cards para caber na
     altura disponível e o `overflow-y: auto` nunca dispara: 13 cards ficavam
     nos mesmos 885px, cada um mais fino, e a rolagem simplesmente não existia. */
  [data-pagina="crm"] .crm-coluna > .crm-cartao { flex: 0 0 auto; }
  [data-pagina="crm"] .crm-tela { overflow: hidden; }
  /* O painel de follow-ups é a segunda coluna: rola sozinho também. */
  [data-pagina="crm"] .crm-tela > .crm-painel { min-height: 0; overflow-y: auto; }
}
@media (max-width: 767.98px) {
  [data-pagina="crm"] .crm-tela { overflow-y: auto; }
}

/* Negócio: capa, trilho de etapas e rodapé ficam parados; o corpo rola. */
[data-pagina="crm-deal"] .crm-capa,
[data-pagina="crm-deal"] .crm-etapas,
[data-pagina="crm-deal"] .crm-rodape { flex: 0 0 auto; }
[data-pagina="crm-deal"] .crm-corpo { flex: 1 1 auto; min-height: 0;
  overflow-y: auto; }

/* Campo buscável (crm-combo.js): a lista flutua ancorada no campo. */
[data-pagina="crm"] .crm-combo,
[data-pagina="crm-deal"] .crm-combo { position: relative; display: block; }

/* Prévia do rascunho em voo: os números derivados esmaecem no instante da
   digitação e voltam quando o servidor responde — sem isto o total da conta
   ANTERIOR parecia ser o da digitação atual. */
[data-pagina="crm-deal"] .crm-previa-pendente [data-previa-total],
[data-pagina="crm-deal"] .crm-previa-pendente [data-previa-qtd],
[data-pagina="crm-deal"] .crm-previa-pendente [data-previa-base],
[data-pagina="crm-deal"] .crm-previa-pendente [data-previa-delta],
[data-pagina="crm-deal"] .crm-previa-pendente [data-previa-chip],
[data-pagina="crm-deal"] .crm-previa-pendente .crm-conversao__txt,
[data-pagina="crm-deal"] .crm-previa-pendente tfoot {
  opacity: .35;
  transition: opacity .15s ease;
}
/* A gangorra é conta do SERVIDOR: mexer na quantidade, no nº de volumes ou
   no conteúdo manda a linha inteira para lá e espera. Esmaecer o número
   velho diz "isto não vale mais"; o giro ao lado da conversão diz "estou
   contando" — sem ele, a espera se parecia com tela travada. Fica na
   legenda porque é ali que se lê o resultado da gangorra. */
[data-pagina="crm-deal"] .crm-previa-pendente [data-previa-conversao]::after {
  content: ''; display: inline-block; vertical-align: -1px;
  width: .7rem; height: .7rem; margin-left: .45rem;
  border: 2px solid var(--crm-acento); border-right-color: transparent;
  border-radius: 50%; animation: crm-girando .6s linear infinite; }
@keyframes crm-girando { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  [data-pagina="crm-deal"] .crm-previa-pendente [data-previa-conversao]::after {
    animation: none; border-right-color: var(--crm-borda); }
}

/* Montar a proposta é a própria tabela: a última linha procura o produto e os
   achados entram como linhas logo abaixo (lista flutuante era cortada pelo
   contêiner que rola). */
[data-pagina="crm-deal"] .crm-linha-nova > td { padding-top: .6rem; }
[data-pagina="crm-deal"] .crm-linha-achado { cursor: pointer; }
[data-pagina="crm-deal"] .crm-linha-achado > td { padding-left: 1.5rem; }
[data-pagina="crm-deal"] .crm-linha-achado:hover > td,
[data-pagina="crm-deal"] .crm-linha-achado:focus > td {
  background: var(--crm-acento-fraco, rgba(23, 26, 24, .05));
}

/* Unidade colada no número (KG ao lado do campo, não embaixo dele): abaixo
   do campo ela era lida como legenda de outra coisa. */
[data-pagina="crm-deal"] .crm-campo-un { display: inline-flex; align-items: center;
  gap: .4rem; justify-content: flex-end; }
[data-pagina="crm-deal"] .crm-campo-un > .form-control { width: 7.5rem; text-align: right; }

/* Lista de escolha com marca à direita (contatos do cliente no "Novo
   negócio"): o item continua sendo `.crm-lista__item`, mas com duas colunas —
   a ficha à esquerda, o sinal de escolhida à direita. Em bloco, a marca caía
   numa linha própria e parecia mais um dado da pessoa. */
[data-pagina="crm"] .crm-lista--escolha .crm-lista__item {
  display: flex; align-items: center; gap: .6rem;
}
[data-pagina="crm"] .crm-lista--escolha [aria-selected="true"] {
  background: var(--crm-acento-fraco, rgba(23, 26, 24, .05));
}

/* Esperando o servidor sem apagar a tela: o conteúdo que ainda é o ANTERIOR
   esmaece até a resposta chegar. É o mesmo vocabulário da prévia do rascunho
   no negócio — dizer "isto ainda não é a sua resposta" em vez de exibir dado
   velho com cara de novo. */
[data-pagina="crm"] .crm-aguardando,
[data-pagina="crm-deal"] .crm-aguardando {
  opacity: .45; transition: opacity .15s ease; pointer-events: none;
}

/* Documento da proposta: coluna direita do bloco do vendedor (representante),
   como no documento que o Ploomes emite. */
.prop-vend-dir{ text-align:right; }

/* Selo das normas na proposta de cordoalha — some junto com a condição 5
   quando a proposta não tem cordoalha. */
.prop-selo{ margin-top:2mm; }
.prop-selo img{ height:14mm; }

/* Negócio no celular: a página inteira rola, em vez da capa comer a tela.
   Com os termos do documento editáveis, a capa passou de 6 para 14 campos —
   empilhados em 390px ela ocupava 639px dos 844 e sobravam 26px para a
   proposta e o acompanhamento, que são o trabalho. Numa tela estreita a
   rolagem única é o gesto natural; a altura cheia continua valendo do tablet
   para cima, onde a capa é uma fita e não uma coluna. */
@media (max-width: 767.98px) {
  .main:has(> .content--altura-cheia):has([data-pagina="crm-deal"]) {
    height: auto; overflow: visible;
  }
  [data-pagina="crm-deal"] .crm-corpo { overflow-y: visible; }
  /* O rodapé de decisão para de flutuar e fecha a página: preso ao pé numa
     página que rola, ele cobriria os últimos itens da proposta. */
  [data-pagina="crm-deal"] .crm-rodape { position: static; }
}

/* Itens da proposta no celular: cartão, não tabela que rola de lado.
   Sete colunas em 337px espremiam o campo de preço a 41px — largo o
   bastante para mostrar "5,3" cortado e estreito demais para digitar. O
   padrão de rolar na horizontal serve para LER uma tabela; aqui se escreve,
   e escrever num campo que está meio fora da tela não é possível.
   Cada item vira um bloco com rótulo à esquerda e valor à direita. */
@media (max-width: 767.98px) {
  [data-pagina="crm-deal"] #dl-itens thead { display: none; }
  [data-pagina="crm-deal"] #dl-itens,
  [data-pagina="crm-deal"] #dl-itens tbody,
  [data-pagina="crm-deal"] #dl-itens tfoot,
  [data-pagina="crm-deal"] #dl-itens tr { display: block; width: 100%; }
  [data-pagina="crm-deal"] #dl-itens tbody tr {
    border: 1px solid var(--crm-borda); border-radius: 8px;
    padding: .6rem .75rem; margin-bottom: .6rem;
  }
  [data-pagina="crm-deal"] #dl-itens td {
    display: flex; align-items: center; justify-content: space-between;
    gap: .75rem; width: 100%; padding: .3rem 0; border: 0; text-align: right;
  }
  /* A primeira célula é o produto: nome inteiro, sem rótulo e sem alinhar
     à direita — é o título do cartão. */
  [data-pagina="crm-deal"] #dl-itens td:first-child {
    display: block; text-align: left; padding-bottom: .5rem;
  }
  [data-pagina="crm-deal"] #dl-itens td[data-rotulo]::before {
    content: attr(data-rotulo); color: var(--crm-tinta-2);
    font-size: var(--bi-fs-compact); text-transform: uppercase; letter-spacing: .06em;
    text-align: left; flex: 0 0 auto;
  }
  /* Célula vazia (a das ações quando não se edita) não vira linha em branco. */
  [data-pagina="crm-deal"] #dl-itens td:empty { display: none; }
  /* No cartão, o campo tem a largura toda que sobra do rótulo — menos a
     busca de produto, que é a linha inteira e não tem rótulo ao lado. */
  [data-pagina="crm-deal"] #dl-itens td[data-rotulo] .form-control { max-width: 10rem; }
  [data-pagina="crm-deal"] #dl-add-corpo td { display: block; padding: .2rem 0; }
  [data-pagina="crm-deal"] #dl-add-busca { max-width: none; width: 100%; }
  /* Achado de produto: linha inteira, texto à esquerda, alvo alto. */
  [data-pagina="crm-deal"] .crm-linha-achado > td {
    display: block; text-align: left; padding: .55rem .75rem; }
  [data-pagina="crm-deal"] .crm-campo-un > .form-control { width: 7rem; }
  /* "vender por embalagem" é uma AÇÃO, não um sufixo da quantidade: ao lado
     do campo ela aparecia cortada ("vender por em"). Vira linha própria. */
  [data-pagina="crm-deal"] #dl-itens td[data-rotulo="Quantidade"] { flex-wrap: wrap; }
  [data-pagina="crm-deal"] #dl-itens td[data-rotulo="Quantidade"] > .crm-btn-3 {
    flex: 1 0 100%; margin: .35rem 0 0 !important; justify-content: flex-end; }
  /* As colunas de apoio deixam de ser escondidas: como cartão, elas cabem. */
  [data-pagina="crm-deal"] #dl-itens td.crm-col-md,
  [data-pagina="crm-deal"] #dl-itens td.crm-col-lg { display: flex; }
  /* Rodapé de totais: mesma leitura de rótulo e valor. */
  [data-pagina="crm-deal"] #dl-itens tfoot tr { display: flex;
    justify-content: space-between; padding: .2rem .75rem; }
  [data-pagina="crm-deal"] #dl-itens tfoot td:empty { display: none; }
}

/* O "X" de fechar painel e modal: 16×16 no sistema inteiro, abaixo dos 24px
   que a WCAG 2.5.8 pede para alvo de toque. A causa não era o Bootstrap —
   ele desenha o botão com `content-box` (16px de ícone + 8px de padding =
   32px de alvo); a regra global de `border-box` do projeto fez o padding
   comer o próprio tamanho. Devolver a caixa que o componente espera
   restaura os 32px SEM mexer no ícone nem no espaçamento visual. */
.btn-close {
  box-sizing: content-box;
  min-width: 1em;
  min-height: 1em;
}
