/* GERADO NA CONSTRUCAO — nao edite. Fonte: framework.fonte.css e a lista em ConcatenarCssV3.targets. */
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — FONTES SELF-HOSTED
   Barlow (texto) + Bakbak One (display) + JetBrains Mono (mono).
   Todas OFL. woff2 subset latin em assets/fonts/.
   Nunca carregar de CDN em runtime (politica CSP/SRI Ibrascan).
   ========================================================================= */

/* Barlow */
@font-face {
    font-family: "Barlow";
    font-style: normal;
    font-weight: 300;
    font-display: swap;
    src: url("assets/fonts/Barlow-Light.woff2") format("woff2");
}

@font-face {
    font-family: "Barlow";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("assets/fonts/Barlow-Regular.woff2") format("woff2");
}

@font-face {
    font-family: "Barlow";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("assets/fonts/Barlow-Medium.woff2") format("woff2");
}

@font-face {
    font-family: "Barlow";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("assets/fonts/Barlow-SemiBold.woff2") format("woff2");
}

@font-face {
    font-family: "Barlow";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("assets/fonts/Barlow-Bold.woff2") format("woff2");
}

/* Bakbak One — display (peso unico) */
@font-face {
    font-family: "Bakbak One";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("assets/fonts/BakbakOne-Regular.woff2") format("woff2");
}

/* JetBrains Mono */
@font-face {
    font-family: "JetBrains Mono";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("assets/fonts/JetBrainsMono-Regular.woff2") format("woff2");
}

@font-face {
    font-family: "JetBrains Mono";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("assets/fonts/JetBrainsMono-Medium.woff2") format("woff2");
}

@font-face {
    font-family: "JetBrains Mono";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("assets/fonts/JetBrainsMono-Bold.woff2") format("woff2");
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — PRIMITIVOS INVARIAVEIS
   Neutros e sinais NAO mudam por produto. A marca (brand/accent/gold) vive
   em themes/*.css. Componente nunca consome isto direto — so os papeis
   semanticos (tokens/semantic.css).
   ========================================================================= */
:root {
    /* Neutros — tom levemente frio, alinhado ao azul institucional */
    --neutral-0: #ffffff;
    --neutral-25: #fafbfc;
    --neutral-50: #f5f7f9;
    --neutral-100: #eef1f4;
    --neutral-150: #e4e9ee;
    --neutral-200: #d8dfe6;
    --neutral-300: #c2ccd6;
    --neutral-400: #9aa8b5;
    --neutral-500: #74838f;
    --neutral-600: #566470;
    --neutral-700: #3e4a54;
    --neutral-800: #29333b;
    --neutral-900: #182026;
    --neutral-950: #0e1620;
    /* Sinais — semantica universal, product-invariant */
    --success-50: #eaf7f0;
    --success-100: #dcf2e6;
    --success-500: #24a15e;
    --success-600: #1f8f52;
    --success-700: #1a7d47;
    --warning-50: #fef7ec;
    --warning-100: #fbeecd;
    --warning-500: #d98a0b;
    --warning-600: #b9770a;
    --warning-700: #8f5c08;
    --danger-50: #fdeaea;
    --danger-100: #fbe0e0;
    --danger-500: #d64545;
    --danger-600: #c23b3b;
    --danger-700: #a32f2f;
    --info-50: #eaf1f8;
    --info-100: #dbe9f3;
    --info-500: #2b78b8;
    --info-600: #21618f;
    --info-700: #1a4e73;
}
/* =========================================================================
   TEMA — IBRASCAN (default da organizacao)
   Cores oficiais do Manual de Marca Ibrascan.
   Um produto novo COPIA este arquivo (ex.: themes/ecvmax.css) e troca SO
   estes ramps. Nada mais muda entre produtos.
   ========================================================================= */
:root {
    /* Marca primaria — azul institucional #02487d */
    --brand-50: #eef4fa;
    --brand-100: #d9e7f3;
    --brand-200: #b3cde5;
    --brand-300: #84acd2;
    --brand-400: #5188ba;
    --brand-500: #26689e;
    --brand-600: #0b5488;
    --brand-700: #02487d; /* oficial — primario */
    --brand-800: #023a64;
    --brand-900: #01294a;
    /* Marca secundaria — ciano #25b2e1 */
    --accent-50: #e9f7fc;
    --accent-100: #cfeef9;
    --accent-200: #a6e1f3;
    --accent-300: #6fceec;
    --accent-400: #43bde6;
    --accent-500: #25b2e1; /* oficial */
    --accent-600: #1b93bd;
    --accent-700: #167898;
    /* Marca terciaria / destaque — amarelo #f3b116 */
    --gold-100: #fdeecb;
    --gold-300: #f8cf6a;
    --gold-500: #f3b116; /* oficial */
    --gold-600: #cf940a;
    /* Logo do produto (arquivos em assets/brand/). Um produto novo troca SO estes
     tres caminhos: positivo (fundo claro), branco (fundo escuro) e negativo
     (fundo primario da marca). */
    --brand-logo: url("assets/brand/logo-horizontal.png");
    --brand-logo-branco: url("assets/brand/logo-horizontal-branco.png");
    --brand-logo-negativo: url("assets/brand/logo-horizontal-negativo.png");
    --brand-simbolo: url("assets/brand/simbolo.png");
    --brand-simbolo-branco: url("assets/brand/simbolo-branco.png");
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — TOKENS SEMANTICOS (PAPEIS)
   A UNICA camada que os componentes consomem.
   Claro/escuro num conjunto so via light-dark(claro, escuro):
     - segue o SO por padrao (color-scheme: light dark);
     - data-theme="dark"|"light" no <html> forca.
   Depende de: color-primitives.css (neutros/sinais) + themes/*.css (marca).
   ========================================================================= */
:root {
    color-scheme: light dark;
    /* Superficies */
    --color-bg: light-dark(var(--neutral-50), var(--neutral-950));
    --color-surface: light-dark(var(--neutral-0), #16212d);
    --color-surface-2: light-dark(var(--neutral-100), #1b2836);
    --color-surface-hover: light-dark(var(--neutral-100), #22303f);
    --color-border: light-dark(var(--neutral-150), #263542);
    --color-border-strong: light-dark(var(--neutral-300), #37485a);
    --color-overlay: light-dark(rgba(16, 27, 38, 0.45), rgba(4, 9, 15, 0.6));
    /* Palco de midia — escuro nos DOIS temas (nao competir com a foto/video).
     Papel proprio para o visualizador: o componente nunca cita neutro direto. */
    --color-stage: var(--neutral-950);
    --color-on-stage: var(--neutral-0);
    --color-stage-control: color-mix(in oklab, var(--neutral-0) 12%, transparent);
    --color-stage-control-hover: color-mix(in oklab, var(--neutral-0) 24%, transparent);
    /* Texto */
    --color-text: light-dark(var(--neutral-900), #e7eef4);
    --color-text-muted: light-dark(var(--neutral-600), #a4b3c1);
    --color-text-subtle: light-dark(var(--neutral-500), #768696);
    --color-text-invert: light-dark(var(--neutral-0), var(--neutral-950));
    /* Primario (marca) — dirige a UI funcional */
    --color-primary: light-dark(var(--brand-700), var(--brand-400));
    --color-primary-hover: light-dark(var(--brand-800), var(--brand-300));
    --color-primary-active: light-dark(var(--brand-900), var(--brand-500));
    --color-primary-soft: light-dark(var(--brand-50), rgba(81, 136, 186, 0.18));
    --color-primary-border: light-dark(var(--brand-200), rgba(81, 136, 186, 0.40));
    --color-on-primary: light-dark(var(--neutral-0), #04182b);
    /* Preenchimento solido de marca (area grande, ex.: header de accordion) —
     distinto de --color-primary (feito pra texto/icone/borda). No escuro usa
     um tom mais fechado da marca em vez do tom claro de destaque, pra nao
     virar uma mancha viva sobre superficies quase pretas. */
    --color-primary-fill: light-dark(var(--brand-700), var(--brand-800));
    --color-primary-fill-hover: light-dark(var(--brand-800), var(--brand-900));
    --color-on-primary-fill: var(--neutral-0);
    /* Accent (ciano) — enfase/decoracao de marca, nao acao primaria */
    --color-accent: light-dark(var(--accent-500), var(--accent-400));
    --color-accent-hover: light-dark(var(--accent-600), var(--accent-300));
    --color-accent-soft: light-dark(var(--accent-50), rgba(37, 178, 225, 0.16));
    --color-on-accent: #04222f;
    /* Destaque (amarelo) — chamadas pontuais, badges de marca */
    --color-highlight: var(--gold-500);
    --color-highlight-soft: light-dark(var(--gold-100), rgba(243, 177, 22, 0.18));
    --color-on-highlight: #3a2a02;
    /* Link */
    --color-link: light-dark(var(--brand-600), var(--brand-300));
    --color-link-hover: light-dark(var(--brand-800), #a9cbe8);
    /* Estados neutros */
    --color-disabled-bg: light-dark(var(--neutral-150), #22303f);
    --color-disabled-text: light-dark(var(--neutral-400), #5f7183);
    --color-focus-ring: light-dark(rgba(2, 72, 125, 0.35), rgba(81, 136, 186, 0.5));
    /* Sinais */
    --color-success: light-dark(var(--success-500), #34b26e);
    --color-success-soft: light-dark(var(--success-100), rgba(52, 178, 110, 0.16));
    --color-warning: light-dark(var(--warning-500), #e0a030);
    --color-warning-soft: light-dark(var(--warning-100), rgba(224, 160, 48, 0.16));
    --color-danger: light-dark(var(--danger-500), #e26060);
    --color-danger-soft: light-dark(var(--danger-100), rgba(226, 96, 96, 0.16));
    /* Perigo solido — fundo do botao destrutivo (texto branco em ambos os temas) */
    --color-danger-strong: var(--danger-600);
    --color-danger-strong-hover: var(--danger-700);
    --color-on-danger: var(--neutral-0);
    --color-info: light-dark(var(--info-500), #4a93cf);
    --color-info-soft: light-dark(var(--info-100), rgba(74, 147, 207, 0.16));
    /* Logo — papel, nao arquivo: o componente consome sempre estes tres.
     --logo-lockup segue o tema; --logo-lockup-invert e para fundo primario. */
    --logo-lockup: light-dark(var(--brand-logo), var(--brand-logo-branco));
    --logo-lockup-invert: var(--brand-logo-negativo);
    --logo-simbolo: light-dark(var(--brand-simbolo), var(--brand-simbolo-branco));
    --logo-lockup-ratio: 3152 / 709;
}

/* Forcar tema explicitamente (vence a preferencia do SO).
   Sem escopo em :root de proposito: o atributo pode ser aplicado em qualquer
   elemento (ex.: um container renderizado pelo Blazor), e color-scheme,
   por ser herdado, propaga o tema para os descendentes daquele elemento. */
[data-theme="light"] {
    color-scheme: light;
}

[data-theme="dark"] {
    color-scheme: dark;
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — TIPOGRAFIA
   Fontes oficiais do Manual de Marca: Barlow (texto) + Bak Bak (display).
   PRODUCAO: as fontes DEVEM ser self-hosted (woff2 local + @font-face);
   nunca Google Fonts em runtime (politica de CSP/SRI Ibrascan).
   Escala FLUIDA via clamp(min, preferido+vw, max) — responsiva por padrao.
   ========================================================================= */
:root {
    --font-sans: "Barlow", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-display: "Bakbak One", "Barlow", system-ui, sans-serif;
    --font-mono: "JetBrains Mono", "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
    /* Escala fluida (min -> max conforme a viewport) */
    --fs-xs: clamp(0.6875rem, 0.66rem + 0.14vw, 0.75rem); /* 11 -> 12 */
    --fs-sm: clamp(0.75rem, 0.72rem + 0.16vw, 0.8125rem); /* 12 -> 13 */
    --fs-md: clamp(0.8125rem, 0.79rem + 0.16vw, 0.875rem); /* 13 -> 14 */
    --fs-base: clamp(0.875rem, 0.84rem + 0.18vw, 1rem); /* 14 -> 16 */
    --fs-lg: clamp(1rem, 0.95rem + 0.30vw, 1.125rem); /* 16 -> 18 */
    --fs-xl: clamp(1.1875rem, 1.10rem + 0.45vw, 1.375rem); /* 19 -> 22 */
    --fs-2xl: clamp(1.375rem, 1.20rem + 0.90vw, 1.75rem); /* 22 -> 28 */
    --fs-3xl: clamp(1.75rem, 1.40rem + 1.60vw, 2.375rem); /* 28 -> 38 */
    --fs-4xl: clamp(2.25rem, 1.60rem + 2.80vw, 3.25rem); /* 36 -> 52 */

    --fw-light: 300;
    --fw-regular: 400;
    --fw-medium: 500;
    --fw-semibold: 600;
    --fw-bold: 700;
    --lh-tight: 1.2;
    --lh-snug: 1.35;
    --lh-normal: 1.5;
    --lh-relaxed: 1.65;
    --ls-tight: -0.02em;
    --ls-normal: 0;
    --ls-wide: 0.08em;
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — ESPACAMENTO
   Escala base 4px, expressa em rem (acompanha o zoom/acessibilidade).
   ========================================================================= */
:root {
    --sp-0: 0;
    --sp-1: 0.25rem; /* 4  */
    --sp-2: 0.5rem; /* 8  */
    --sp-3: 0.75rem; /* 12 */
    --sp-4: 1rem; /* 16 */
    --sp-5: 1.25rem; /* 20 */
    --sp-6: 1.5rem; /* 24 */
    --sp-7: 2rem; /* 32 */
    --sp-8: 2.5rem; /* 40 */
    --sp-9: 3rem; /* 48 */
    --sp-10: 4rem; /* 64 */
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — RAIOS E BORDA
   ========================================================================= */
:root {
    --radius-sm: 4px;
    --radius-md: 6px;
    --radius-lg: 10px;
    --radius-xl: 14px;
    --radius-full: 999px;
    --border-w: 1px;
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — ELEVACAO
   Sombras adaptam ao tema via light-dark(claro, escuro).
   ========================================================================= */
:root {
    --shadow-xs: 0 1px 2px light-dark(rgba(16, 27, 38, 0.06), rgba(0, 0, 0, 0.40));
    --shadow-sm: 0 1px 3px light-dark(rgba(16, 27, 38, 0.08), rgba(0, 0, 0, 0.45));
    --shadow-md: 0 4px 12px light-dark(rgba(16, 27, 38, 0.10), rgba(0, 0, 0, 0.50));
    --shadow-lg: 0 12px 32px light-dark(rgba(16, 27, 38, 0.14), rgba(0, 0, 0, 0.55));
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — MOVIMENTO
   Respeita prefers-reduced-motion (acessibilidade).
   ========================================================================= */
:root {
    --ease: cubic-bezier(0.4, 0, 0.2, 1);
    --ease-out: cubic-bezier(0, 0, 0.2, 1);
    --dur-fast: 120ms;
    --dur-base: 180ms;
    --dur-slow: 260ms;
    /* Sinal de que o sistema esta trabalhando (indicador de carga). NAO e
       movimento, e por isso NAO se zera abaixo: apaga-la esconde o estado do
       sistema de quem pediu menos movimento. */
    --dur-sinal: 1s;
    --z-base: 1;
    --z-sticky: 100;
    --z-dropdown: 500;
    --z-overlay: 900;
    --z-modal: 1000;
    --z-toast: 1100;
}

/* Movimento reduzido zera SO a duracao de decoracao. A especificacao de Media
   Queries define 'reduce' como remover OU SUBSTITUIR animacao baseada em
   MOVIMENTO e NAO-ESSENCIAL — nao como apagar toda animacao. E a WCAG, no
   criterio 2.2.2 nota 4, trata animacao de carga como ESSENCIAL: sem ela o
   usuario acha que travou.

   Ja custou: zerar --dur-slow aqui matou os tres pontinhos do botao que
   dispara chamada ao servidor. O bloco do componente trocava so o
   animation-name, e herdava a duracao zerada — animacao de duracao zero nao
   tem efeito visivel nenhum. Indicador de atividade usa --dur-sinal, que
   sobrevive a este bloco de proposito. */
@media (prefers-reduced-motion: reduce) {
    :root {
        --dur-fast: 0ms;
        --dur-base: 0ms;
        --dur-slow: 0ms;
    }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — LAYOUT E BASE RESPONSIVA
   WEB/DESKTOP-FIRST: o alvo primario e o navegador no PC; o layout e otimizado
   pra web. Responsivo e OBRIGATORIO (tablet/celular sempre funcionam — acesso
   de emergencia sem PC), mas o desktop manda. Fluido (rem + clamp), poucos
   breakpoints; adapta pra baixo. Nunca um CSS por resolucao.
   ========================================================================= */
:root {
    /* Breakpoints — lista fechada da v3: 480, 640, 768, 900, 1024. Os tokens
     abaixo sao so documentacao: var() nao funciona dentro da condicao de um
     @media, entao cada componente repete o valor literal no proprio arquivo.
     640 e 900 nao tem token proprio — nomeie-os pelo numero direto no @media. */
    --bp-sm: 480px; /* celular grande */
    --bp-md: 768px; /* tablet */
    --bp-lg: 1024px; /* laptop */
    /* Altura padrao de controles — botao/input/select alinhados */
    --control-h: 36px;
    --control-h-sm: 30px;
    --control-h-lg: 46px;
    /* Dimensoes de shell */
    --sidebar-w: 248px;
    --sidebar-w-mini: 64px;
    --topbar-h: 80px;
    --content-max: 1440px;
}

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

html {
    font-size: 100%;
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    font-family: var(--font-sans);
    font-size: var(--fs-base);
    line-height: var(--lh-normal);
    color: var(--color-text);
    background: var(--color-bg);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

main {
    min-height: 100vh;
    background: var(--color-bg);
    color: var(--color-text);
    border-bottom: 1px solid var(--color-border);
}

header {
    background: var(--color-bg);
    width: 100%;
    color: var(--color-text);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--sp-4) var(--sp-7);
    border-bottom: var(--border-w) solid var(--color-border);
    z-index: 1000;
}

/* Link nu — sem isso o navegador aplica o proprio azul, fora do tema. */
a {
    color: var(--color-link);
    text-decoration-color: color-mix(in oklab, currentColor 40%, transparent);
    text-underline-offset: 2px;
}

a:hover {
    color: var(--color-link-hover);
    text-decoration-color: currentColor;
}

:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

/* Foco só por programa (ex.: FocusOnNavigate do Blazor pousando tabindex="-1"
   no h1 a cada navegação) não ganha anel — não é alvo de navegação por
   teclado. Interativo real (Tab, botão, link, campo) mantém o anel acima. */
[tabindex="-1"]:focus, [tabindex="-1"]:focus-visible {
    outline: none;
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — UTILITARIOS
   Vocabulario generico de layout (pilha, linha, grade) + apoio de tipografia
   para compor telas sem reinventar a mesma receita a cada componente novo.
   Token-only.

   .stack        pilha vertical, gap padrao (--sp-4). Use dentro de qualquer
                 contêiner menor — card, modal, secao — para empilhar campos
                 e blocos. Nao confundir com .content-stack (shell.css), que
                 e especifico para empilhar os blocos de uma pagina inteira
                 (ver guidelines/02-fundamentos.card.html).
     .stack-sm   gap --sp-2
     .stack-lg   gap --sp-6

   .row          linha horizontal, alinhada e com quebra automatica
                 (flex-wrap). Uso geral: agrupar botoes, campos, badges.
     .row-tight  gap --sp-2, para elementos mais proximos
     .row-between  acrescenta justify-content:space-between — o padrao de
                 barra titulo+acoes que .page-head/.card-header/.modal-header/
                 .ev-header ja repetem cada um com nome proprio.

   .grid-2/3/4   grade de colunas fixas e iguais. Adapta pra baixo: grid-3 e
                 grid-4 caem para 2 colunas em --bp-lg e 1 coluna em --bp-md;
                 grid-2 cai para 1 coluna em --bp-sm.

   .grid-auto    grade auto-ajustavel, generaliza a receita que .ev-fields/
                 .stat-row repetem cada um com seu proprio nome. O minimo da
                 coluna se ajusta por variavel inline, sem CSS novo:
                 style="--grid-min:260px".

   .gap-1..6     escala de gap avulso para ajuste fino de .row/.stack/.grid*,
                 sem precisar de mais um modificador nomeado. Sem !important:
                 estas classes devem vir DEPOIS de .row/.stack/.grid* na lista
                 de classes do elemento, para vencer por ordem de declaracao.

   .p-0..10      escala de padding avulso, todos os lados, um por token de
                 tokens/spacing.css (--sp-0 a --sp-10). Uso geral: dar respiro
                 a um bloco sem escrever padding inline nem criar componente
                 novo so para isso. Extensao local do essentials, nao vem do
                 Design System.

   .cell-stack   par de linhas empilhadas numa mesma celula/campo: valor
                 principal (.cell-stack-main) em cima e detalhe secundario
                 (.cell-stack-sub) embaixo (ex.: Razao Social + CNPJ na mesma
                 coluna). Compartilhado — serve em <td>, lista ou card, onde
                 precisar de dois niveis de leitura. Numeros/documentos ganham
                 tabular-nums para alinhar.

   .text-*       apoio de tipografia para ajuste pontual de um trecho de
                 texto — familia (.text-sans/.text-mono/.tabular-nums),
                 tamanho (.text-xs..lg, mapeia --fs-*), peso (.fw-regular..
                 bold, mapeia --fw-*), cor por papel semantico (.text-muted/
                 .text-subtle/.text-primary/.text-danger) e alinhamento
                 (.text-left/.text-center/.text-right). Nao substitui a
                 tipografia propria de um componente.

   .bg-*         fundo por superficie semantica (.bg-page/.bg-surface/
                 .bg-surface-2) e por sinal (.bg-{primary,success,warning,
                 danger,info}-soft). Nao substitui a superficie propria de um
                 componente.

   .uppercase    forca text-transform:uppercase num trecho de texto. Extensao
                 local do essentials, nao vem do Design System.

   .sr-only      texto que so leitor de tela le, ou elemento focavel que
                 precisa existir no layout de tabulacao sem aparecer na tela
                 (sentinela de foco de dialogo, rotulo de acessibilidade).
                 Nunca display:none nem visibility:hidden — as duas tirariam
                 o elemento da ordem de tabulacao, que e o motivo dele existir.
   ========================================================================= */
.stack {
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
}

.stack-sm {
    gap: var(--sp-2);
}

.stack-lg {
    gap: var(--sp-6);
}

.row {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    flex-wrap: wrap;
}

.row-tight {
    gap: var(--sp-2);
}

.row-between {
    justify-content: space-between;
}

.grid-2 {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--sp-4);
}

.grid-3 {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--sp-4);
}

.grid-4 {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--sp-4);
}

.grid-auto {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(var(--grid-min, 220px), 1fr));
    gap: var(--sp-4);
}

@media (max-width: 1024px) {
    .grid-3, .grid-4 {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 768px) {
    .grid-3, .grid-4 {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 480px) {
    .grid-2 {
        grid-template-columns: 1fr;
    }
}

.gap-1 {
    gap: var(--sp-1);
}

.gap-2 {
    gap: var(--sp-2);
}

.gap-3 {
    gap: var(--sp-3);
}

.gap-4 {
    gap: var(--sp-4);
}

.gap-5 {
    gap: var(--sp-5);
}

.gap-6 {
    gap: var(--sp-6);
}

.p-0 {
    padding: var(--sp-0);
}

.p-1 {
    padding: var(--sp-1);
}

.p-2 {
    padding: var(--sp-2);
}

.p-3 {
    padding: var(--sp-3);
}

.p-4 {
    padding: var(--sp-4);
}

.p-5 {
    padding: var(--sp-5);
}

.p-6 {
    padding: var(--sp-6);
}

.p-7 {
    padding: var(--sp-7);
}

.p-8 {
    padding: var(--sp-8);
}

.p-9 {
    padding: var(--sp-9);
}

.p-10 {
    padding: var(--sp-10);
}

/* Par de linhas numa mesma celula/campo — valor principal + detalhe secundario. */
.cell-stack {
    display: inline-flex;
    flex-direction: column;
    gap: var(--sp-1);
    line-height: var(--lh-tight);
    text-align: left;
}

.cell-stack-main {
    color: var(--color-text);
}

.cell-stack-sub {
    font-size: var(--fs-sm);
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}

/* -------------------------------------------------------------------------
   APOIO DE TIPOGRAFIA
   Conjunto CURADO (nao um framework aberto): so o que se repetia como classe
   local por tela. Ajuste pontual de fonte/tamanho/peso/cor em trecho de texto
   que nao justifica um componente. Sempre token-only. Componente proprio
   define sua tipografia na propria folha — nao empilhar estas ali.
   ------------------------------------------------------------------------- */

/* Familia */
.text-sans {
    font-family: var(--font-sans);
}

.text-mono {
    font-family: var(--font-mono);
}

.tabular-nums {
    font-variant-numeric: tabular-nums;
}

/* Tamanho (mapeia --fs-*) */
.text-xs {
    font-size: var(--fs-xs);
}

.text-sm {
    font-size: var(--fs-sm);
}

.text-md {
    font-size: var(--fs-md);
}

.text-base {
    font-size: var(--fs-base);
}

.text-lg {
    font-size: var(--fs-lg);
}

/* Peso (mapeia --fw-*) */
.fw-regular {
    font-weight: var(--fw-regular);
}

.fw-medium {
    font-weight: var(--fw-medium);
}

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

.fw-bold {
    font-weight: var(--fw-bold);
}

/* Cor de texto (papeis semanticos) */
.text-muted {
    color: var(--color-text-muted);
}

.text-subtle {
    color: var(--color-text-subtle);
}

.text-primary {
    color: var(--color-primary);
}

.text-danger {
    color: var(--color-danger);
}

/* Fundo — so superficie semantica (segue o tema). Nao substitui a superficie
   propria de um componente (.card, .alert, .badge); sinal usa o -soft. */
.bg-page {
    background: var(--color-bg);
}

.bg-surface {
    background: var(--color-surface);
}

.bg-surface-2 {
    background: var(--color-surface-2);
}

.bg-primary-soft {
    background: var(--color-primary-soft);
}

.bg-success-soft {
    background: var(--color-success-soft);
}

.bg-warning-soft {
    background: var(--color-warning-soft);
}

.bg-danger-soft {
    background: var(--color-danger-soft);
}

.bg-info-soft {
    background: var(--color-info-soft);
}

/* Alinhamento */
.text-left {
    text-align: left;
}

.text-center {
    text-align: center;
}

.text-right {
    text-align: right;
}

.uppercase {
    text-transform: uppercase;
}

/* Texto só para leitor de tela, ou elemento focável mantido fora da tela.
   Sem display:none e sem visibility:hidden — as duas removeriam o elemento
   da ordem de tabulacao. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — SHELL (sidebar + topbar + conteudo)
   Frame das telas de backoffice. Consome dims de tokens/layout.css.
   Base fixa em 100vh, com colapso da sidebar em telas largas (>=900px) e
   painel deslizante em telas estreitas (<900px). Desktop-first.
   ========================================================================= */
.app-shell {
    display: grid;
    grid-template-columns: 1fr;
    grid-template-rows: 100vh;
    min-height: 100vh;
    background: var(--color-bg);
}

.sidebar {
    display: flex;
    flex-direction: column;
    gap: 0;
    padding: 0;
    overflow: hidden;
    background: var(--color-surface);
    border-right: var(--border-w) solid var(--color-border);
}

/* -------------------------------------------------------------------------
   MARCA — cabeçalho fixo da sidebar, com altura igual à do topbar
   ------------------------------------------------------------------------- */
.sidebar-brand {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    height: var(--topbar-h);
    padding: 0 var(--sp-4);
    flex: none;
    border-bottom: var(--border-w) solid var(--color-border);
}

.sidebar-brand-mark {
    height: 30px;
    width: auto;
    flex: none;
    display: block;
    background: none;
    border-radius: 0;
}

/* Variante escura do símbolo de marca, trocada por tema — ver seção de tema no fim do arquivo */
.sidebar-brand-mark-dark {
    display: none;
}

.sidebar-brand-logo {
    object-fit: contain;
    width: 50px;
    border-radius: var(--radius-md);
    flex: none;
}

.sidebar-brand-text {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}

.sidebar-brand-name {
    font-family: var(--font-display);
    font-size: var(--fs-xl);
    letter-spacing: var(--ls-tight);
    color: var(--color-text);
    line-height: 1.2;
}

/* Rótulo do portal — identifica qual dos portais do produto esta sidebar representa */
.sidebar-brand-portal {
    font-family: var(--font-sans);
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: var(--ls-wide);
    text-transform: uppercase;
    color: var(--color-text-muted);
}

/* -------------------------------------------------------------------------
   NAVEGAÇÃO — área rolável da sidebar, abaixo da marca
   ------------------------------------------------------------------------- */
.sidebar-nav {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: var(--sp-3) var(--sp-2);
}

.nav-group {
    margin-bottom: var(--sp-4);
}

.nav-section {
    margin-top: 0;
    padding: 0 var(--sp-3) var(--sp-2);
    font-size: var(--fs-xs);
    font-weight: var(--fw-semibold);
    text-transform: uppercase;
    letter-spacing: var(--ls-wide);
    color: var(--color-text-subtle);
}

.nav-link {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-3);
    margin-bottom: 2px;
    border-radius: var(--radius-md);
    color: var(--color-text-muted);
    text-decoration: none;
    font-size: var(--fs-base);
    font-weight: var(--fw-medium);
    white-space: nowrap;
}

    .nav-link:hover {
        background: var(--color-surface-hover);
        color: var(--color-text);
    }

    .nav-link.is-active {
        background: var(--color-primary-soft);
        color: var(--color-primary);
    }

    .nav-link svg {
        width: 18px;
        height: 18px;
        flex: none;
    }

    .nav-link .icon {
        width: 18px;
        height: 18px;
        flex: none;
    }

    .nav-link .nav-label {
        flex: 1 1 auto;
    }

    /* Contador no item de menu (ex.: pendências) */
    .nav-link .nav-count {
        font-size: var(--fs-xs);
        font-weight: var(--fw-semibold);
        padding: 1px 7px;
        border-radius: var(--radius-full);
        background: var(--color-surface-hover);
        color: var(--color-text-muted);
    }

    .nav-link.is-active .nav-count {
        background: var(--color-primary);
        color: var(--color-on-primary);
    }

    /* Notificacao: pendencia que pede acao. Sinal fixo, nao muda no item ativo. */
    .nav-link .nav-count.is-alert {
        background: var(--color-danger-strong);
        color: var(--color-on-danger);
        font-variant-numeric: tabular-nums;
    }

    /* Texto so para leitor de tela (ex.: "pendentes") */
    .nav-count-sr {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

/* -------------------------------------------------------------------------
   ÁREA PRINCIPAL — topbar fixo + conteúdo rolável
   ------------------------------------------------------------------------- */
/* Coluna principal (a celula da grade ao lado da sidebar). Ela mesma rola; o
   .topbar fica preso no topo (sticky) e o .content-inner cresce abaixo dele.
   Fundacao: .app-shell > .sidebar + main.content > (header.topbar + .content-inner) */
.content {
    display: flex;
    flex-direction: column;
    min-width: 0;
    height: 100vh;
    overflow-y: auto;
    /* Nunca rolagem horizontal na pagina, nem por elemento fora do fluxo
       que fica invisivel mas ainda ocupa layout (ex.: balao de tooltip via
       ::after com content: attr()). */
    overflow-x: hidden;
}

.topbar {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    min-width: 0;
    flex: none;
    height: var(--topbar-h);
    padding: 0 var(--sp-5);
    position: sticky;
    top: 0;
    z-index: var(--z-sticky);
    background: var(--color-surface);
    border-bottom: var(--border-w) solid var(--color-border);
    container: topbar / inline-size;
}

/* Botão de recolher a sidebar — só existe em telas largas; ver responsivo */
.topbar-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    flex: none;
    border: 0;
    background: none;
    cursor: pointer;
    border-radius: var(--radius-md);
    color: var(--color-text-muted);
}

    .topbar-toggle:hover {
        background: var(--color-surface-hover);
        color: var(--color-text);
    }

.topbar-search {
    flex: 0 1 360px;
    min-width: 0;
}

    .topbar-search .field {
        min-width: 0;
    }

    .topbar-search .input-container {
        background: var(--color-surface-2);
        border-color: transparent;
    }

        .topbar-search .input-container:focus-within {
            background: var(--color-surface);
            border-color: var(--color-primary);
        }

.topbar-spacer {
    flex: 1;
}

/* Miolo rolavel: respiro e largura maxima de leitura vivem aqui, nao no topbar.
   Cresce para ocupar a altura restante mesmo com pouco conteudo. */
.content-inner {
    flex: 1 1 auto;
    width: 100%;
    max-width: var(--content-max);
    margin: 0 auto;
    padding: var(--sp-6) var(--sp-7);
}

.page-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--sp-4);
    margin: 0 0 var(--sp-6);
    flex-wrap: wrap;
}

    /* Trilha dentro do cabecalho: filha direta do .page-head ocupa a primeira
       linha inteira; titulo e acoes dividem a linha de baixo, alinhados. Se a
       trilha vier acima do .page-head (irma), tambem vale. */
    .page-head > .breadcrumb {
        flex: 1 0 100%;
    }

    .page-head .breadcrumb {
        margin-bottom: var(--sp-2);
    }

.page-title {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    min-height: var(--control-h);
    margin: 0;
    font-size: var(--fs-2xl);
    font-weight: var(--fw-bold);
    line-height: var(--lh-tight);
    letter-spacing: var(--ls-tight);
}
/* Identificacao do registro sob o titulo (numero, versao, situacao) */
.page-subtitle {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    flex-wrap: wrap;
    margin: var(--sp-1) 0 0;
    font-size: var(--fs-base);
    color: var(--color-text-muted);
}

/* Acoes na linha do titulo: mesma altura da primeira linha do .page-head e
   alinhadas ao topo, entao o centro do botao bate com o centro do titulo. */
.page-actions {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-2);
    min-height: var(--control-h);
}
/* Blocos empilhados de uma tela (cards, alertas, secoes): ritmo unico */
.content-stack {
    display: flex;
    flex-direction: column;
    gap: var(--sp-5);
}

/* -------------------------------------------------------------------------
   GRADES DE CONTEÚDO — colunas fixas para cartão, formulário e listagem
   ------------------------------------------------------------------------- */
.grid {
    display: grid;
    gap: var(--sp-5);
}

.grid-2 {
    grid-template-columns: repeat(2, 1fr);
}

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

.grid-4 {
    grid-template-columns: repeat(4, 1fr);
}

.stat-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--sp-4);
    margin-bottom: var(--sp-5);
}

.stat {
    padding: var(--sp-5);
}

.stat-label {
    font-size: var(--fs-xs);
    font-weight: var(--fw-semibold);
    letter-spacing: var(--ls-wide);
    text-transform: uppercase;
    color: var(--color-text-subtle);
}

.stat-value {
    font-size: var(--fs-2xl);
    font-weight: var(--fw-bold);
    letter-spacing: var(--ls-tight);
    margin-top: var(--sp-2);
}

/* =========================================================================
   NAVEGACAO EM TELA ESTREITA (<900px)
   Abaixo de 900px a sidebar vira painel deslizante, aberto pelo hamburguer do
   topbar: navegacao nunca desaparece sem substituto (o celular e acesso de
   emergencia e precisa alcancar qualquer destino). Tablet retrato (834px)
   tambem cai aqui — 586px de conteudo ao lado da sidebar era estreito demais.
   No Blazor: .is-open por binding; backdrop e Esc fecham.
   ========================================================================= */
.sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: var(--z-modal);
    width: min(var(--sidebar-w), 84vw);
    overflow-y: auto;
    visibility: hidden;
    transform: translateX(-100%);
    transition: transform var(--dur-base) var(--ease-out), visibility var(--dur-base);
}

    .sidebar.is-open {
        visibility: visible;
        transform: translateX(0);
    }

.nav-backdrop {
    position: fixed;
    inset: 0;
    z-index: var(--z-overlay);
    background: var(--color-overlay);
    border: 0;
    padding: 0;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur-base) var(--ease);
}

    .nav-backdrop.is-open {
        opacity: 1;
        pointer-events: auto;
    }

.nav-toggle {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--control-h);
    height: var(--control-h);
    border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    color: var(--color-text-muted);
    cursor: pointer;
}

    .nav-toggle:hover {
        background: var(--color-surface-hover);
        color: var(--color-text);
    }

    .nav-toggle svg {
        width: 20px;
        height: 20px;
    }

.sidebar-close {
    flex: none;
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 0;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--color-text-muted);
    cursor: pointer;
}

    .sidebar-close:hover {
        background: var(--color-surface-hover);
        color: var(--color-text);
    }

    .sidebar-close svg {
        width: 18px;
        height: 18px;
    }

/* =========================================================================
   DESKTOP (>=900px) — sidebar estática, trilho mini de colapso
   ========================================================================= */
@media (min-width: 900px) {
    .app-shell {
        grid-template-columns: var(--sidebar-w) 1fr;
    }

    .sidebar {
        position: static;
        width: auto;
        overflow: visible;
        visibility: visible;
        transform: none;
        z-index: auto;
        transition: none;
    }

    .nav-toggle, .sidebar-close, .nav-backdrop {
        display: none;
    }

    .topbar {
        gap: var(--sp-4);
    }

    /* Trilho mini: a sidebar encolhe para largura fixa e some com rótulo e contador */
    .app-shell.is-collapsed {
        grid-template-columns: var(--sidebar-w-mini) 1fr;
    }

        .app-shell.is-collapsed .sidebar-brand {
            justify-content: center;
            padding: 0;
        }

        .app-shell.is-collapsed .sidebar-brand-text {
            display: none;
        }

        .app-shell.is-collapsed .nav-section {
            visibility: hidden;
            height: var(--sp-3);
        }

        .app-shell.is-collapsed .nav-link {
            justify-content: center;
            padding: var(--sp-2);
        }

            /* Recolhida, o texto e o numero saem da tela mas continuam lidos por leitor
               de tela: display:none os tiraria da arvore de acessibilidade e o link
               ficaria sem nome. */
            .app-shell.is-collapsed .nav-link .nav-label,
            .app-shell.is-collapsed .nav-link .nav-count:not(.is-alert) {
                position: absolute;
                width: 1px;
                height: 1px;
                padding: 0;
                margin: -1px;
                overflow: hidden;
                clip: rect(0 0 0 0);
                white-space: nowrap;
                border: 0;
            }

        /* Recolhida: a notificacao vira ponto sobre o icone — o aviso nao some */
        .app-shell.is-collapsed .nav-link {
            position: relative;
        }

        .app-shell.is-collapsed .nav-link .nav-count.is-alert {
            position: absolute;
            top: 4px;
            right: 6px;
            width: 10px;
            height: 10px;
            padding: 0;
            font-size: 0;
            box-shadow: 0 0 0 2px var(--color-surface);
        }
}

/* O botão de recolher é do desktop; em tela estreita quem abre é o .nav-toggle */
@media (max-width: 899.98px) {
    .topbar-toggle {
        display: none;
    }
}

@media (max-width: 768px) {
    .topbar-search {
        flex: 1 1 auto;
    }

    .grid-2, .grid-3, .grid-4 {
        grid-template-columns: 1fr;
    }
}

/* Troca de ASSET por tema (símbolo de marca) — não é cor, light-dark() não se aplica */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .sidebar-brand-mark-light {
        display: none;
    }

    :root:not([data-theme="light"]) .sidebar-brand-mark-dark {
        display: block;
    }
}

:root[data-theme="dark"] .sidebar-brand-mark-light {
    display: none;
}

:root[data-theme="dark"] .sidebar-brand-mark-dark {
    display: block;
}

/* =========================================================================
   CORRECAO DA FUNDACAO — ausente no Design System (commit 07cf701).
   overflow-y:auto forca overflow-x:auto; filho mais largo que o trilho
   recolhido reabriria a barra horizontal na propria sidebar.
   ========================================================================= */
@media (min-width: 900px) {
    .app-shell.is-collapsed .nav-section {
        overflow: hidden;
    }

    .app-shell.is-collapsed .sidebar-nav {
        overflow-x: hidden;
    }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — DROPDOWN / MENU
   Base no essentials (.dropdown/.dropdown-toggle/.dropdown-menu/.dropdown-item),
   refinado: token-only, dark, + separador e rotulo de secao.
   ========================================================================= */
.dropdown {
  position: relative;
  display: inline-block;
}

/* Extensao local (nao vem do design system original): abrir/fechar generico
   para qualquer botao de dropdown reutilizavel (BotaoDropdown, em
   Componentes/V3/Formularios). .user-menu/.tenant-switch tem mecanica propria,
   escopada e responsiva por container query, em user-menu.css — nao usam
   esta classe, para não colidir com o alinhamento delas. */
.btn-dropdown > .menu {
  position: absolute;
  top: calc(100% + var(--sp-2));
  left: 0;
  z-index: 40;
  display: none;
}
.btn-dropdown.is-open > .menu {
  display: block;
}
.btn-dropdown.is-aligned-right > .menu {
  left: auto;
  right: 0;
}

.menu {
  min-width: 200px;
  padding: var(--sp-1);
  background: var(--color-surface);
  border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
}
.menu-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  padding: var(--sp-2) var(--sp-3);
  border: 0;
  background: none;
  cursor: pointer;
  text-align: left;
  text-decoration: none;
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  color: var(--color-text);
  border-radius: var(--radius-sm);
}
.menu-item:hover {
  background: var(--color-surface-hover);
}
.menu-item .menu-glyph {
  width: 16px;
  height: 16px;
  flex: none;
  color: var(--color-text-muted);
}
.menu-item.is-danger {
  color: var(--color-danger);
}
.menu-item.is-danger .menu-glyph {
  color: var(--color-danger);
}
.menu-sep {
  height: 1px;
  background: var(--color-border);
  margin: var(--sp-1) 0;
}
.menu-label {
  padding: var(--sp-2) var(--sp-3) var(--sp-1);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--color-text-subtle);
  text-transform: uppercase;
  letter-spacing: var(--ls-wide);
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — IDENTIDADE NO TOPBAR
   Dois controles distintos, ambos no topbar (unica faixa que sobrevive ao
   mobile — a sidebar colapsa em <=768px):
     .tenant-switch  ESQUERDA — escopo dos dados (qual tenant estou operando)
     .user-menu      DIREITA  — identidade (quem sou, tema, sessao)
   Abertura por classe .is-open no wrapper (no Blazor: @onclick + campo bool).
   Reusa .menu / .menu-item / .menu-sep / .menu-label de dropdown.css.
   ========================================================================= */

/* Posicionamento comum dos paineis ancorados no topbar. Nunca ultrapassa a
   tela: cabem na altura util (topbar + respiro) e rolam por dentro se preciso. */
.tenant-switch .menu,
.user-menu .menu {
  position: absolute; top: calc(100% + var(--sp-2)); z-index: var(--z-dropdown); display: none;
  max-height: calc(100vh - var(--topbar-h) - var(--sp-6)); overflow-y: auto;
}
.tenant-switch.is-open .menu,
.user-menu.is-open .menu { display: block; }
/* Ancoragem horizontal: tenant abre pela esquerda, usuario pela direita. O
   `.dropdown.<wrapper>` sobe a especificidade para vencer o `.dropdown > .menu
   { left: 0 }` de dropdown.css seja qual for a ordem de carga das folhas —
   sem isso os dois `left` e `right` valem juntos e o painel vaza pra fora. */
.dropdown.tenant-switch > .menu { left: 0; right: auto; }
.dropdown.user-menu > .menu { left: auto; right: 0; }

/* -------------------------------------------------------------------------
   GATILHO DO USUARIO (direita do topbar)
   ------------------------------------------------------------------------- */
.user-menu { flex: none; max-width: 100%; }
.user-trigger {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  height: var(--control-h); max-width: min(220px, 100%); padding: var(--sp-1) var(--sp-2);
  border: var(--border-w) solid transparent; border-radius: var(--radius-md);
  background: none; cursor: pointer; font-family: var(--font-sans); color: var(--color-text); text-align: left;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.user-trigger:hover { background: var(--color-surface-hover); }
.user-menu.is-open .user-trigger { background: var(--color-surface-hover); border-color: var(--color-border); }
.user-trigger-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.user-trigger-name { font-size: var(--fs-sm); font-weight: var(--fw-medium); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-trigger-role { font-size: var(--fs-xs); color: var(--color-text-subtle); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Contador de papeis extras no gatilho — “Financeiro +1” (nunca “2 papéis”) */
.user-trigger-role-more { font-weight: var(--fw-semibold); color: var(--color-text-muted); }
.user-trigger-chevron { width: 16px; height: 16px; flex: none; color: var(--color-text-subtle); }

/* -------------------------------------------------------------------------
   PAINEL DO USUARIO
   ------------------------------------------------------------------------- */
.user-panel { min-width: 268px; }
.user-identity { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3); }
.user-identity-text { display: flex; flex-direction: column; min-width: 0; gap: 2px; }
.user-identity-name { font-size: var(--fs-base); font-weight: var(--fw-semibold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-identity-mail { font-size: var(--fs-sm); color: var(--color-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-identity-role {
  align-self: flex-start; margin: 0 var(--sp-3) var(--sp-2);
  padding: 2px var(--sp-2); border-radius: var(--radius-full);
  background: var(--color-primary-soft); color: var(--color-primary);
  font-size: var(--fs-xs); font-weight: var(--fw-semibold); letter-spacing: var(--ls-wide); text-transform: uppercase;
}
/* Mais de um papel: os papeis sao acumulativos (a permissao e a uniao deles),
   nunca um contexto que se troca. Todos aparecem no painel, com o mesmo peso. */
.user-identity-roles { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin: 0 var(--sp-3) var(--sp-2); }
.user-identity-roles .user-identity-role { margin: 0; }

/* Preferencia do usuario dentro do painel — trilha segmentada de 2 a 3 opcoes
   (Tema: Auto/Claro/Escuro · Ajudas: Ligadas/Desligadas). O trilho em si (o
   crescimento e o alinhamento das opcoes) e responsabilidade do componente
   Segmented (selecao.css/.segmented, variante .segmented-block quando precisa
   ocupar a largura toda) — aqui so a moldura que o acomoda na linha do menu. */
.user-choice { margin: 0 var(--sp-3) var(--sp-2); }

/* -------------------------------------------------------------------------
   GATILHO DE TENANT (esquerda do topbar)
   ------------------------------------------------------------------------- */
.tenant-switch { flex: none; max-width: 100%; }
.tenant-trigger {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  height: var(--control-h); max-width: min(260px, 100%); padding: var(--sp-1) var(--sp-2);
  border: var(--border-w) solid var(--color-border); border-radius: var(--radius-md);
  background: var(--color-surface); cursor: pointer; font-family: var(--font-sans); color: var(--color-text); text-align: left;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.tenant-trigger:hover { background: var(--color-surface-hover); border-color: var(--color-border-strong); }
.tenant-switch.is-open .tenant-trigger { border-color: var(--color-primary); }
.tenant-mark {
  display: grid; place-items: center; flex: none; width: 24px; height: 24px; overflow: hidden;
  border-radius: var(--radius-sm); background: var(--color-accent-soft); color: var(--color-accent-hover);
  font-size: var(--fs-xs); font-weight: var(--fw-bold);
}
.tenant-mark img { width: 100%; height: 100%; object-fit: contain; }
.tenant-trigger-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
.tenant-trigger-label { font-size: var(--fs-xs); color: var(--color-text-subtle); letter-spacing: var(--ls-wide); text-transform: uppercase; }
.tenant-trigger-name { font-size: var(--fs-sm); font-weight: var(--fw-medium); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tenant-trigger-chevron { width: 16px; height: 16px; flex: none; color: var(--color-text-subtle); }

/* Tenant unico — sem troca possivel: mesma caixa, sem gatilho */
.tenant-static {
  display: inline-flex; align-items: center; gap: var(--sp-2); height: var(--control-h); max-width: 260px;
  padding: var(--sp-1) var(--sp-2); border-radius: var(--radius-md); color: var(--color-text-muted);
}

/* -------------------------------------------------------------------------
   PAINEL DE TENANT
   ------------------------------------------------------------------------- */
.tenant-menu { min-width: 320px; }
.tenant-search { padding: var(--sp-2) var(--sp-2) var(--sp-3); }
.tenant-list { max-height: 264px; overflow-y: auto; }
.tenant-item { align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-3); }
.tenant-item-text { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; gap: 2px; }
.tenant-item-name { font-size: var(--fs-base); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tenant-item-meta { font-size: var(--fs-xs); color: var(--color-text-subtle); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tenant-item-check { width: 16px; height: 16px; flex: none; color: var(--color-primary); visibility: hidden; }
.tenant-item.is-current { background: var(--color-primary-soft); }
.tenant-item.is-current .tenant-item-name { font-weight: var(--fw-semibold); color: var(--color-primary); }
.tenant-item.is-current .tenant-item-check { visibility: visible; }
.tenant-empty { padding: var(--sp-4) var(--sp-3); font-size: var(--fs-sm); color: var(--color-text-subtle); text-align: center; }

/* Skeleton enquanto a lista de tenants carrega */
.tenant-item.is-loading { pointer-events: none; }
.tenant-item.is-loading .tenant-mark,
.tenant-item.is-loading .tenant-item-name,
.tenant-item.is-loading .tenant-item-meta { color: transparent; background: var(--color-surface-hover); border-radius: var(--radius-sm); }
.tenant-item.is-loading .tenant-item-name { width: 62%; height: 12px; }
.tenant-item.is-loading .tenant-item-meta { width: 38%; height: 10px; }

/* -------------------------------------------------------------------------
   ADAPTA PRA BAIXO — o gatilho encolhe pela largura do TOPBAR (container
   query), nao pela do viewport: o mesmo topbar estreito responde igual dentro
   de um card de documentacao, num tablet com sidebar ou num celular.
   Sobra sempre a essencia: marca do tenant e avatar do usuario.
   ------------------------------------------------------------------------- */
@container topbar (max-width: 620px) {
  .tenant-trigger { max-width: 100%; }
  .tenant-trigger-label { display: none; }
  .user-trigger-text { display: none; }
  .tenant-menu { min-width: 260px; }
  .user-panel { min-width: 240px; }
}
@container topbar (max-width: 420px) {
  .tenant-trigger-text { display: none; }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — BOTAO
   Vocabulario do essentials (.btn-action + variantes), REFINADO:
   token-only, dark-ready, estados completos. Loader lds-ellipsis mantido
   (padrao atual do essentials), tokenizado.
   Mudanca vs essentials: primario era preto (--primary: black) -> agora azul
   da marca (--color-primary). Seletor .btn-action-small corrigido.
   ========================================================================= */

.btn-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    font-family: var(--font-sans);
    font-size: var(--fs-base);
    font-weight: var(--fw-medium);
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    text-decoration: none;
    user-select: none;
    height: var(--control-h);
    padding: 0 var(--sp-4);
    border: var(--border-w) solid transparent;
    border-radius: var(--radius-lg);
    background: var(--color-surface);
    color: var(--color-text);
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}

    .btn-action:hover {
        background: var(--color-surface-hover);
    }

    .btn-action:focus-visible {
        outline: none;
        box-shadow: 0 0 0 3px var(--color-focus-ring);
    }

    .btn-action .btn-glyph {
        width: 18px;
        height: 18px;
        flex: none;
    }

/* Primario — marca (era preto no essentials; agora azul institucional) */
.btn-action-primary {
    background: var(--color-primary);
    color: var(--color-on-primary);
    border-color: var(--color-primary);
}

    .btn-action-primary:hover {
        background: var(--color-primary-hover);
        border-color: var(--color-primary-hover);
        color: var(--color-on-primary);
    }

    .btn-action-primary:active {
        background: var(--color-primary-active);
    }

/* Contornado (secundario) */
.btn-action-transparent {
    background: transparent;
    border-color: var(--color-border-strong);
    color: var(--color-text);
}

    .btn-action-transparent:hover {
        background: var(--color-surface-hover);
    }

/* Sem borda (terciario / ghost) */
.btn-action-transparent-borderless {
    background: transparent;
    color: var(--color-text-muted);
}

    .btn-action-transparent-borderless:hover {
        background: var(--color-surface-hover);
        color: var(--color-text);
    }

/* Perigo solido — acao destrutiva confirmada (ex.: Excluir no modal). Fundo vermelho, texto branco. */
.btn-action-danger {
    background: var(--color-danger-strong);
    color: var(--color-on-danger);
    border-color: var(--color-danger-strong);
}

    .btn-action-danger:hover {
        background: var(--color-danger-strong-hover);
        border-color: var(--color-danger-strong-hover);
        color: var(--color-on-danger);
    }

    .btn-action-danger:active {
        background: var(--color-danger-strong-hover);
    }

/* Perigo transparente — acao destrutiva secundaria/ghost (ex.: icone de excluir na linha da tabela) */
.btn-action-danger-transparent {
    background: transparent;
    color: var(--color-danger);
}

    .btn-action-danger-transparent:hover {
        background: var(--color-danger-soft);
    }

/* Tamanhos (corrige o seletor descendente do essentials) */
.btn-action.btn-action-small {
    height: var(--control-h-sm);
    padding: 0 var(--sp-3);
    font-size: var(--fs-sm);
    gap: var(--sp-1);
}

    .btn-action.btn-action-small .btn-glyph {
        width: 15px;
        height: 15px;
    }

.btn-action.btn-action-lg {
    height: var(--control-h-lg);
    padding: 0 var(--sp-5);
    font-size: var(--fs-lg);
}

.btn-action.btn-action-icon {
    width: var(--control-h);
    padding: 0;
}

    .btn-action.btn-action-icon.btn-action-small {
        width: var(--control-h-sm);
    }

.btn-action-block {
    display: flex;
    width: 100%;
}

/* Desabilitado — solido, sem opacidade fraca; vence as variantes */
.btn-action:disabled,
.btn-action.is-disabled {
    cursor: not-allowed;
    pointer-events: none;
    background: var(--color-disabled-bg);
    border-color: var(--color-disabled-bg);
    color: var(--color-disabled-text);
}

.btn-action-transparent-borderless:disabled,
.btn-action-danger-transparent:disabled {
    background: transparent;
    border-color: transparent;
}

/* Loading (REGRA DE OURO) — botao que dispara chamada ao servidor.
   Trocar o conteudo pelo loader e manter o botao disabled. */
.btn-action.is-loading {
    pointer-events: none;
}

.lds-ellipsis {
    display: inline-flex;
    align-items: center;
    gap: 5px;
}

    .lds-ellipsis span {
        width: 6px;
        height: 6px;
        border-radius: var(--radius-full);
        background: currentColor;
        animation: lds-ellipsis var(--dur-slow) infinite alternate;
    }

        .lds-ellipsis span:nth-child(2) {
            animation-delay: 0.15s;
        }

        .lds-ellipsis span:nth-child(3) {
            animation-delay: 0.30s;
        }

@keyframes lds-ellipsis {
    from {
        opacity: 0.3;
        transform: translateY(1px);
    }

    to {
        opacity: 1;
        transform: translateY(-1px);
    }
}

/* Movimento reduzido: sem deslocamento, mas mantem o pulso de opacidade (feedback de carga) */
@keyframes lds-ellipsis-fade {
    from {
        opacity: 0.3;
    }

    to {
        opacity: 1;
    }
}

@media (prefers-reduced-motion: reduce) {
    /* O atalho inteiro se redeclara, com a duracao de sinal. Trocar so o
       animation-name nao basta: a duracao vinha de --dur-slow, que este mesmo
       bloco zera em tokens/motion.css, e animacao de duracao zero nao aparece. */
    .lds-ellipsis span {
        animation: lds-ellipsis-fade var(--dur-sinal) infinite alternate;
    }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — ACCORDION
   Base no essentials (.accordion-container/.accordion-header/-content, estados
   expand/collapse), refinado: chevron SVG (era fonte), token-only, .is-open.
   ========================================================================= */
.accordion {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
}

.accordion-item {
    background: var(--color-surface);
    border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.accordion-header {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    width: 100%;
    padding: var(--sp-4);
    background: var(--color-primary-fill);
    border: 0;
    cursor: pointer;
    text-align: left;
    font-family: var(--font-sans);
    font-size: var(--fs-base);
    font-weight: var(--fw-medium);
    color: var(--color-on-primary-fill);
}

    .accordion-header:hover {
        background: var(--color-primary-fill-hover);
    }

    .accordion-header:focus-visible {
        outline: none;
        box-shadow: inset 0 0 0 2px var(--color-focus-ring);
    }

.accordion-item.is-open .accordion-header {
    border-bottom: var(--border-w) solid var(--color-border);
}

.accordion-title {
    flex: 1;
    min-width: 0;
}

.accordion-chevron {
    width: 18px;
    height: 18px;
    flex: none;
    color: var(--color-on-primary-fill);
    transition: transform var(--dur-base) var(--ease);
}

.accordion-item.is-open .accordion-chevron {
    transform: rotate(180deg);
}

.accordion-content {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--dur-base) var(--ease);
}

.accordion-item.is-open .accordion-content {
    grid-template-rows: 1fr;
}

.accordion-content-inner {
    overflow: hidden;
    min-height: 0;
}

.accordion-content-body {
    padding: var(--sp-4);
    color: var(--color-text-muted);
    font-size: var(--fs-sm);
}

@media (prefers-reduced-motion: reduce) {
    .accordion-content {
        transition-duration: 0s;
    }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — ICONE
   SVG inline (sprite <use> ou markup direto). A geometria usa currentColor,
   entao a cor vem do token semantico aplicado em `color` — nunca do fill/stroke
   do SVG, nunca cor literal. Duas formas de colorir:
     1. Contexto: o icone dentro de um componente ja herda a cor do texto ao
        lado (.menu-item, .btn-action, .alert...). Nao precisa de classe.
     2. Standalone / destoar do texto: some uma classe de cor abaixo.
   Tamanho por classe (nunca width/height inline). Ver guidelines/03-icones.
   ========================================================================= */
.icone { width: 24px; height: 24px; color: var(--color-text); flex: none; }
.icone-sm { width: 16px; height: 16px; }
.icone-md { width: 20px; height: 20px; }
.icone-lg { width: 32px; height: 32px; }

/* Cor — sempre papel semantico. Neutros primeiro, marca e sinais depois. */
.icone-muted   { color: var(--color-text-muted); }
.icone-subtle  { color: var(--color-text-subtle); }
.icone-primary { color: var(--color-primary); }   /* acao/enfase funcional (azul) */
.icone-accent  { color: var(--color-accent); }    /* enfase de marca (ciano) — nao acao */
.icone-highlight { color: var(--color-highlight); } /* chamada pontual (amarelo) */
.icone-success { color: var(--color-success); }
.icone-warning { color: var(--color-warning); }
.icone-danger  { color: var(--color-danger); }    /* acao destrutiva (ex.: excluir) */
.icone-info    { color: var(--color-info); }
.icone-invert  { color: var(--color-text-invert); } /* sobre fundo primario/solido */
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — TOOLTIP
   CSS puro via [data-tooltip]. Fundo usa --color-text e texto --color-text-invert
   (contrasta com a pagina em claro e escuro). .is-shown forca no preview.
   ========================================================================= */
.has-tooltip {
    position: relative;
}

    .has-tooltip::after {
        content: attr(data-tooltip);
        position: absolute;
        bottom: calc(100% + 6px);
        left: 50%;
        transform: translateX(-50%);
        white-space: nowrap;
        font-size: var(--fs-xs);
        font-weight: var(--fw-medium);
        color: var(--color-text-invert);
        background: var(--color-text);
        padding: 4px 8px;
        border-radius: var(--radius-sm);
        opacity: 0;
        pointer-events: none;
        transform: translateX(-50%) translateY(4px);
        transform-origin: bottom center;
        transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
        z-index: var(--z-toast);
    }

    .has-tooltip:hover::after, .has-tooltip:focus-visible::after, .has-tooltip.is-shown::after {
        opacity: 1;
        transform: translateX(-50%) translateY(0);
    }

/* -------------------------------------------------------------------------
   MODIFICADORES — usados pelas telas (topbar, acoes de linha, gatilhos de
   ajuda). Precisam existir aqui: sem eles a tela pede a variante e nao recebe.
   -help e so um marcador semantico: a caixa e a mesma da base.
   ------------------------------------------------------------------------- */

/* -wide — balao de varias linhas para frases de ajuda (a base e nowrap) */
.has-tooltip-wide::after {
    white-space: normal;
    width: max-content;
    max-width: 260px;
    text-align: left;
    line-height: var(--lh-snug);
}

/* -start — ancora pela borda ESQUERDA do elemento: o balao cresce para a direita */
.has-tooltip-start::after {
    left: 0;
    right: auto;
    transform: translateX(0) translateY(4px);
    transform-origin: bottom left;
}

.has-tooltip-start:hover::after, .has-tooltip-start:focus-visible::after, .has-tooltip-start.is-shown::after {
    transform: translateX(0) translateY(0);
}

/* -end — ancora pela borda DIREITA do elemento: o balao cresce para a esquerda */
.has-tooltip-end::after {
    left: auto;
    right: 0;
    transform: translateX(0) translateY(4px);
    transform-origin: bottom right;
}

.has-tooltip-end:hover::after, .has-tooltip-end:focus-visible::after, .has-tooltip-end.is-shown::after {
    transform: translateX(0) translateY(0);
}

/* -down — abre ABAIXO do elemento, para gatilhos colados no topo da tela */
.has-tooltip-down::after {
    top: calc(100% + 6px);
    bottom: auto;
    transform-origin: top center;
}

.has-tooltip-down.has-tooltip-start::after {
    transform-origin: top left;
}

.has-tooltip-down.has-tooltip-end::after {
    transform-origin: top right;
}

@media (prefers-reduced-motion: reduce) {
    .has-tooltip::after {
        transition-duration: 0s;
    }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — AVATAR
   Novo (nao existe no essentials). Iniciais ou imagem, tamanhos e grupo.
   ========================================================================= */
.avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 36px;
    height: 36px;
    border-radius: var(--radius-full);
    overflow: hidden;
    background: var(--color-primary-soft);
    color: var(--color-primary);
    font-size: var(--fs-sm);
    font-weight: var(--fw-semibold);
}

    .avatar img {
        width: 100%;
        height: 100%;
        object-fit: cover;
    }

.avatar-sm {
    width: 28px;
    height: 28px;
    font-size: var(--fs-xs);
}

.avatar-lg {
    width: 48px;
    height: 48px;
    font-size: var(--fs-lg);
}

.avatar-neutral {
    background: var(--color-surface-2);
    color: var(--color-text-muted);
}

.avatar-group {
    display: inline-flex;
}

    .avatar-group .avatar {
        border: 2px solid var(--color-surface);
        margin-left: -8px;
    }

        .avatar-group .avatar:first-child {
            margin-left: 0;
        }
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — BADGE / TAG
   Simplifica o .badge-container-* (verboso) do essentials para .badge +
   variantes de sinal. Token-only, dark-ready.
   ========================================================================= */
.badge {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
    width: fit-content;
    font-size: var(--fs-xs);
    font-weight: var(--fw-semibold);
    line-height: 1;
    white-space: nowrap;
    padding: 4px 8px;
    border-radius: var(--radius-full);
    background: var(--color-surface-2);
    color: var(--color-text-muted);
    border: var(--border-w) solid var(--color-border);
}

.badge-sm {
    font-size: 10px;
    padding: 3px 6px;
}

.badge-dot::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: var(--radius-full);
    background: currentColor;
}

.badge-primary {
    background: var(--color-primary-soft);
    color: var(--color-primary);
    border-color: var(--color-primary-border);
}

.badge-success {
    background: var(--color-success-soft);
    color: var(--color-success);
    border-color: transparent;
}

.badge-warning {
    background: var(--color-warning-soft);
    color: var(--color-warning);
    border-color: transparent;
}

.badge-danger {
    background: var(--color-danger-soft);
    color: var(--color-danger);
    border-color: transparent;
}

.badge-info {
    background: var(--color-info-soft);
    color: var(--color-info);
    border-color: transparent;
}

.badge-neutral {
    background: var(--color-surface-2);
    color: var(--color-text-muted);
    border-color: var(--color-border);
}

/* Contornado (só borda + cor, sem preenchimento) */
.badge-outline {
    background: transparent;
}

    .badge-outline.badge-primary {
        color: var(--color-primary);
        border-color: var(--color-primary-border);
    }

    .badge-outline.badge-danger {
        color: var(--color-danger);
        border-color: var(--color-danger);
    }
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — PILL (contexto travado / leitura)
   Cápsula de leitura para identificadores fixos que o usuário não edita
   (CNPJ, produto, protocolo). Duas partes: rótulo apagado + valor forte.
   Cadeado opcional reforça o caráter travado. Token-only, dark-ready.
   NÃO é badge (selo de status) nem escolha (usar .segmented).
   ========================================================================= */
.pill {
  display: inline-flex; align-items: center; gap: var(--sp-2); width: fit-content;
  padding: 5px 12px; border-radius: var(--radius-full);
  background: var(--color-surface-2); border: var(--border-w) solid var(--color-border);
  line-height: 1; white-space: nowrap; max-width: 100%;
}
.pill-icon { flex: none; width: 14px; height: 14px; color: var(--color-text-subtle); }
.pill-label {
  font-size: var(--fs-xs); font-weight: var(--fw-semibold); text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--color-text-muted);
}
.pill-value {
  font-family: var(--font-mono); font-size: var(--fs-sm); font-weight: var(--fw-semibold);
  color: var(--color-text); overflow: hidden; text-overflow: ellipsis;
}

/* Valor não-numérico/código: usa a fonte de texto em vez de mono */
.pill-value-text { font-family: var(--font-sans); }

/* Ênfase de marca no valor */
.pill-primary .pill-value { color: var(--color-primary); }
.pill-primary .pill-icon  { color: var(--color-primary); }

/* Compacto */
.pill-sm { padding: 3px 9px; gap: var(--sp-1); }
.pill-sm .pill-icon { width: 12px; height: 12px; }
.pill-sm .pill-value { font-size: var(--fs-xs); }
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — CAMPO DE ENTRADA
   Vocabulario do essentials, REFINADO (token-only, dark-ready, estados):
     .lbl                -> rotulo
     .input-container    -> wrapper (borda/foco), com <input>/<select>/<textarea> dentro
     .invalid            -> Blazor InputBase adiciona ao controle quando invalido
     .validation-message -> saida do <ValidationMessage> do Blazor
   Icone: SVG INLINE (.input-glyph). O essentials hoje usa <i class="IconClass"> de
   fonte de icone; na adocao, trocar por SVG (regra: so SVG inline).
   ========================================================================= */

/* Rotulo */
.lbl {
    display: block;
    width: 100%;
    font-size: var(--fs-sm);
    font-weight: var(--fw-medium);
    color: var(--color-text);
    margin-bottom: var(--sp-2);
}

.lbl .req {
    color: var(--color-danger);
    margin-left: 2px;
}

/* Modificador — asterisco automatico via ::after, para quem escreve
   <label class="lbl is-required"> sem precisar do <span class="req"> a mao. */
.lbl.is-required::after {
    content: "*";
    color: var(--color-danger);
    margin-left: 2px;
}

/* Wrapper */
.input-container {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    width: 100%;
    padding: var(--sp-2) var(--sp-3);
    min-height: var(--control-h);
    background: var(--color-surface);
    border: var(--border-w) solid var(--color-border-strong);
    border-radius: var(--radius-lg);
    transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}

    .input-container input,
    .input-container select,
    .input-container textarea {
        flex: 1 1 auto;
        min-width: 0;
        border: none;
        outline: none;
        background: transparent;
        font-family: var(--font-sans);
        font-size: var(--fs-base);
        color: var(--color-text);
        padding: 0;
    }

    .input-container textarea {
        min-height: 68px;
        resize: vertical;
        line-height: var(--lh-normal);
    }

        .input-container input::placeholder,
        .input-container textarea::placeholder {
            color: var(--color-text-subtle);
        }

.input-glyph {
    width: 18px;
    height: 18px;
    flex: none;
    color: var(--color-text-subtle);
}

/* Acao dentro do campo (mostrar senha, limpar) — botao icone, SVG inline */
.input-action {
    flex: none;
    display: grid;
    place-items: center;
    width: 24px;
    height: 24px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text-subtle);
    cursor: pointer;
}

    .input-action:hover {
        background: var(--color-surface-hover);
        color: var(--color-text);
    }

    .input-action svg {
        width: 17px;
        height: 17px;
    }

    .input-action .ico-eye-off {
        display: none;
    }

    .input-action.is-revealed .ico-eye {
        display: none;
    }

    .input-action.is-revealed .ico-eye-off {
        display: block;
    }

/* Foco (essentials: focus-within + border --primary) */
.input-container:focus-within {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--color-focus-ring);
}

/* Desabilitado */
.input-container.is-disabled,
.input-container:has(:disabled) {
    background: var(--color-surface-2);
    cursor: not-allowed;
}

    .input-container:has(:disabled) input,
    .input-container :disabled {
        color: var(--color-text-subtle);
        cursor: not-allowed;
    }

/* Invalido — reflete o .invalid do controle no wrapper */
.input-container.is-invalid,
.input-container:has(.invalid) {
    border-color: var(--color-danger);
}

    .input-container.is-invalid:focus-within,
    .input-container:has(.invalid):focus-within {
        box-shadow: 0 0 0 3px var(--color-danger-soft);
    }

/* Mensagem de erro (Blazor) e dica */
.validation-message {
    display: block;
    margin-top: var(--sp-2);
    font-size: var(--fs-sm);
    color: var(--color-danger);
}

.field-hint {
    display: block;
    margin-top: var(--sp-2);
    font-size: var(--fs-sm);
    color: var(--color-text-subtle);
}

/* Select — seta via mask (usa token de cor, sem hex solto) */
.input-container.is-select {
    position: relative;
    padding-right: var(--sp-8);
}

    .input-container.is-select select {
        appearance: none;
        -webkit-appearance: none;
        cursor: pointer;
    }
    /* Lista aberta: as <option> nao herdam cor; tokeniza p/ acompanhar o tema no desktop.
   color-scheme (semantic.css) cuida do popup nativo do SO em mobile/Safari. */
    .input-container.is-select option {
        background: var(--color-surface);
        color: var(--color-text);
    }

    .input-container.is-select::after {
        content: "";
        position: absolute;
        right: var(--sp-3);
        top: 50%;
        transform: translateY(-50%);
        width: 16px;
        height: 16px;
        pointer-events: none;
        background-color: var(--color-text-subtle);
        -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") center / contain no-repeat;
        mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") center / contain no-repeat;
    }

/* =========================================================================
   SOMENTE LEITURA (.is-readonly / [readonly])
   Campo que mostra valor mas nao aceita digitacao (GUID, codigo gerado).
   Diferente de :disabled — o valor continua selecionavel e o campo focavel.
   ========================================================================= */
.input-container.is-readonly,
.input-container:has([readonly]) {
    background: var(--color-surface-2);
    border-color: var(--color-border);
}

    .input-container.is-readonly input,
    .input-container:has([readonly]) input {
        cursor: default;
    }

    .input-container.is-readonly:focus-within,
    .input-container:has([readonly]):focus-within {
        border-color: var(--color-border-strong);
        box-shadow: none;
    }

/* =========================================================================
   CAMPO NUMERICO (.is-number)
   type="text" + inputmode="numeric|decimal": o spinner nativo do type=number
   nao e estilizavel e o incremento por scroll causa digitacao errada. O filtro
   de caracteres e do controle (Blazor: InputNumber / mascara).
     .is-number-end  -> alinha a direita (valor monetario, quantidade em tabela)
     .input-affix    -> unidade/prefixo ancorado ao campo (R$, kg, %)
     .is-stepper     -> passo -/+ tokenizado, substitui o spinner do SO
   ========================================================================= */
.input-container.is-number input {
    font-variant-numeric: tabular-nums;
}

    .input-container.is-number input::-webkit-outer-spin-button,
    .input-container.is-number input::-webkit-inner-spin-button {
        -webkit-appearance: none;
        appearance: none;
        margin: 0;
    }

    .input-container.is-number input[type="number"] {
        -moz-appearance: textfield;
        appearance: textfield;
    }

.input-container.is-number-end input {
    text-align: right;
}

.input-affix {
    flex: none;
    font-size: var(--fs-sm);
    color: var(--color-text-subtle);
    white-space: nowrap;
}

.input-container.is-stepper {
    padding: var(--sp-1);
    gap: var(--sp-1);
}

    .input-container.is-stepper input {
        text-align: center;
    }

.input-step {
    flex: none;
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-md);
    background: var(--color-surface-2);
    color: var(--color-text);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}

    .input-step:hover:not(:disabled) {
        background: var(--color-surface-hover);
    }

    .input-step:focus-visible {
        outline: var(--border-w) solid var(--color-primary);
        outline-offset: 1px;
    }

    .input-step svg {
        width: 16px;
        height: 16px;
    }

    .input-step:disabled {
        color: var(--color-text-subtle);
        cursor: not-allowed;
    }

.input-container:has(:disabled) .input-step {
    color: var(--color-text-subtle);
    pointer-events: none;
}

/* =========================================================================
   CAMPO GUID (.is-guid)
   Identificador nunca e digitado a mao: o campo e somente leitura e as duas
   acoes escrevem nele — colar do clipboard e gerar um novo GUID (v4).
   Fonte mono p/ o valor nao "tremer" e o usuario conferir digito a digito.
   ========================================================================= */
.input-container.is-guid input {
    font-family: var(--font-mono);
    font-size: var(--fs-sm);
}

.input-container.is-guid .input-glyph {
    color: var(--color-text-subtle);
}

.input-guid-actions {
    display: flex;
    flex: none;
    gap: var(--sp-1);
    margin-left: auto;
}

    .input-guid-actions .input-action {
        width: 28px;
        height: 28px;
        border: var(--border-w) solid var(--color-border);
        background: var(--color-surface);
    }

        .input-guid-actions .input-action:hover {
            background: var(--color-surface-hover);
            color: var(--color-primary);
            border-color: var(--color-border-strong);
        }

        .input-guid-actions .input-action:focus-visible {
            outline: var(--border-w) solid var(--color-primary);
            outline-offset: 1px;
        }

.input-container:has(:disabled) .input-guid-actions .input-action {
    color: var(--color-text-subtle);
    background: var(--color-surface-2);
    pointer-events: none;
}

.input-container.is-guid input:placeholder-shown {
    color: var(--color-text-subtle);
}

/* =========================================================================
   INPUT DE ARQUIVO (.file-field / .file-drop / .file-item)
   O <input type="file"> nativo nao e estilizavel: escondemos o controle e
   acionamos por um <label for>. Tres formas:
     .file-field -> picker compacto (botao + nome do arquivo)
     .file-drop  -> area de arraste-e-solte (drag & drop)
     .file-item  -> arquivo escolhido (nome/tamanho, remover, progresso, erro)
   O <input> real fica com .file-native (visualmente escondido, acessivel).
   ========================================================================= */
.file-native {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* Picker compacto */
.file-field {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
}

.file-field-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    flex: none;
    height: var(--control-h);
    padding: 0 var(--sp-4);
    font-family: var(--font-sans);
    font-size: var(--fs-sm);
    font-weight: var(--fw-medium);
    color: var(--color-text);
    background: var(--color-surface);
    border: var(--border-w) solid var(--color-border-strong);
    border-radius: var(--radius-lg);
    cursor: pointer;
    transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}

    .file-field-btn:hover {
        background: var(--color-surface-hover);
    }

    .file-field-btn svg {
        width: 17px;
        height: 17px;
        flex: none;
        color: var(--color-text-subtle);
    }

.file-native:focus-visible + .file-field-btn {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--color-focus-ring);
}

.file-field-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--fs-sm);
    color: var(--color-text);
}

    .file-field-name.is-empty {
        color: var(--color-text-subtle);
    }

.file-native:disabled + .file-field-btn {
    background: var(--color-surface-2);
    color: var(--color-text-subtle);
    cursor: not-allowed;
}

    .file-native:disabled + .file-field-btn svg {
        color: var(--color-text-subtle);
    }

/* Dropzone */
.file-drop {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--sp-2);
    width: 100%;
    padding: var(--sp-6) var(--sp-5);
    background: var(--color-surface);
    border: var(--border-w) dashed var(--color-border-strong);
    border-radius: var(--radius-lg);
    cursor: pointer;
    transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}

    .file-drop:hover {
        background: var(--color-surface-hover);
    }

.file-native:focus-visible + .file-drop {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--color-focus-ring);
}

.file-drop.is-dragover {
    border-color: var(--color-primary);
    border-style: solid;
    background: var(--color-primary-soft);
}

.file-drop-icon {
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-full);
    background: var(--color-surface-2);
    color: var(--color-text-subtle);
    margin-bottom: var(--sp-1);
}

.file-drop.is-dragover .file-drop-icon {
    background: var(--color-primary-soft);
    color: var(--color-primary);
}

.file-drop-icon svg {
    width: 20px;
    height: 20px;
}

.file-drop-title {
    font-size: var(--fs-base);
    color: var(--color-text);
}

.file-drop-link {
    color: var(--color-primary);
    font-weight: var(--fw-medium);
}

.file-drop-hint {
    font-size: var(--fs-sm);
    color: var(--color-text-subtle);
}

.file-drop.is-invalid {
    border-color: var(--color-danger);
}

/* Arquivo escolhido */
.file-item {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    width: 100%;
    padding: var(--sp-3);
    background: var(--color-surface);
    border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-lg);
}

.file-item-icon {
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    flex: none;
    border-radius: var(--radius-md);
    background: var(--color-surface-2);
    color: var(--color-text-subtle);
}

    .file-item-icon svg {
        width: 18px;
        height: 18px;
    }

.file-item-info {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.file-item-name {
    font-size: var(--fs-sm);
    font-weight: var(--fw-medium);
    color: var(--color-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.file-item-meta {
    font-size: var(--fs-xs);
    color: var(--color-text-subtle);
}

.file-item-remove {
    flex: none;
    display: grid;
    place-items: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text-subtle);
    cursor: pointer;
}

    .file-item-remove:hover {
        background: var(--color-surface-hover);
        color: var(--color-danger);
    }

    .file-item-remove svg {
        width: 16px;
        height: 16px;
    }
/* Barra de progresso (upload) */
.file-item-progress {
    height: 4px;
    border-radius: var(--radius-full);
    background: var(--color-surface-2);
    overflow: hidden;
    margin-top: var(--sp-1);
}

.file-item-progress-bar {
    display: block;
    height: 100%;
    width: var(--progress, 0%);
    border-radius: inherit;
    background: var(--color-primary);
    transition: width var(--dur-base) var(--ease);
}

.file-item:not(.is-uploading) .file-item-progress {
    display: none;
}

.file-item.is-uploading .file-item-icon {
    color: var(--color-primary);
}
/* Erro (arquivo rejeitado / falha no envio) */
.file-item.is-error {
    border-color: var(--color-danger);
}

    .file-item.is-error .file-item-icon {
        background: var(--color-danger-soft);
        color: var(--color-danger);
    }

    .file-item.is-error .file-item-meta {
        color: var(--color-danger);
    }

/* =========================================================================
   ANEXO NO SERVIDOR (.file-list / .file-item-actions)
   Mesmo .file-item, em leitura: arquivo que ja existe no servidor, com Abrir
   (nova aba — PDF/imagem, tipos que o navegador exibe) e Baixar (<a download>).
   Estados: normal, is-loading (baixando), is-error (indisponivel),
   is-skeleton e .file-list-empty.
   ========================================================================= */
.file-list {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

    .file-list > li {
        min-width: 0;
    }

.file-item-actions {
    flex: none;
    display: flex;
    align-items: center;
    gap: var(--sp-1);
}

.file-item-action {
    flex: none;
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--color-text-muted);
    cursor: pointer;
    text-decoration: none;
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}

    .file-item-action:hover {
        background: var(--color-surface-hover);
        color: var(--color-primary);
    }

    .file-item-action:focus-visible {
        outline: none;
        box-shadow: 0 0 0 3px var(--color-focus-ring);
    }

    .file-item-action svg {
        width: 17px;
        height: 17px;
    }

    .file-item-action.is-loading {
        pointer-events: none;
        color: var(--color-primary);
    }

        .file-item-action.is-loading .lds-ellipsis span {
            width: 4px;
            height: 4px;
        }

    .file-item-action:disabled,
    .file-item-action.is-disabled {
        pointer-events: none;
        color: var(--color-text-subtle);
        cursor: not-allowed;
    }

a.file-item-name {
    text-decoration: none;
}

    a.file-item-name:hover {
        color: var(--color-primary);
        text-decoration: underline;
    }

.file-item.is-skeleton .file-item-icon {
    background: var(--color-surface-hover);
}

.file-item.is-skeleton .sk-line {
    width: 55%;
}

    .file-item.is-skeleton .sk-line + .sk-line {
        width: 30%;
    }

.file-list-empty {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-4);
    border: var(--border-w) dashed var(--color-border-strong);
    border-radius: var(--radius-lg);
    font-size: var(--fs-sm);
    color: var(--color-text-subtle);
}

    .file-list-empty svg {
        width: 18px;
        height: 18px;
        flex: none;
    }

/* =========================================================================
   ROTULO FLUTUANTE (.float-field)
   Input com label sobre a linha da borda. Em repouso o rotulo ocupa o lugar do
   placeholder; ao focar ou preencher, sobe e encolhe. A label sempre indica o
   objetivo do campo, mesmo no modo de edicao (util no titulo do card de registro).
   Requer placeholder=" " (um espaco) no controle p/ acionar :placeholder-shown.
   ========================================================================= */
.float-field {
    position: relative;
    width: 100%;
}

.float-field-control {
    width: 100%;
    min-height: var(--control-h);
    padding: var(--sp-4) var(--sp-3) var(--sp-2);
    background: var(--color-surface);
    border: var(--border-w) solid var(--color-border-strong);
    border-radius: var(--radius-lg);
    font-family: var(--font-sans);
    font-size: var(--fs-base);
    color: var(--color-text);
    outline: none;
    transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}

textarea.float-field-control {
    min-height: 84px;
    resize: vertical;
    line-height: var(--lh-normal);
}

.float-field-control::placeholder {
    color: transparent;
}
/* Extensao local (nao vem do design system): slot de acao (revelar senha, colar/gerar GUID)
   dentro do float-field, posicionado a direita. Empurra o texto do controle pra nao sobrepor. */
.float-field:has(.float-field-action) .float-field-control {
    padding-right: var(--sp-10);
}

.float-field-action {
    position: absolute;
    right: var(--sp-2);
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    gap: var(--sp-1);
}

.float-field-label {
    position: absolute;
    left: calc(var(--sp-3) - var(--sp-1) + var(--border-w));
    top: 50%;
    transform: translateY(-50%);
    transform-origin: left center;
    padding: 0 var(--sp-1);
    background: var(--color-surface);
    color: var(--color-text-subtle);
    font-family: var(--font-sans);
    font-size: var(--fs-base);
    font-weight: var(--fw-regular);
    pointer-events: none;
    max-width: calc(100% - var(--sp-6));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    will-change: transform;
    transition: top var(--dur-base) var(--ease), transform var(--dur-base) var(--ease), color var(--dur-fast) var(--ease), letter-spacing var(--dur-base) var(--ease);
}

    .float-field-label .req {
        color: var(--color-danger);
        margin-left: 2px;
    }
/* Flutuar: focado OU preenchido. O tamanho muda por scale (nao por font-size):
   escala e composta na GPU, entao o movimento nao reflui texto nem "pisa" no
   pixel. A subida usa --ease-out (sai rapido, assenta); a volta usa --ease. */
.float-field-control:focus-visible ~ .float-field-label,
.float-field-control:not(:placeholder-shown) ~ .float-field-label {
    top: 0;
    transform: translateY(-50%) scale(0.78);
    font-weight: var(--fw-medium);
    letter-spacing: var(--ls-wide);
    transition-timing-function: var(--ease-out);
}

.float-field-control:focus-visible ~ .float-field-label {
    color: var(--color-primary);
}
/* Foco */
.float-field-control:focus-visible {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--color-focus-ring);
}
/* Desabilitado */
.float-field-control:disabled {
    background: var(--color-surface-2);
    color: var(--color-text-subtle);
    cursor: not-allowed;
}

    .float-field-control:disabled ~ .float-field-label {
        background: var(--color-surface-2);
    }
/* Invalido */
.float-field-control.invalid {
    border-color: var(--color-danger);
}

    .float-field-control.invalid:focus-visible {
        box-shadow: 0 0 0 3px var(--color-danger-soft);
    }

        .float-field-control.invalid:focus-visible ~ .float-field-label,
        .float-field-control.invalid:not(:placeholder-shown) ~ .float-field-label {
            color: var(--color-danger);
        }
/* =========================================================================
   AUTOFILL DO NAVEGADOR (senha/dados salvos)
   Dois problemas, dois consertos:
   1) O navegador pinta o campo com fundo proprio (amarelo/azul) que ignora o
      tema. Neutralizamos com box-shadow inset (o unico jeito de vencer o fundo
      interno do WebKit) + -webkit-text-fill-color.
   2) Rotulo flutuante em cima do texto preenchido: no autofill o campo nunca
      recebeu foco e, na fase de PREVIA do Chrome, o valor sugerido nao chega ao
      CSS — :placeholder-shown continua verdadeiro e o rotulo fica no meio, sobre
      o texto. Por isso :autofill / :-webkit-autofill tambem fazem o rotulo subir.
   Cada pseudo em regra separada: pseudo desconhecido invalida a lista toda.
   ========================================================================= */
.input-container input:-webkit-autofill,
.float-field-control:-webkit-autofill {
    -webkit-text-fill-color: var(--color-text);
    caret-color: var(--color-text);
    -webkit-box-shadow: inset 0 0 0 100px var(--color-surface);
    box-shadow: inset 0 0 0 100px var(--color-surface);
    -webkit-transition: background-color 600000s 0s;
    transition: background-color 600000s 0s;
    font-family: var(--font-sans);
    font-size: var(--fs-base);
}

.input-container input:autofill,
.float-field-control:autofill {
    filter: none;
}

.input-container:has(:-webkit-autofill) {
    background: var(--color-surface);
}

.input-container input:-webkit-autofill:disabled,
.float-field-control:-webkit-autofill:disabled {
    -webkit-text-fill-color: var(--color-text-subtle);
    -webkit-box-shadow: inset 0 0 0 100px var(--color-surface-2);
    box-shadow: inset 0 0 0 100px var(--color-surface-2);
}
/* Rotulo sobe tambem no autofill (inclusive na previa, sem foco) */
.float-field-control:-webkit-autofill ~ .float-field-label {
    top: 0;
    transform: translateY(-50%) scale(0.78);
    font-weight: var(--fw-medium);
    letter-spacing: var(--ls-wide);
}

.float-field-control:autofill ~ .float-field-label {
    top: 0;
    transform: translateY(-50%) scale(0.78);
    font-weight: var(--fw-medium);
    letter-spacing: var(--ls-wide);
}

.float-field-title .float-field-control:-webkit-autofill ~ .float-field-label {
    transform: translateY(-50%) scale(0.66);
}

.float-field-title .float-field-control:autofill ~ .float-field-label {
    transform: translateY(-50%) scale(0.66);
}

/* Titulo — variante grande p/ nome do registro (fs-xl como .ev-header-title) */
.float-field-title .float-field-control {
    font-size: var(--fs-xl);
    font-weight: var(--fw-semibold);
    letter-spacing: var(--ls-tight);
}

.float-field-title .float-field-label {
    font-size: var(--fs-lg);
}

.float-field-title .float-field-control:focus-visible ~ .float-field-label,
.float-field-title .float-field-control:not(:placeholder-shown) ~ .float-field-label {
    transform: translateY(-50%) scale(0.66);
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — SELECT CUSTOMIZADO E AUTOCOMPLETE
   Por que nao estilizar o <select> nativo: a caixa de opcoes que abre e
   desenhada pelo SISTEMA OPERACIONAL, nao pelo CSS da pagina. Nao ha como
   estilizar <option> de forma confiavel entre navegadores (nem cor de fundo,
   raio, sombra ou hover). Para controlar a caixa aberta usamos um listbox
   proprio (botao + <ul role="listbox">), abaixo.

     .select        -> select customizado (trigger + menu estilizavel)
     .autocomplete  -> campo de busca com resultados assincronos (loading/empty)

   Token-only, dark-ready. Reaproveita .input-container do input.css no campo
   do autocomplete. Estados seguem a REGRA DE OURO (loading / empty / normal).
   ========================================================================= */

/* =========================== SELECT (LISTBOX) =========================== */
.select {
    position: relative;
    width: 100%;
}

.select-trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-2);
    width: 100%;
    height: var(--control-h);
    padding: 0 var(--sp-3);
    text-align: left;
    font-family: var(--font-sans);
    font-size: var(--fs-base);
    color: var(--color-text);
    background: var(--color-surface);
    border: var(--border-w) solid var(--color-border-strong);
    border-radius: var(--radius-lg);
    cursor: pointer;
    transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}

    .select-trigger:hover {
        background: var(--color-surface-hover);
    }

    .select-trigger:focus-visible {
        outline: none;
        border-color: var(--color-primary);
        box-shadow: 0 0 0 3px var(--color-focus-ring);
    }

.select[data-open="true"] .select-trigger {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--color-focus-ring);
}

.select-value {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

    .select-value.is-placeholder {
        color: var(--color-text-subtle);
    }

.select-caret {
    width: 16px;
    height: 16px;
    flex: none;
    color: var(--color-text-subtle);
    transition: transform var(--dur-fast) var(--ease);
}

.select[data-open="true"] .select-caret {
    transform: rotate(180deg);
}

/* Extensao local (nao vem do design system): invalido/desabilitado do trigger.
   O select customizado nao tem <input> interno pra disparar .input-container:has(.invalid)
   do input.css — o Blazor InputBase poe as classes valid/invalid/modified direto no
   .select-trigger, entao os estados replicam aqui o mesmo tratamento visual do campo comum. */
.select-trigger.invalid {
    border-color: var(--color-danger);
}

    .select-trigger.invalid:focus-visible {
        box-shadow: 0 0 0 3px var(--color-danger-soft);
    }

.select-trigger:disabled {
    background: var(--color-surface-2);
    color: var(--color-text-subtle);
    cursor: not-allowed;
}

/* A caixa que abre — totalmente estilizada por nos */
.select-menu {
    position: absolute;
    z-index: var(--z-dropdown);
    top: calc(100% + var(--sp-1));
    left: 0;
    right: 0;
    margin: 0;
    padding: var(--sp-1);
    list-style: none;
    max-height: 260px;
    overflow-y: auto;
    background: var(--color-surface);
    border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
}

.select[data-open="false"] .select-menu {
    display: none;
}

.select-group-label {
    padding: var(--sp-3) var(--sp-3) var(--sp-1);
    font-size: var(--fs-xs);
    font-weight: var(--fw-semibold);
    letter-spacing: var(--ls-wide);
    text-transform: uppercase;
    color: var(--color-text-subtle);
}

.select-option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-3);
    border-radius: var(--radius-md);
    font-size: var(--fs-base);
    color: var(--color-text);
    cursor: pointer;
}

    .select-option:hover,
    .select-option.is-active {
        background: var(--color-surface-hover);
    }

    .select-option.is-selected {
        background: var(--color-primary-soft);
        color: var(--color-primary);
        font-weight: var(--fw-medium);
    }

.select-option-check {
    width: 16px;
    height: 16px;
    flex: none;
    opacity: 0;
    color: var(--color-primary);
}

.select-option.is-selected .select-option-check {
    opacity: 1;
}

/* ============================ AUTOCOMPLETE ============================= */
.autocomplete {
    position: relative;
    width: 100%;
}

.autocomplete-menu {
    position: absolute;
    z-index: var(--z-dropdown);
    top: calc(100% + var(--sp-1));
    left: 0;
    right: 0;
    margin: 0;
    padding: var(--sp-1);
    list-style: none;
    max-height: 300px;
    overflow-y: auto;
    background: var(--color-surface);
    border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
}

.autocomplete[data-open="false"] .autocomplete-menu {
    display: none;
}

.autocomplete-option {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--sp-2) var(--sp-3);
    border-radius: var(--radius-md);
    cursor: pointer;
}

    .autocomplete-option:hover,
    .autocomplete-option.is-active {
        background: var(--color-surface-hover);
    }

.autocomplete-option-title {
    font-size: var(--fs-base);
    color: var(--color-text);
}

    .autocomplete-option-title mark {
        background: var(--color-highlight-soft);
        color: inherit;
        border-radius: var(--radius-sm);
        padding: 0 2px;
        font-weight: var(--fw-semibold);
    }

.autocomplete-option-sub {
    font-size: var(--fs-sm);
    color: var(--color-text-subtle);
}

/* Estados: loading (busca em andamento) e empty (sem resultado) */
.autocomplete-status {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-3);
    font-size: var(--fs-sm);
    color: var(--color-text-muted);
}

/* Spinner de campo — anel girando, cor de marca */
.field-spinner {
    width: 16px;
    height: 16px;
    flex: none;
    border-radius: var(--radius-full);
    border: 2px solid var(--color-border-strong);
    border-top-color: var(--color-primary);
    animation: field-spin var(--dur-slow) linear infinite;
}
/* Spinner dentro do campo do autocomplete: some por padrao, aparece so buscando */
.autocomplete-spinner {
    display: none;
}

.autocomplete.is-searching .autocomplete-spinner {
    display: block;
}

@keyframes field-spin {
    to {
        transform: rotate(360deg);
    }
}
/* Movimento reduzido: nao gira (evita rotacao), mas segue sinalizando carga com um pulso suave */
@keyframes field-pulse {
    50% {
        opacity: 0.3;
    }
}

@media (prefers-reduced-motion: reduce) {
    .field-spinner {
        animation: field-pulse var(--dur-sinal) ease-in-out infinite;
    }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — SELETOR DE DATA (DATEPICKER)
   Por que nao usar <input type="date"> nativo: o calendario que abre e
   desenhado pelo SISTEMA OPERACIONAL (fundo, hover, mes, cabecalho) e nao
   acompanha o tema nem a marca. Usamos um trigger proprio + um calendario
   totalmente tokenizado.

     .datepicker           -> raiz (trigger + painel flutuante)
     .datepicker-trigger   -> campo que abre o calendario (icone + valor)
     .datepicker-panel     -> caixa flutuante (popup)
     .datepicker-static    -> calendario embutido (sem popup)
     .datepicker-calendar  -> cabecalho + dias da semana + grade
     .datepicker-day       -> celula de dia (today/selected/outside/disabled/range)

   Token-only, dark-ready. Estados seguem a REGRA DE OURO. Intervalo (range)
   usa dois meses lado a lado (.datepicker-months).
   ========================================================================= */

.datepicker {
    position: relative;
    width: 100%;
}

/* ============================== TRIGGER =============================== */
.datepicker-trigger {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    width: 100%;
    height: var(--control-h);
    padding: 0 var(--sp-3);
    text-align: left;
    font-family: var(--font-sans);
    font-size: var(--fs-base);
    color: var(--color-text);
    background: var(--color-surface);
    border: var(--border-w) solid var(--color-border-strong);
    border-radius: var(--radius-lg);
    cursor: pointer;
    transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}

    .datepicker-trigger:hover {
        background: var(--color-surface-hover);
    }

    .datepicker-trigger:focus-visible {
        outline: none;
        border-color: var(--color-primary);
        box-shadow: 0 0 0 3px var(--color-focus-ring);
    }

.datepicker[data-open="true"] .datepicker-trigger {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--color-focus-ring);
}

.datepicker-trigger-icon {
    width: 18px;
    height: 18px;
    flex: none;
    color: var(--color-text-subtle);
}

.datepicker-value {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

    .datepicker-value.is-placeholder {
        color: var(--color-text-subtle);
    }

.datepicker-clear {
    flex: none;
    display: grid;
    place-items: center;
    width: 24px;
    height: 24px;
    padding: 0;
    margin: 0 -4px 0 0;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text-subtle);
    cursor: pointer;
}

    .datepicker-clear:hover {
        background: var(--color-surface-hover);
        color: var(--color-text);
    }

    .datepicker-clear svg {
        width: 15px;
        height: 15px;
    }

/* Extensao local (nao vem do design system): invalido/desabilitado do trigger
   por classe direta. O datepicker customizado nao tem <input> interno pra
   disparar .input-container:has(.invalid) do input.css — o Blazor InputBase
   poe as classes valid/invalid/modified direto no .datepicker-trigger, entao
   os estados replicam aqui o mesmo tratamento visual do campo comum. Soma-se
   aos seletores oficiais do design system abaixo, que reagem a .datepicker
   na raiz (is-disabled / is-invalid). */
.datepicker-trigger.invalid {
    border-color: var(--color-danger);
}

    .datepicker-trigger.invalid:focus-visible {
        box-shadow: 0 0 0 3px var(--color-danger-soft);
    }

/* Desabilitado */
.datepicker.is-disabled .datepicker-trigger,
.datepicker-trigger:disabled {
    background: var(--color-surface-2);
    color: var(--color-text-subtle);
    cursor: not-allowed;
}

.datepicker.is-disabled .datepicker-trigger-icon,
.datepicker-trigger:disabled .datepicker-trigger-icon {
    color: var(--color-text-subtle);
}

/* Invalido */
.datepicker.is-invalid .datepicker-trigger {
    border-color: var(--color-danger);
}

.datepicker.is-invalid[data-open="true"] .datepicker-trigger,
.datepicker.is-invalid .datepicker-trigger:focus-visible {
    box-shadow: 0 0 0 3px var(--color-danger-soft);
}

/* ============================ PAINEL / EMBUTIDO ======================= */
.datepicker-panel {
    position: absolute;
    z-index: var(--z-dropdown);
    top: calc(100% + var(--sp-1));
    left: 0;
    padding: var(--sp-3);
    background: var(--color-surface);
    border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
}

.datepicker[data-open="false"] .datepicker-panel {
    display: none;
}

.datepicker-static {
    display: inline-block;
    padding: var(--sp-3);
    background: var(--color-surface);
    border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-lg);
}

.datepicker-calendar {
    width: 268px;
    max-width: 100%;
}

/* ============================== CABECALHO ============================= */
.datepicker-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-2);
    margin-bottom: var(--sp-2);
}

.datepicker-title {
    font-size: var(--fs-base);
    font-weight: var(--fw-semibold);
    color: var(--color-text);
    text-transform: capitalize;
}

.datepicker-nav {
    display: flex;
    gap: var(--sp-1);
}

.datepicker-nav-btn {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--color-text-muted);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}

    .datepicker-nav-btn:hover {
        background: var(--color-surface-hover);
        color: var(--color-text);
    }

    .datepicker-nav-btn:focus-visible {
        outline: none;
        box-shadow: 0 0 0 3px var(--color-focus-ring);
    }

    .datepicker-nav-btn:disabled {
        color: var(--color-text-subtle);
        opacity: 0.4;
        cursor: not-allowed;
    }

        .datepicker-nav-btn:disabled:hover {
            background: transparent;
        }

    .datepicker-nav-btn svg {
        width: 16px;
        height: 16px;
    }
/* Preenche o lado sem botao de navegacao no cabecalho do calendario de
   intervalo (primeiro mes sem "proximo", segundo sem "anterior"). */
.datepicker-header-spacer {
    width: 30px;
    height: 30px;
    flex: none;
}

/* =========================== DIAS DA SEMANA ========================== */
.datepicker-weekdays {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
}

.datepicker-weekday {
    text-align: center;
    padding: var(--sp-1) 0;
    font-size: var(--fs-xs);
    font-weight: var(--fw-semibold);
    letter-spacing: var(--ls-wide);
    text-transform: uppercase;
    color: var(--color-text-subtle);
}

/* =============================== GRADE =============================== */
.datepicker-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
}

.datepicker-day {
    aspect-ratio: 1 / 1;
    display: grid;
    place-items: center;
    width: 100%;
    border: 0;
    background: transparent;
    border-radius: var(--radius-md);
    font-family: var(--font-sans);
    font-size: var(--fs-sm);
    color: var(--color-text);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}

    .datepicker-day:hover {
        background: var(--color-surface-hover);
    }

    .datepicker-day:focus-visible {
        outline: none;
        box-shadow: 0 0 0 2px var(--color-focus-ring);
    }

    .datepicker-day.is-outside {
        color: var(--color-text-subtle);
        opacity: 0.55;
    }

    .datepicker-day.is-today {
        font-weight: var(--fw-bold);
        color: var(--color-primary);
        box-shadow: inset 0 0 0 var(--border-w) var(--color-primary-border);
    }

    .datepicker-day.is-selected,
    .datepicker-day.is-selected:hover {
        background: var(--color-primary);
        color: var(--color-on-primary);
        font-weight: var(--fw-semibold);
        box-shadow: none;
    }

    .datepicker-day:disabled,
    .datepicker-day.is-disabled {
        color: var(--color-text-subtle);
        opacity: 0.4;
        cursor: not-allowed;
        text-decoration: line-through;
    }

        .datepicker-day:disabled:hover,
        .datepicker-day.is-disabled:hover {
            background: transparent;
        }

/* Intervalo (range) — sem gap p/ o realce ficar continuo. FORA de escopo aqui, manter no CSS por ser o mesmo arquivo-fonte, mas nao construir markup/estado C# para isso. */
.datepicker-calendar.is-range .datepicker-grid {
    gap: 0;
}

.datepicker-calendar.is-range .datepicker-day {
    border-radius: 0;
}

.datepicker-day.is-in-range {
    background: var(--color-primary-soft);
    color: var(--color-primary);
}

.datepicker-day.is-range-start {
    background: var(--color-primary);
    color: var(--color-on-primary);
    font-weight: var(--fw-semibold);
    border-radius: var(--radius-md) 0 0 var(--radius-md);
}

.datepicker-day.is-range-end {
    background: var(--color-primary);
    color: var(--color-on-primary);
    font-weight: var(--fw-semibold);
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
}

.datepicker-day.is-range-start.is-range-end {
    border-radius: var(--radius-md);
}

/* Dois meses lado a lado (intervalo) */
.datepicker-months {
    display: flex;
    gap: var(--sp-5);
}

    .datepicker-months .datepicker-calendar {
        width: 240px;
    }

@media (max-width: 640px) {
    .datepicker-months {
        flex-direction: column;
        gap: var(--sp-4);
    }
}

/* ================================ RODAPE ============================= */
.datepicker-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-2);
    margin-top: var(--sp-3);
    padding-top: var(--sp-3);
    border-top: var(--border-w) solid var(--color-border);
}

.datepicker-footer-info {
    font-size: var(--fs-sm);
    color: var(--color-text-muted);
}

.datepicker-link {
    padding: 0;
    border: 0;
    background: transparent;
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: var(--fw-medium);
    color: var(--color-primary);
    cursor: pointer;
}

    .datepicker-link:hover {
        text-decoration: underline;
    }

    .datepicker-link:focus-visible {
        outline: none;
        box-shadow: 0 0 0 3px var(--color-focus-ring);
        border-radius: var(--radius-sm);
    }
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — CONTROLES DE SELECAO
   Checkbox / Radio: input nativo + accent-color (abordagem do essentials).
   Toggle: vocabulario .toggle-switch* do essentials, refinado.
   Ativo/selecionado = azul da marca (--color-primary), consistente entre os tres.
   Mudanca vs essentials: checkbox usava --primary (preto) e toggle usava verde;
   agora ambos usam a marca.
   ========================================================================= */

/* ---- Checkbox / Radio ---- */
.check {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    cursor: pointer;
    font-size: var(--fs-base);
    color: var(--color-text);
}

.check-input {
    width: 16px;
    height: 16px;
    margin: 0;
    flex: none;
    accent-color: var(--color-primary);
    cursor: pointer;
}

    .check-input:focus-visible {
        outline: 2px solid var(--color-primary);
        outline-offset: 2px;
    }

    .check-input:disabled {
        cursor: not-allowed;
    }

.check:has(.check-input:disabled) {
    color: var(--color-text-subtle);
    cursor: not-allowed;
}

/* ---- Toggle ---- */
.toggle-switch {
    position: relative;
    display: inline-flex;
    align-items: center;
    cursor: pointer;
}

.toggle-switch-input {
    position: absolute;
    width: 0;
    height: 0;
    opacity: 0;
}

.toggle-switch-fill {
    position: relative;
    flex: none;
    width: 40px;
    height: 22px;
    border-radius: var(--radius-full);
    background: var(--color-border-strong);
    transition: background var(--dur-base) var(--ease);
}

    .toggle-switch-fill::after {
        content: "";
        position: absolute;
        top: 2px;
        left: 2px;
        width: 18px;
        height: 18px;
        border-radius: var(--radius-full);
        background: var(--neutral-0);
        box-shadow: var(--shadow-xs);
        transition: transform var(--dur-base) var(--ease);
    }

.toggle-switch-input:checked + .toggle-switch-fill {
    background: var(--color-primary);
}

    .toggle-switch-input:checked + .toggle-switch-fill::after {
        transform: translateX(18px);
    }

.toggle-switch-input:focus-visible + .toggle-switch-fill {
    box-shadow: 0 0 0 3px var(--color-focus-ring);
}

.toggle-switch-input:disabled + .toggle-switch-fill {
    background: var(--color-disabled-bg);
}

    .toggle-switch-input:disabled + .toggle-switch-fill::after {
        box-shadow: none;
    }

.toggle-switch:has(.toggle-switch-input:disabled) {
    cursor: not-allowed;
}

/* Toggle com rótulo (essentials: ToggleSwitchLabel) */
.toggle-switch-label {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-3);
    cursor: pointer;
    font-size: var(--fs-base);
    color: var(--color-text);
}

/* ---- Toggle-button — um botao que liga/desliga (pressed) ----
   Um unico controle binario com cara de botao: desligado le como acao
   disponivel; ligado fica preenchido no azul da marca (estado "ativo").
   Use para ligar/desligar UMA coisa quando o switch nao cabe visualmente
   (barra de filtros, toolbar) ou quando a acao e o proprio rotulo
   ("Somente ativos", "Mostrar arquivados"). Escolha exclusiva entre varias
   -> .segmented. Liga/desliga em formulario/lista de preferencias -> toggle.
   Checkbox nativo por baixo: name, label, teclado e binding do Blazor
   (aria-pressed vem do :checked) funcionam sem JS. */
.toggle-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    min-height: var(--control-h);
    padding: 0 var(--sp-4);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: var(--fw-medium);
    line-height: 1.2;
    white-space: nowrap;
    color: var(--color-text);
    background: var(--color-surface);
    border: var(--border-w) solid var(--color-border-strong);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}

.toggle-btn-input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    margin: 0;
    pointer-events: none;
}

.toggle-btn svg {
    width: 16px;
    height: 16px;
    flex: none;
}

.toggle-btn:hover {
    background: var(--color-surface-hover);
}

.toggle-btn:has(.toggle-btn-input:checked) {
    color: var(--color-on-primary);
    background: var(--color-primary);
    border-color: var(--color-primary);
}

    .toggle-btn:has(.toggle-btn-input:checked):hover {
        background: var(--color-primary-hover);
        border-color: var(--color-primary-hover);
    }

.toggle-btn:has(.toggle-btn-input:focus-visible) {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

.toggle-btn:has(.toggle-btn-input:disabled) {
    color: var(--color-text-subtle);
    background: var(--color-disabled-bg);
    border-color: var(--color-border);
    cursor: not-allowed;
}

.toggle-btn:has(.toggle-btn-input:checked:disabled) {
    color: var(--color-on-primary);
    background: var(--color-disabled-bg);
    border-color: var(--color-disabled-bg);
    opacity: .6;
}

/* Ocupa a largura do campo */
.toggle-btn-block {
    display: flex;
    width: 100%;
}

/* ---- Radio-buttons — escolha exclusiva com botoes SEPARADOS ----
   Diferente do .segmented (trilha unica, um objeto): aqui cada opcao e um
   botao autonomo, com folga entre eles. Le como N acoes das quais UMA fica
   ativa. Use quando as opcoes tem peso proprio (metodo de pagamento, plano,
   tipo de vistoria) e/ou rotulos maiores, ou quando devem quebrar/empilhar
   com folga. Opcoes curtas e coladas classificando algo -> .segmented.
   Radio nativo por baixo: name, label e teclado (setas) funcionam sem JS. */
.radio-btns {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-3);
}

.radio-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    min-height: var(--control-h);
    padding: 0 var(--sp-4);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: var(--fw-medium);
    line-height: 1.2;
    white-space: nowrap;
    color: var(--color-text);
    background: var(--color-surface);
    border: var(--border-w) solid var(--color-border-strong);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}

.radio-btn-input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    margin: 0;
    pointer-events: none;
}

.radio-btn svg {
    width: 16px;
    height: 16px;
    flex: none;
}

.radio-btn:hover {
    background: var(--color-surface-hover);
}

.radio-btn:has(.radio-btn-input:checked) {
    color: var(--color-primary);
    background: var(--color-primary-soft);
    border-color: var(--color-primary);
    font-weight: var(--fw-semibold);
}

.radio-btn:has(.radio-btn-input:focus-visible) {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

.radio-btn:has(.radio-btn-input:disabled) {
    color: var(--color-text-subtle);
    background: var(--color-disabled-bg);
    border-color: var(--color-border);
    cursor: not-allowed;
}

.radio-btn:has(.radio-btn-input:checked:disabled) {
    opacity: .6;
}

/* Ocupa a largura do campo, opcoes dividindo o espaco */
.radio-btns-block {
    display: flex;
}

    .radio-btns-block .radio-btn {
        flex: 1 1 0;
        min-width: 0;
    }

/* ---- Segmented — escolha exclusiva entre 2 e 5 opcoes curtas ----
   Uma trilha unica com um segmento preenchido: le como UM valor com N
   alternativas, porque e um objeto so. Use quando as opcoes classificam algo
   (resultado, prioridade, periodo) e cabem em 1-2 palavras cada.
   Rotulo longo, selecao multipla ou 6+ opcoes -> .check ou select.
   O radio nativo continua no markup, apenas fora do fluxo visual: name, label,
   teclado (setas) e binding do Blazor funcionam sem nada de especial.
   Selecionado e SEMPRE --color-primary: nao existe variante de sinal. Sinal
   descreve estado que ja existe (.badge, .timeline-item); segmented e escolha
   sendo feita — verde/vermelho aqui seria lido como validacao. */
.segmented {
    display: inline-flex;
    align-items: stretch;
    max-width: 100%;
    padding: 3px;
    gap: 2px;
    background: var(--color-surface-2);
    border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-lg);
}

    .segmented.segmented-full-width {
        width: 100%;
    }

.segmented-option {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: calc(var(--control-h) - 8px);
    padding: 0 var(--sp-4);
    font-size: var(--fs-sm);
    font-weight: var(--fw-medium);
    line-height: 1.2;
    white-space: nowrap;
    color: var(--color-text-muted);
    background: transparent;
    border-radius: calc(var(--radius-lg) - 3px);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}

.segmented.segmented-full-width .segmented-option{
    width: 100%;
}

.segmented-input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    margin: 0;
    pointer-events: none;
}

.segmented-option:hover {
    color: var(--color-text);
    background: var(--color-surface-hover);
}

.segmented-option:has(.segmented-input:checked) {
    color: var(--color-primary);
    background: var(--color-surface);
    box-shadow: var(--shadow-xs);
    font-weight: var(--fw-semibold);
}

.segmented-option:has(.segmented-input:focus-visible) {
    outline: 2px solid var(--color-primary);
    outline-offset: 1px;
}

.segmented-option:has(.segmented-input:disabled) {
    color: var(--color-text-subtle);
    cursor: not-allowed;
    background: transparent;
}

.segmented:has(.segmented-input:disabled) {
    background: var(--color-disabled-bg);
}

/* Ocupa a largura do campo (dentro de .field, coluna estreita ou mobile) */
.segmented-block {
    display: flex;
    width: 100%;
}

    .segmented-block .segmented-option {
        flex: 1 1 0;
        min-width: 0;
    }

    .segmented-block .segmented-option {
        white-space: normal;
        text-align: center;
    }

@media (max-width: 640px) {
    .segmented {
        display: flex;
        width: 100%;
    }

        .segmented .segmented-option {
            flex: 1 1 0;
            min-width: 0;
        }
}

/* ---- Option-cards — lista de cards selecionaveis (um radio por card) ----
   Escolha exclusiva onde cada opcao precisa de titulo, selo, descricao e
   metadado: o card inteiro e o alvo do clique e o radio nativo e o controle.
   Use quando a opcao carrega explicacao/consequencia (integrador, plano, forma
   de contratacao) e nao cabe numa trilha curta. Opcoes de 1-2 palavras ->
   .segmented ou .radio-btns. Radio nativo por baixo: name, label, teclado e
   binding do Blazor funcionam sem JS. Selecionado = azul da marca, igual aos
   demais controles de selecao. */
.option-cards {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
}

.option-card {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    padding: var(--sp-4);
    color: var(--color-text);
    background: var(--color-surface);
    border: var(--border-w) solid var(--color-border-strong);
    border-radius: var(--radius-lg);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}

.option-card-input {
    width: 18px;
    height: 18px;
    margin: 1px 0 0;
    flex: none;
    accent-color: var(--color-primary);
    cursor: pointer;
}

.option-card:hover {
    background: var(--color-surface-hover);
    border-color: var(--color-primary-border);
}

.option-card:has(.option-card-input:checked) {
    background: var(--color-primary-soft);
    border-color: var(--color-primary);
}

.option-card:has(.option-card-input:focus-visible) {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

.option-card:has(.option-card-input:disabled) {
    color: var(--color-text-subtle);
    background: var(--color-disabled-bg);
    border-color: var(--color-border);
    cursor: not-allowed;
}

    .option-card:has(.option-card-input:disabled) .option-card-desc,
    .option-card:has(.option-card-input:disabled) .option-card-meta {
        color: var(--color-disabled-text);
    }

.option-card-content {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    min-width: 0;
}

.option-card-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--sp-2);
}

.option-card-title {
    font-size: var(--fs-base);
    font-weight: var(--fw-semibold);
    line-height: var(--lh-snug);
    color: var(--color-text);
}

.option-card-desc {
    font-size: var(--fs-sm);
    line-height: var(--lh-normal);
    color: var(--color-text-muted);
    text-wrap: pretty;
}

.option-card-meta {
    font-size: var(--fs-xs);
    font-family: var(--font-mono);
    color: var(--color-text-subtle);
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — SKELETON (CARREGAMENTO DE CONTEUDO)
   Vocabulario OFICIAL do estado de loading estrutural (REGRA DE OURO).
   Estava embutido em table.css; agora e folha propria (table.css a importa,
   entao quem ja linkava table.css continua funcionando).

     .skeleton    -> bloco cinza com brilho (obrigatorio em toda peca)
     .sk-line     -> linha de texto (12px);  .sk-line-lg -> 16px
     .sk-title    -> titulo (20px, 45% de largura)
     .sk-pill     -> badge/tag (20px de altura, raio full)
     .sk-btn      -> botao (altura de controle, raio lg)
     .sk-circle   -> avatar/marcador (usar --sk-size)
     .sk-block    -> area (miniatura, mapa, grafico) — usar --sk-h
   Largura: preferir classe do proprio componente (ex.: .ev-fields .sk-value)
   ou o utilitario .sk-w-25/50/75/100. Nunca style= inline.
   ========================================================================= */
.skeleton {
    display: block;
    background: var(--color-surface-hover);
    border-radius: var(--radius-sm);
    position: relative;
    overflow: hidden;
}

    .skeleton::after {
        content: "";
        position: absolute;
        inset: 0;
        transform: translateX(-100%);
        background: linear-gradient(90deg, transparent, var(--color-surface-2), transparent);
        animation: skeleton-shine 1.2s infinite;
    }

@keyframes skeleton-shine {
    to {
        transform: translateX(100%);
    }
}

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

/* Formas */
.sk-line {
    height: 12px;
}

.sk-line-lg {
    height: 16px;
}

.sk-title {
    height: 20px;
    width: 45%;
    border-radius: var(--radius-md);
}

.sk-pill {
    height: 20px;
    width: 84px;
    border-radius: var(--radius-full);
}

.sk-btn {
    height: var(--control-h);
    width: 92px;
    border-radius: var(--radius-lg);
}

.sk-circle {
    width: var(--sk-size, 32px);
    height: var(--sk-size, 32px);
    border-radius: var(--radius-full);
}

.sk-block {
    height: var(--sk-h, 120px);
    width: 100%;
    border-radius: var(--radius-md);
}

/* Larguras utilitarias (quando o componente nao define a sua) */
.sk-w-25 {
    width: 25%;
}

.sk-w-50 {
    width: 50%;
}

.sk-w-75 {
    width: 75%;
}

.sk-w-100 {
    width: 100%;
}

/* Grupo de linhas — paragrafo falso, ultima linha mais curta */
.sk-lines {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
}

    .sk-lines .sk-line:last-child {
        width: 60%;
    }
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — CARD / PAINEL
   Vocabulario do essentials (.card / .card-header / .card-body), refinado:
   token-only, dark-ready, + .card-footer e .card-title/.card-subtitle.
   ========================================================================= */
.card {
    background: var(--color-surface);
    color: var(--color-text);
    border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}

.card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-4) var(--sp-5);
    background: var(--color-surface);
    border-bottom: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}

.card-heading {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.card-title-group {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
}

.card-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 20px;
    padding: 0 6px;
    border-radius: var(--radius-full);
    background: var(--color-primary-soft);
    color: var(--color-primary);
    font-size: var(--fs-xs);
    font-weight: var(--fw-semibold);
    font-variant-numeric: tabular-nums;
}

.card-title {
    margin: 0;
    font-size: var(--fs-lg);
    font-weight: var(--fw-semibold);
    letter-spacing: var(--ls-tight);
}

.card-subtitle {
    margin: 0;
    font-size: var(--fs-sm);
    font-weight: var(--fw-regular);
    color: var(--color-text-muted);
}

.card-actions {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    flex: none;
}

.card-body {
    padding: var(--sp-5);
}

.card-footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--sp-3);
    padding: var(--sp-4) var(--sp-5);
    background: var(--color-surface-2);
    border-top: var(--border-w) solid var(--color-border);
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

.card-footer:empty {
    display: none;
}

/* Tabela embutida direto no card: some a borda/raio proprios */
.card .card-body .table-wrap {
    border: 0;
    border-radius: 0;
}

    .card .card-body .table-wrap:last-child {
        border-radius: 0 0 var(--radius-lg) var(--radius-lg);
        overflow: hidden;
    }

/* Conteudo do ChildContent de um Card que precisa ficar rente a borda do
   card, escapando do padding do .card-body sem precisar nomear cada
   elemento interno. Embrulhe em <div class="card-body-flush">. */
.card .card-body > .card-body-flush {
    margin: calc(var(--sp-5) * -1);
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — TABELA
   Base no TableTemplate do essentials (thead/tbody, hover, .table-actions,
   estados de busca), refinada: classe .table (nao seletor global), tokens,
   dark, + estados empty / loading (skeleton) — REGRA DE OURO.
   O skeleton vive em skeleton.css (folha oficial) e e importado pelo
   framework.css, antes deste arquivo na cascata.
   ========================================================================= */

/* SEM rolagem horizontal — NUNCA. A tabela adapta pra baixo: o texto quebra e,
   em <=640px, cada linha vira um bloco rotulado (data-label no <td>). */
.table-wrap {
    width: 100%;
    background: var(--color-surface);
    border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-lg);
}

.table {
    width: 100%;
    min-width: 0;
    border-collapse: collapse;
    font-size: var(--fs-base);
    color: var(--color-text);
    overflow-wrap: anywhere;
}

    .table thead th {
        text-align: left;
        font-size: var(--fs-sm);
        font-weight: var(--fw-semibold);
        color: var(--color-text-muted);
        text-transform: uppercase;
        letter-spacing: 0.02em;
        background: var(--color-surface-2);
        padding: var(--sp-3) var(--sp-4);
        border-bottom: var(--border-w) solid var(--color-border);
    }

    .table tbody td {
        padding: var(--sp-3) var(--sp-4);
        border-bottom: var(--border-w) solid var(--color-border);
        vertical-align: middle;
    }

    .table tbody tr:last-child td {
        border-bottom: 0;
    }

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

    .table th:first-child, .table td:first-child {
        padding-left: var(--sp-5);
    }

    .table th:last-child, .table td:last-child {
        padding-right: var(--sp-5);
    }

    /* Cabecalho segue o alinhamento do corpo nas colunas de acao/numero — sem
       isso thead th (0-1-2) vence .col-actions/.col-num (0-1-0) e o titulo
       fica a esquerda enquanto os valores ficam a direita. */
    .table thead th.col-actions, .table thead th.col-num {
        text-align: right;
    }

    /* Totalizador — linha de resumo no rodape da tabela (tfoot) */
    .table tfoot td {
        padding: var(--sp-3) var(--sp-4);
        background: var(--color-surface-2);
        border-top: 2px solid var(--color-border-strong);
        color: var(--color-text);
        font-weight: var(--fw-semibold);
        font-size: var(--fs-sm);
    }

        .table tfoot td:first-child {
            padding-left: var(--sp-5);
            color: var(--color-text-muted);
            font-weight: var(--fw-medium);
            text-transform: uppercase;
            letter-spacing: 0.02em;
        }

        .table tfoot td:last-child {
            padding-right: var(--sp-5);
        }

    .table tfoot .col-num {
        font-variant-numeric: tabular-nums;
        font-size: var(--fs-base);
        color: var(--color-text);
    }

/* Barra de filtros — acima da tabela, dentro do card */
.table-toolbar {
    display: flex;
    align-items: flex-end;
    gap: var(--sp-3);
    flex-wrap: wrap;
    padding: var(--sp-4) var(--sp-5);
    background: var(--color-surface);
    border-bottom: var(--border-w) solid var(--color-border);
}

    .table-toolbar .toolbar-field {
        flex: 1 1 160px;
        min-width: 0;
    }

    .table-toolbar .lbl {
        margin-bottom: var(--sp-1);
        font-size: var(--fs-xs);
        font-weight: var(--fw-medium);
        color: var(--color-text-muted);
    }

    .table-toolbar .toolbar-actions {
        display: inline-flex;
        align-items: center;
        gap: var(--sp-2);
        margin-left: auto;
    }

@media (max-width: 640px) {
    .table-toolbar .toolbar-field {
        flex-basis: 100%;
    }

    .table-toolbar .toolbar-actions {
        margin-left: 0;
        width: 100%;
    }

        .table-toolbar .toolbar-actions .btn-action {
            flex: 1 1 auto;
        }
}

/* Abas de filtro — cabecalho de listagem: .tabs (com .tab-count) a esquerda e
   uma busca a direita, tudo acima da tabela dentro do card. A barra dona da
   borda inferior; a .tabs perde a propria e o sublinhado ativo encosta nela. */
.table-tabs {
    display: flex;
    align-items: flex-end;
    gap: var(--sp-4);
    padding: var(--sp-2) var(--sp-5) 0;
    background: var(--color-surface);
    border-bottom: var(--border-w) solid var(--color-border);
}

    .table-tabs .tabs {
        flex: 1 1 auto;
        min-width: 0;
    }

    .table-tabs .table-tabs-search {
        flex: none;
        width: min(340px, 40%);
        align-self: center;
        margin-bottom: var(--sp-2);
    }

@media (max-width: 640px) {
    .table-tabs {
        flex-direction: column;
        align-items: stretch;
        gap: var(--sp-3);
        padding: 0 var(--sp-4) var(--sp-3);
    }

        .table-tabs .tabs {
            margin: 0 calc(var(--sp-4) * -1);
            padding: 0 var(--sp-4);
        }

        .table-tabs .table-tabs-search {
            width: 100%;
            margin-bottom: 0;
        }
}

/* Celula sem valor — placeholder automatico. <td> vazio no corpo ganha um
   traco em cor sutil, sem markup: no Blazor basta a expressao vir vazia. Usa
   ::after para nao colidir com o rotulo (::before via data-label) no mobile,
   onde a linha vira label a esquerda e "—" a direita. */
.table tbody td:empty::after {
    content: "—";
    color: var(--color-text-subtle);
}

.col-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.col-id {
    width: 1%;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.col-actions {
    text-align: right;
    white-space: nowrap;
}

.table-actions {
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--sp-2);
}

.table-compact thead th, .table-compact tbody td {
    padding: var(--sp-2) var(--sp-3);
}

/* Empty state — LEGADO. Novo codigo usa .empty-state (empty-state.css) dentro
   do <td colspan>; .table-empty fica so pelo que ja existe. */
.table-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-9) var(--sp-4);
    text-align: center;
    color: var(--color-text-subtle);
}

.table-empty-icon {
    width: 32px;
    height: 32px;
    color: var(--color-text-subtle);
}

.table-empty-title {
    font-size: var(--fs-base);
    font-weight: var(--fw-medium);
    color: var(--color-text-muted);
}

/* =========================================================================
   ADAPTA PRA BAIXO (<=640px) — linha empilhada, rotulo vem de data-label.
   Cabecalho vira redundante e sai; celula sem data-label ocupa a largura toda
   (bom pra skeleton e pra <td colspan> com empty-state).
   ========================================================================= */
@media (max-width: 640px) {
    .table-wrap:not(.viewport-guard-desk *) {
        background: none;
        border: 0;
        border-radius: 0;
    }

    .card > .table-wrap:not(.viewport-guard-desk *) {
        padding: var(--sp-3);
    }

    .table:not(.viewport-guard-desk *), .table:not(.viewport-guard-desk *) tbody, .table:not(.viewport-guard-desk *) tfoot, .table:not(.viewport-guard-desk *) tr, .table:not(.viewport-guard-desk *) td {
        display: block;
        width: 100%;
    }

        .table:not(.viewport-guard-desk *) thead {
            display: none;
        }

        .table:not(.viewport-guard-desk *) tbody tr {
            background: var(--color-surface);
            border: var(--border-w) solid var(--color-border);
            border-radius: var(--radius-md);
            padding: var(--sp-2) 0;
        }

            .table:not(.viewport-guard-desk *) tbody tr + tr {
                margin-top: var(--sp-3);
            }

            .table:not(.viewport-guard-desk *) tbody tr:hover {
                background: var(--color-surface);
            }

        .table:not(.viewport-guard-desk *) tbody td {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: var(--sp-4);
            padding: var(--sp-2) var(--sp-4);
            border-bottom: 0;
            text-align: right;
        }

            .table:not(.viewport-guard-desk *) tbody td[data-label]::before {
                content: attr(data-label);
                flex: none;
                text-align: left;
                font-size: var(--fs-xs);
                font-weight: var(--fw-semibold);
                letter-spacing: var(--ls-wide);
                text-transform: uppercase;
                color: var(--color-text-subtle);
            }

        .table:not(.viewport-guard-desk *) th:first-child, .table:not(.viewport-guard-desk *) td:first-child,
        .table:not(.viewport-guard-desk *) th:last-child, .table:not(.viewport-guard-desk *) td:last-child {
            padding-left: var(--sp-4);
            padding-right: var(--sp-4);
        }

        .table:not(.viewport-guard-desk *) td[colspan] {
            padding: 0;
        }

        .table:not(.viewport-guard-desk *) tfoot td {
            display: flex;
            justify-content: space-between;
            gap: var(--sp-4);
            border-top: 0;
        }

            .table:not(.viewport-guard-desk *) tfoot td:first-child {
                border-top: 2px solid var(--color-border-strong);
            }

        .table:not(.viewport-guard-desk *) .col-actions, .table:not(.viewport-guard-desk *) .col-num {
            text-align: right;
        }

        .table:not(.viewport-guard-desk *) .col-id {
            white-space: normal;
        }

    .table-compact:not(.viewport-guard-desk *) tbody td {
        padding: var(--sp-2) var(--sp-3);
    }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — VIEWPORT GUARD (.viewport-guard)
   Escape hatch, NAO atalho. Envolve UM BLOCO cujo conteudo e genuinamente 2D
   (matriz de colunas editaveis, cronograma, planilha) e que nao tem leitura
   honesta em <640px. Abaixo do limite ele: (1) avisa, e (2) mantem o bloco
   utilizavel em largura de desktop dentro de uma moldura com rolagem lateral —
   nunca bloqueia. Mobile aqui e acesso de emergencia sem PC: negar acesso
   contraria o motivo de a tela existir.

   Quando NAO usar: tabela de leitura (table.css empilha), formulario (uma
   coluna), lista, card. Se da pra adaptar, adapte — o guard nao substitui
   trabalho de responsividade.

   Markup:
     .viewport-guard-note                 (aviso DA TELA — no topo, sob o page-head)
     .viewport-guard                      (envolve o bloco largo)
       > .viewport-guard-frame            (moldura que rola na horizontal)
         > .viewport-guard-desk           (conteudo em largura de desktop)

   O aviso e reclamacao DA TELA, nao do bloco: vive no topo, uma vez, junto do
   page-head — nao repetido dentro de cada bloco largo.

   MARCADOR DECLARATIVO — a tela nao decide, o componente declara.
   Componente que so tem leitura honesta em tela larga carrega na PROPRIA RAIZ:
     .needs-wide      exige >=640px
     .needs-wide-lg   exige >=1024px
   O aviso fica sempre no topo da tela (custo zero quando nao aparece) e o
   `:has()` o liga quando a tela contem algum componente marcado E a viewport
   esta abaixo do limite DESSE componente. Sem JS, sem a tela saber quais
   componentes tem dentro — inclui um componente marcado, o aviso aparece; tira,
   desaparece. `.viewport-guard` e marcador de si mesmo (`.viewport-guard-lg` no
   limite alto), entao a guarda nao precisa repetir a classe.

   `.needs-wide*` SEM guarda e legitimo: componente que precisa de largura mas
   nao rola numa moldura (grafico, mapa, canvas) — marca e pronto, a tela avisa.

   REGRA DE LIMITE: a guarda tem que cobrir TODA a faixa em que o componente
   guardado adaptaria pra baixo, senao sobra uma faixa sem modo bloco e sem
   moldura. Limite padrao 640px; `.viewport-guard-lg` sobe pra 1024px — e o
   correto para `live-table`: sete colunas de controle nao cabem ao lado da
   sidebar de 248px antes disso.

   No Blazor: markup identico; nada de JS. O marcador vai na raiz do proprio
   componente (`.razor`), nao na tela que o usa.
   ========================================================================= */
.viewport-guard { display: flex; flex-direction: column; gap: var(--sp-3); min-width: 0; }

/* Aviso da tela: oculto por padrao; quem o liga sao as duas @media do fim. */
.viewport-guard-note {
  display: none; align-items: flex-start; gap: var(--sp-3); margin: 0 0 var(--sp-5);
  padding: var(--sp-4); border: var(--border-w) solid var(--color-warning);
  border-radius: var(--radius-lg); background: var(--color-warning-soft);
  color: var(--color-text);
}
.viewport-guard-note svg { flex: none; width: 20px; height: 20px; margin-top: 2px; color: var(--color-warning); }
.viewport-guard-note-body { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.viewport-guard-note-title { margin: 0; font-size: var(--fs-base); font-weight: var(--fw-semibold); }
.viewport-guard-note-text { margin: 0; font-size: var(--fs-sm); color: var(--color-text-muted); text-wrap: pretty; }

.viewport-guard-frame {
  min-width: 0; overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
  scrollbar-width: thin; -webkit-overflow-scrolling: touch;
  border-radius: var(--radius-lg);
}
.viewport-guard-desk { width: 1080px; }
.viewport-guard-wide .viewport-guard-desk { width: 1280px; }

/* Guarda embutida direto no card: nem a moldura nem a tabela reintroduzem
   borda/raio proprios (card.css some com eles em `.card > .table-wrap`, que a
   moldura no meio deixou de casar). O raio de baixo e do card, no ultimo filho. */
.card > .viewport-guard .table-wrap { border: 0; border-radius: 0; }
.card > .viewport-guard .viewport-guard-frame { border-radius: 0; }
.card > .viewport-guard:last-child .viewport-guard-frame { border-radius: 0 0 var(--radius-lg) var(--radius-lg); }
.card > .viewport-guard:last-child .table-wrap { border-radius: 0 0 var(--radius-lg) var(--radius-lg); }

/* =========================================================================
   DENTRO DA MOLDURA O CONTEUDO E DESKTOP
   As @media dos componentes leem a viewport (390px), nao a moldura — entao as
   adaptacoes pra baixo excluem o conteudo guardado NA ORIGEM: em table.css,
   live-table.css e stepper.css cada seletor de tela estreita leva
   :not(.viewport-guard-desk *). Componente novo que possa entrar numa guarda
   faz o mesmo — escopar aqui, por propriedade, sempre deixa vazar tamanho.
   ========================================================================= */

@media (min-width: 640px) {
  .viewport-guard:not(.viewport-guard-lg) .viewport-guard-frame { overflow: visible; border-radius: 0; }
  .viewport-guard:not(.viewport-guard-lg) .viewport-guard-desk { width: auto; }
}

/* Limite alto (1024px) — para bloco que nao cabe nem em laptop ao lado da
   sidebar, como a tabela viva. */
@media (min-width: 1024px) {
  .viewport-guard-lg .viewport-guard-frame { overflow: visible; border-radius: 0; }
  .viewport-guard-lg .viewport-guard-desk { width: auto; }
}

/* =========================================================================
   AVISO AUTOMATICO (:has())
   A tela nao lista o que tem dentro: se QUALQUER descendente pede tela larga e
   a viewport esta abaixo do limite dele, o aviso do topo aparece. Os dois
   limites sao independentes — 640px para `.needs-wide`/guarda padrao, 1024px
   para `.needs-wide-lg`/`.viewport-guard-lg`.
   ========================================================================= */
@media (max-width: 639.98px) {
  body:has(.needs-wide, .viewport-guard:not(.viewport-guard-lg)) .viewport-guard-note { display: flex; }
}
@media (max-width: 1023.98px) {
  body:has(.needs-wide-lg, .viewport-guard-lg) .viewport-guard-note { display: flex; }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — TABELA VIVA (linhas de item)
   Tabela que nasce vazia e cresce por acao do usuario: "+ Adicionar item" cria
   uma linha JA em edicao (foco no 1o campo). Nao ha confirmar por linha — o que
   esta digitado e o item; a persistencia e do Salvar da tela.
   Uso: <table class="table live-table"> (herda thead/tfoot/hover de table.css).

     .live-table              -> tabela de itens (densa, celula = controle)
     .live-table-control      -> input/select dentro da celula (borda so no hover/foco)
     .live-table-index        -> celula do "#", com alca de arrastar
     .live-table-handle       -> alca de reordenar (arrastar)
     .live-table-computed     -> valor calculado, nao editavel (total da linha)
     .live-table-combo        -> celula com busca no catalogo (reusa .autocomplete-menu)
     .live-table-add          -> rodape de acao ("+ Adicionar item")
     .live-table-hint         -> dica de teclado no rodape
     .live-table-edit         -> "Editar" da linha (aparece so no celular)
   Estados na <tr>: .is-invalid (celula obrigatoria vazia), .is-locked (item
   travado, somente leitura), .is-dragging / .is-drop-target (reordenacao).
   Vazio, skeleton e loading vem das folhas oficiais (empty-state.css,
   skeleton.css, loading.css) — nada proprio aqui.
   ========================================================================= */

/* Celula = moldura do controle: padding minimo, o controle preenche */
.live-table tbody td { padding: var(--sp-1) var(--sp-2); }
.live-table tbody td:first-child { padding-left: var(--sp-3); }
.live-table tbody td:last-child { padding-right: var(--sp-4); }
.live-table tbody tr:hover { background: transparent; }

/* Larguras (so no layout em colunas) — o Produto e a coluna elastica */
.live-table .live-col-index   { width: 52px; }
.live-table .live-col-code    { width: 148px; }
.live-table .live-col-qty     { width: 96px; }
.live-table .live-col-price   { width: 136px; }
.live-table .live-col-total   { width: 136px; }
.live-table .live-col-actions { width: 84px; }

/* ============================== CONTROLE ================================ */
.live-table-control {
  display: block; width: 100%; min-width: 0; min-height: 34px;
  padding: var(--sp-2) var(--sp-2); background: transparent;
  border: var(--border-w) solid transparent; border-radius: var(--radius-md);
  font-family: var(--font-sans); font-size: var(--fs-base); color: var(--color-text);
  outline: none; transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.live-table-control::placeholder { color: var(--color-text-subtle); }
.live-table-control:hover:not(:disabled) { border-color: var(--color-border); background: var(--color-surface-2); }
.live-table-control:focus-visible {
  border-color: var(--color-primary); background: var(--color-surface);
  box-shadow: 0 0 0 3px var(--color-focus-ring);
}
.live-table-control:disabled { color: var(--color-text-subtle); background: transparent; cursor: not-allowed; }
.live-table-control.col-num,
td.col-num > .live-table-control { text-align: right; font-variant-numeric: tabular-nums; }

/* Select na celula: wrapper com a seta por mascara (cor de token, sem hex solto) */
.live-table-select { position: relative; display: block; }
select.live-table-control { appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: var(--sp-6); }
.live-table-select::after {
  content: ""; position: absolute; right: var(--sp-2); top: 50%; transform: translateY(-50%);
  width: 15px; height: 15px; pointer-events: none; background-color: var(--color-text-subtle);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* Validacao de celula — borda vermelha permanente + mensagem curta embaixo */
.live-table-control.invalid { border-color: var(--color-danger); background: var(--color-danger-soft); }
.live-table-control.invalid:focus-visible { box-shadow: 0 0 0 3px var(--color-danger-soft); }
.live-table .validation-message { margin-top: 2px; padding-left: var(--sp-2); font-size: var(--fs-xs); }
.live-table tbody tr.is-invalid td { background: light-dark(color-mix(in oklab, var(--color-danger) 5%, transparent), color-mix(in oklab, var(--color-danger) 9%, transparent)); }

/* ========================= INDICE E ALCA DE ARRASTAR ==================== */
.live-table-index {
  color: var(--color-text-subtle); font-size: var(--fs-sm); font-variant-numeric: tabular-nums;
}
.live-table-index-inner { display: flex; align-items: center; gap: var(--sp-1); }
.live-table-handle {
  display: grid; place-items: center; flex: none; width: 22px; height: 26px; padding: 0;
  border: 0; border-radius: var(--radius-sm); background: transparent;
  color: var(--color-text-subtle); cursor: grab; opacity: 0;
  transition: opacity var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.live-table-handle svg { width: 15px; height: 15px; }
.live-table-handle:hover { background: var(--color-surface-hover); color: var(--color-text-muted); }
.live-table-handle:focus-visible { outline: none; opacity: 1; box-shadow: 0 0 0 2px var(--color-focus-ring); }
.live-table tbody tr:hover .live-table-handle,
.live-table tbody tr:focus-within .live-table-handle { opacity: 1; }
.live-table tbody tr.is-dragging { opacity: 0.45; }
.live-table tbody tr.is-drop-target td { box-shadow: inset 0 2px 0 0 var(--color-primary); }

/* ============================ VALOR CALCULADO =========================== */
.live-table-computed {
  display: block; padding: var(--sp-2); font-size: var(--fs-base); font-weight: var(--fw-medium);
  color: var(--color-text); text-align: right; font-variant-numeric: tabular-nums;
}
.live-table-computed.is-empty { color: var(--color-text-subtle); font-weight: var(--fw-regular); }

/* ============================== LINHA TRAVADA =========================== */
.live-table tbody tr.is-locked td { background: var(--color-surface-2); }
.live-table tbody tr.is-locked .live-table-control { border-color: transparent; background: transparent; color: var(--color-text-muted); pointer-events: none; }
.live-table tbody tr.is-locked .live-table-handle { display: none; }
.live-table-lock { display: inline-grid; place-items: center; width: 28px; height: 28px; color: var(--color-text-subtle); }
.live-table-lock svg { width: 15px; height: 15px; }

/* ========================= BUSCA NO CATALOGO ============================ */
.live-table-combo { position: relative; }
.live-table-combo[data-open="false"] .autocomplete-menu { display: none; }
.live-table-combo .autocomplete-menu { min-width: 260px; }

/* ==================== RODAPE DE TOTAIS ("footer items") =================
   O rodape e opcional e composto: cada item e UMA linha dentro de
   <tfoot class="live-table-summary">. Nenhum total a mostrar? Nao escreva o
   tfoot — nada sobra na tabela.

     <tfoot class="live-table-summary">
       <tr class="live-table-summary-row">
         <th class="live-table-summary-label" colspan="5" scope="row">Subtotal</th>
         <td class="live-table-summary-value">R$ 1.405,20</td><td></td>
       </tr>
     </tfoot>

   colspan do rotulo = numero de colunas ANTES da coluna do valor; o que vier
   depois do valor (a coluna de acoes, quando existe) entra como <td> vazio. Variacoes SOMADAS na linha:
     .is-editable  valor e campo (desconto digitado) — use .live-table-control
     .is-subtract  valor abate do total (o sinal − vai no conteudo, nao no CSS)
     .is-muted     linha informativa (contagem, peso, volume), sem enfase
     .is-total     fecho da conta — sempre a ultima linha, tipo maior
   Nota curta sob o rotulo: <span class="live-table-summary-note">.
   ======================================================================== */
.live-table tfoot.live-table-summary th,
.live-table tfoot.live-table-summary td { background: transparent; border-top: 0; border-bottom: 0; font-size: var(--fs-base); font-weight: var(--fw-regular); text-transform: none; letter-spacing: normal; }
.live-table tfoot.live-table-summary .live-table-summary-row > th,
.live-table tfoot.live-table-summary .live-table-summary-row > td { padding: var(--sp-2) var(--sp-2); }
.live-table tfoot.live-table-summary .live-table-summary-row:first-child > th,
.live-table tfoot.live-table-summary .live-table-summary-row:first-child > td { padding-top: var(--sp-3); border-top: 2px solid var(--color-border-strong); }
.live-table tfoot.live-table-summary .live-table-summary-row:last-child > th,
.live-table tfoot.live-table-summary .live-table-summary-row:last-child > td { padding-bottom: var(--sp-3); }
.live-table tfoot.live-table-summary .live-table-summary-row:last-child > td:last-child,
.live-table tfoot.live-table-summary .live-table-summary-row > td:last-child { padding-right: var(--sp-4); }
.live-table tfoot.live-table-summary .live-table-summary-label {
  text-align: right; font-size: var(--fs-sm); font-weight: var(--fw-medium);
  color: var(--color-text-muted); white-space: normal;
}
.live-table-summary-note { display: block; font-size: var(--fs-xs); font-weight: var(--fw-regular); color: var(--color-text-subtle); }
.live-table tfoot.live-table-summary .live-table-summary-value {
  text-align: right; font-size: var(--fs-base); font-weight: var(--fw-medium);
  color: var(--color-text); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.live-table-summary-row.is-muted .live-table-summary-label,
.live-table-summary-row.is-muted .live-table-summary-value { font-size: var(--fs-sm); font-weight: var(--fw-regular); color: var(--color-text-subtle); }
.live-table-summary-row.is-subtract .live-table-summary-value { color: var(--color-text-muted); }
.live-table-summary-row.is-editable .live-table-control { min-height: 30px; padding-block: var(--sp-1); }
.live-table tfoot.live-table-summary .live-table-summary-row.is-total > th,
.live-table tfoot.live-table-summary .live-table-summary-row.is-total > td { padding-top: var(--sp-3); border-top: var(--border-w) solid var(--color-border); }
.live-table tfoot.live-table-summary .live-table-summary-row.is-total .live-table-summary-label { color: var(--color-text); font-weight: var(--fw-semibold); }
.live-table tfoot.live-table-summary .live-table-summary-row.is-total .live-table-summary-value { font-size: var(--fs-lg); font-weight: var(--fw-bold); }

/* =============================== BORDERED ==============================
   Variante opcional: moldura externa. Enquadra a tabela inteira com uma unica
   borda ao redor, sem divisores verticais entre colunas — as linhas horizontais
   que a .table ja desenha continuam. Delimita a tabela quando ela nao esta
   dentro de um .table-wrap emoldurado.
   Uso: <table class="table live-table live-table-bordered">. So no layout em
   colunas; no bloco do celular some (cada linha ja e um cartao). */
.live-table-bordered { border: var(--border-w) solid var(--color-border); }

/* Extensao local — o Design System nao define esta combinacao (o card de
   BORDERED nao mostra rodape junto). Quando um LiveTableAdd (Rodape) segue a
   tabela no mesmo .table-wrap, ele entra na mesma moldura: a tabela perde a
   borda de baixo (o rodape fecha o quadro) e o rodape ganha os lados e a base,
   senão a moldura "abre" nele. */
.live-table-bordered:has(+ .live-table-add) { border-bottom: 0; }
.live-table-bordered + .live-table-add {
  border-right: var(--border-w) solid var(--color-border);
  border-bottom: var(--border-w) solid var(--color-border);
  border-left: var(--border-w) solid var(--color-border);
}

/* =============================== AGRUPADO ==============================
   Itens agrupados por um "dono" (integrador, fornecedor, categoria). Cada grupo
   abre com uma linha de cabecalho <tr class="live-table-group">: o nome do
   grupo (enfase de marca), um badge de condicao e a acao do grupo inteiro
   (ex.: Remover integrador) a direita. Os itens seguem como linhas normais ate
   o proximo cabecalho. Variante de LEITURA: o nome vira coluna forte
   (.live-table-item-name) e o valor sai como .live-table-computed — sem campo.
     <table class="table live-table live-table-grouped">
       <tr class="live-table-group">
         <td class="live-table-group-head" colspan="3">
           <span class="live-table-group-inner">
             <span class="live-table-group-heading">
               <span class="live-table-group-name">DETRAN-MG</span>
               <span class="badge badge-primary badge-sm">Preço tabelado</span>
             </span>
             <span class="table-actions">…Remover…</span>
           </span>
         </td>
       </tr>
   O cabecalho ocupa uma unica celula com colspan das colunas todas; dentro dela
   o .live-table-group-inner e um flex space-between que poe nome+badge a
   esquerda e a acao a direita. Os itens
   seguem como linhas normais ate o proximo cabecalho. No Blazor, cada grupo e um
   foreach do modelo e o Remover dispara @onclick no dono, nao na linha. */
.live-table tbody tr.live-table-group > td {
  background: var(--color-surface-2);
  border-top: var(--border-w) solid var(--color-border);
  padding: var(--sp-2) var(--sp-3); vertical-align: middle;
}
.live-table tbody tr.live-table-group:first-child > td { border-top: 0; }
.live-table tbody tr.live-table-group:hover > td { background: var(--color-surface-2); }
.live-table td.live-table-group-head { text-align: left; }
.live-table-group-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap;
}
.live-table-group-heading { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.live-table-group-name {
  font-size: var(--fs-xs); font-weight: var(--fw-semibold); text-transform: uppercase;
  letter-spacing: var(--ls-wide); color: var(--color-primary);
}
.live-table-group-head .table-actions { flex: none; justify-content: flex-end; }
/* Coluna forte da linha de leitura (o nome da modalidade/servico) */
.live-table td.live-table-item-name {
  font-size: var(--fs-base); font-weight: var(--fw-medium); color: var(--color-text);
  padding: var(--sp-3) var(--sp-2);
}
.live-table tbody tr:hover td.live-table-item-name { color: var(--color-text); }

/* ========================= "+ ADICIONAR ITEM" =========================== */
.live-table-add {
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4); background: var(--color-surface);
  border-top: var(--border-w) solid var(--color-border);
}
.table-wrap > .live-table-add { border-radius: 0 0 var(--radius-lg) var(--radius-lg); }
.live-table-hint { font-size: var(--fs-xs); color: var(--color-text-subtle); }
.live-table-count { margin-left: auto; font-size: var(--fs-xs); color: var(--color-text-subtle); font-variant-numeric: tabular-nums; }

/* "Editar" da linha — so no celular (ver adaptacao abaixo) */
.live-table td .live-table-edit { display: none; }

/* =========================================================================
   ADAPTA PRA BAIXO (<=900px, ajustado do original 1000px — lista fechada da v3)
   — linha vira BLOCO EM LEITURA + "Editar". Sem rolagem horizontal, nunca:
   seis colunas de controle nao cabem numa tela estreita, entao a tabela viva
   empilha ANTES do breakpoint das tabelas de leitura (table.css, <=640px) e
   repete aqui aquelas regras de bloco.
   Os controles continuam no DOM (mostram o valor como texto) mas nao recebem
   toque; a edicao acontece no painel lateral (offcanvas-form.css).
   No Blazor: readonly/disabled por breakpoint e o "Editar" abre o OffCanvas.
   ========================================================================= */
@media (max-width: 900px) {
  .table-wrap:has(> .live-table):not(.viewport-guard-desk *){ background: none; border: 0; border-radius: 0; }
  .card > .table-wrap:has(> .live-table):not(.viewport-guard-desk *){ padding: var(--sp-3); }
  .live-table:not(.viewport-guard-desk *), .live-table:not(.viewport-guard-desk *) tbody, .live-table:not(.viewport-guard-desk *) tfoot, .live-table:not(.viewport-guard-desk *) tr, .live-table:not(.viewport-guard-desk *) td{ display: block; width: 100%; }
  .live-table:not(.viewport-guard-desk *) thead{ display: none; }
  .live-table:not(.viewport-guard-desk *) tbody tr{
    background: var(--color-surface); border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-md); padding: var(--sp-2) 0;
  }
  .live-table:not(.viewport-guard-desk *) tbody tr + tr{ margin-top: var(--sp-3); }
  .live-table:not(.viewport-guard-desk *) tbody td{
    display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
    padding: var(--sp-2) var(--sp-4); border-bottom: 0; text-align: right; flex-wrap: wrap;
  }
  .live-table-bordered:not(.viewport-guard-desk *){ border: 0; }
  .live-table:not(.viewport-guard-desk *) tbody td[data-label]::before{
    content: attr(data-label); flex: none; text-align: left;
    font-size: var(--fs-xs); font-weight: var(--fw-semibold); letter-spacing: var(--ls-wide);
    text-transform: uppercase; color: var(--color-text-subtle);
  }
  .live-table:not(.viewport-guard-desk *) td[colspan]{ padding: 0; }
  .live-table:not(.viewport-guard-desk *) td[colspan]::before{ content: none; }
  .live-table:not(.viewport-guard-desk *) tfoot td{ display: flex; justify-content: space-between; gap: var(--sp-4); border-top: 0; padding: var(--sp-2) var(--sp-4); }
  .live-table-summary:not(.viewport-guard-desk *){ display: block; width: 100%; margin-top: var(--sp-3); background: var(--color-surface); border: var(--border-w) solid var(--color-border); border-radius: var(--radius-md); padding: var(--sp-2) 0; }
  .live-table:not(.viewport-guard-desk *) tr.live-table-summary-row{ display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4); width: 100%; }
  .live-table:not(.viewport-guard-desk *) tfoot.live-table-summary .live-table-summary-row > th,
  .live-table:not(.viewport-guard-desk *) tfoot.live-table-summary .live-table-summary-row > td,
  .live-table:not(.viewport-guard-desk *) tfoot.live-table-summary .live-table-summary-row:first-child > th,
  .live-table:not(.viewport-guard-desk *) tfoot.live-table-summary .live-table-summary-row:first-child > td,
  .live-table:not(.viewport-guard-desk *) tfoot.live-table-summary .live-table-summary-row.is-total > th,
  .live-table:not(.viewport-guard-desk *) tfoot.live-table-summary .live-table-summary-row.is-total > td{ display: block; width: auto; padding: var(--sp-2) var(--sp-4); border-top: 0; }
  .live-table:not(.viewport-guard-desk *) tfoot.live-table-summary .live-table-summary-label{ text-align: left; }
  .live-table:not(.viewport-guard-desk *) tfoot.live-table-summary .live-table-summary-row > td:empty{ display: none; }
  .live-table-summary-row.is-total:not(.viewport-guard-desk *){ border-top: var(--border-w) solid var(--color-border); margin-top: var(--sp-1); padding-top: var(--sp-1); }
  .live-table:not(.viewport-guard-desk *) tfoot.live-table-summary .live-table-summary-value{ flex: none; }
  .live-table:not(.viewport-guard-desk *) tbody tr.is-invalid td{ background: none; }
  .live-table:not(.viewport-guard-desk *) tbody tr.is-invalid{ border-color: var(--color-danger); }
  .live-table:not(.viewport-guard-desk *) tbody tr.is-locked td{ background: none; }
  .live-table:not(.viewport-guard-desk *) tbody tr.is-locked{ background: var(--color-surface-2); }
  .live-table-control:not(.viewport-guard-desk *),
  .live-table-computed:not(.viewport-guard-desk *){
    flex: 1 1 auto; width: auto; min-width: 0; min-height: 0; padding: 0; text-align: right;
    border-color: transparent; background: transparent; pointer-events: none;
  }
  .live-table:not(.viewport-guard-desk *) tfoot .live-table-control{ padding: 0; }
  .live-table-select::after:not(.viewport-guard-desk *){ display: none; }
  .live-table-combo:not(.viewport-guard-desk *){ flex: 1 1 auto; min-width: 0; }
  .live-table-combo:not(.viewport-guard-desk *) .live-table-control{ width: 100%; }
  .live-table-control:hover:not(.viewport-guard-desk *){ border-color: transparent; background: transparent; }
  .live-table-handle:not(.viewport-guard-desk *){ display: none; }
  .live-table-index:not(.viewport-guard-desk *){ color: var(--color-text-subtle); }
  .live-table:not(.viewport-guard-desk *) td.col-actions .table-actions{ gap: var(--sp-1); }
  .live-table:not(.viewport-guard-desk *) td .live-table-edit{ display: inline-flex; pointer-events: auto; }
  .live-table:not(.viewport-guard-desk *) .validation-message{ flex: 0 0 100%; padding-left: 0; text-align: right; }
  .live-table-add:not(.viewport-guard-desk *){ border-top: 0; border-radius: var(--radius-lg); border: var(--border-w) solid var(--color-border); margin-top: var(--sp-3); }

  /* Agrupado no bloco: o cabecalho de grupo vira faixa, itens seguem em cartao */
  .live-table:not(.viewport-guard-desk *) tbody tr.live-table-group{
    display: block; background: var(--color-surface-2); border: 0;
    border-radius: var(--radius-md); padding: 0; margin-top: var(--sp-3);
  }
  .live-table:not(.viewport-guard-desk *) tbody tr.live-table-group > td{
    display: block; width: auto; background: transparent; border: 0; padding: var(--sp-2) var(--sp-3);
  }
  .live-table:not(.viewport-guard-desk *) tbody tr.live-table-group td::before{ content: none; }
  .live-table:not(.viewport-guard-desk *) tbody tr.live-table-group + tr{ margin-top: var(--sp-2); }
  .live-table:not(.viewport-guard-desk *) td.live-table-item-name{ justify-content: flex-start; text-align: left; }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — ESTADO VAZIO (GENERICO)
   Nome oficial: .empty-state. Serve em qualquer container (card, painel,
   offcanvas, lista, grade, celula de tabela). Substitui os vazios locais
   (.table-empty / .media-empty ficam como legado dos seus componentes).

     .empty-state          -> bloco centralizado
     .empty-state-figure   -> moldura circular do icone (opcional)
     .empty-state-icon     -> SVG inline (so SVG inline)
     .empty-state-title    -> titulo curto e afirmativo
     .empty-state-text     -> uma frase dizendo o proximo passo
     .empty-state-actions  -> area de acoes (.btn-action)
   Modificadores: .empty-state-sm (denso), .empty-state-inline (horizontal, p/
   painel estreito), .empty-state-boxed (moldura tracejada, p/ area de drop),
   e a cor do icone por intencao: .empty-state-info / -warning / -danger.
   ========================================================================= */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--sp-3);
    padding: var(--sp-9) var(--sp-5);
    text-align: center;
    color: var(--color-text-muted);
}

.empty-state-figure {
    display: grid;
    place-items: center;
    flex: none;
    width: 56px;
    height: 56px;
    border-radius: var(--radius-full);
    background: var(--color-surface-2);
    border: var(--border-w) solid var(--color-border);
    color: var(--color-text-subtle);
}

.empty-state-icon {
    width: 28px;
    height: 28px;
    flex: none;
    color: var(--color-text-subtle);
}

    .empty-state-figure .empty-state-icon {
        width: 26px;
        height: 26px;
        color: inherit;
    }

.empty-state-title {
    margin: 0;
    font-size: var(--fs-lg);
    font-weight: var(--fw-semibold);
    line-height: var(--lh-snug);
    color: var(--color-text);
}

.empty-state-text {
    margin: 0;
    max-width: 46ch;
    font-size: var(--fs-sm);
    line-height: var(--lh-normal);
    color: var(--color-text-muted);
    text-wrap: pretty;
}

.empty-state-actions {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    flex-wrap: wrap;
    margin-top: var(--sp-1);
}

/* Denso — dentro de card pequeno, dropdown, coluna de dashboard */
.empty-state-sm {
    gap: var(--sp-2);
    padding: var(--sp-6) var(--sp-4);
}

    .empty-state-sm .empty-state-figure {
        width: 40px;
        height: 40px;
    }

        .empty-state-sm .empty-state-figure .empty-state-icon {
            width: 20px;
            height: 20px;
        }

    .empty-state-sm .empty-state-title {
        font-size: var(--fs-base);
    }

/* Horizontal — painel lateral estreito / bloco dentro de formulario */
.empty-state-inline {
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    text-align: left;
    gap: var(--sp-4);
    padding: var(--sp-5) var(--sp-4);
}

    .empty-state-inline .empty-state-body {
        display: flex;
        flex-direction: column;
        gap: var(--sp-1);
        min-width: 0;
    }

    .empty-state-inline .empty-state-actions {
        margin-top: 0;
        margin-left: auto;
    }

@media (max-width: 640px) {
    .empty-state-inline {
        flex-direction: column;
        text-align: center;
    }

        .empty-state-inline .empty-state-actions {
            margin-left: 0;
        }
}

/* Moldura tracejada — area vazia que aceita conteudo (upload, grade de fotos) */
.empty-state-boxed {
    border: 1px dashed var(--color-border-strong);
    border-radius: var(--radius-lg);
    background: var(--color-surface);
}

/* Intencao do icone — vazio por filtro (info), atencao ou falha de carga */
.empty-state-info .empty-state-figure {
    color: var(--color-info);
    background: var(--color-info-soft);
    border-color: transparent;
}

.empty-state-warning .empty-state-figure {
    color: var(--color-warning);
    background: var(--color-warning-soft);
    border-color: transparent;
}

.empty-state-danger .empty-state-figure {
    color: var(--color-danger);
    background: var(--color-danger-soft);
    border-color: transparent;
}

.empty-state-info .empty-state-icon {
    color: var(--color-info);
}

.empty-state-warning .empty-state-icon {
    color: var(--color-warning);
}

.empty-state-danger .empty-state-icon {
    color: var(--color-danger);
}

/* Encaixes: colado no container, sem padding duplicado */
.card > .empty-state {
    padding-block: var(--sp-10);
}

.table-wrap .empty-state,
.table td > .empty-state {
    padding-block: var(--sp-8);
}

.offcanvas-body > .empty-state {
    padding-inline: 0;
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — PAGINACAO
   Base no essentials (ul li), refatorado para classes (.pagination/.page),
   token-only, dark, ativo/disabled.
   .pagination-bar -> rodape padrao de tabela: info "X–Y de Z registros" +
   seletor de itens por pagina + .pagination. Vai dentro do .card-footer.
   ========================================================================= */
.pagination {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
    flex-wrap: wrap;
}

.pagination-page {
    min-width: 32px;
    height: 32px;
    padding: 0 var(--sp-2);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-sans);
    font-size: var(--fs-sm);
    color: var(--color-text-muted);
    background: var(--color-surface);
    border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}

    .pagination-page:hover {
        background: var(--color-surface-hover);
        color: var(--color-text);
    }

    .pagination-page:focus-visible {
        outline: none;
        box-shadow: 0 0 0 3px var(--color-focus-ring);
    }

    .pagination-page.is-active {
        background: var(--color-primary);
        color: var(--color-on-primary);
        border-color: var(--color-primary);
    }

    .pagination-page:disabled {
        opacity: 0.45;
        cursor: not-allowed;
    }

.pagination-ellipsis {
    min-width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-subtle);
}

.pagination-glyph {
    width: 16px;
    height: 16px;
}

/* ---- Barra acoplada a tabela ---- */
.pagination-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3) var(--sp-5);
    flex-wrap: wrap;
    width: 100%;
}

.pagination-info {
    font-size: var(--fs-sm);
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}

    .pagination-info strong {
        color: var(--color-text);
        font-weight: var(--fw-semibold);
    }

.pagination-bar-end {
    display: flex;
    align-items: center;
    gap: var(--sp-3) var(--sp-5);
    flex-wrap: wrap;
}

.pagination-size {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
}

    .pagination-size .lbl {
        width: auto;
        margin: 0;
        font-weight: var(--fw-regular);
        color: var(--color-text-muted);
        white-space: nowrap;
    }

    .pagination-size .input-container {
        width: auto;
        min-height: 32px;
        padding-top: 0;
        padding-bottom: 0;
        border-radius: var(--radius-md);
    }

        .pagination-size .input-container select {
            font-size: var(--fs-sm);
        }

@media (max-width: 639.98px) {
    .pagination-bar,
    .pagination-bar-end {
        justify-content: center;
    }

    .pagination-info {
        width: 100%;
        text-align: center;
    }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — TOAST
   Refina o .toast-ui do essentials: token-only, cores de sinal via token
   (eram hardcoded), icone SVG inline (era fonte de icone), barra de contagem.
   ========================================================================= */
.toast-ui {
    position: fixed;
    top: var(--sp-8);
    right: var(--sp-5);
    z-index: var(--z-toast);
    width: 25rem;
    max-width: calc(100vw - 2rem);
    overflow: hidden;
    background: var(--color-surface);
    color: var(--color-text);
    border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
}

.toast-ui-container {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    padding: var(--sp-4);
    border-left: 4px solid var(--color-info);
}

.toast-icon {
    flex: none;
    width: 22px;
    height: 22px;
    margin-top: 1px;
    color: var(--color-info);
}

.toast-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1;
    min-width: 0;
}

.toast-title {
    font-weight: var(--fw-semibold);
}

.toast-message {
    font-size: var(--fs-sm);
    color: var(--color-text-muted);
}

.toast-close {
    flex: none;
    border: 0;
    background: transparent;
    color: var(--color-text-subtle);
    cursor: pointer;
    padding: 0;
}

    .toast-close:hover {
        color: var(--color-text);
    }

    .toast-close svg {
        width: 16px;
        height: 16px;
    }

/* Variantes de sinal */
.toast-success .toast-ui-container {
    border-left-color: var(--color-success);
}

.toast-success .toast-icon {
    color: var(--color-success);
}

.toast-warning .toast-ui-container {
    border-left-color: var(--color-warning);
}

.toast-warning .toast-icon {
    color: var(--color-warning);
}

.toast-danger .toast-ui-container {
    border-left-color: var(--color-danger);
}

.toast-danger .toast-icon {
    color: var(--color-danger);
}

.toast-info .toast-ui-container {
    border-left-color: var(--color-info);
}

.toast-info .toast-icon {
    color: var(--color-info);
}

/* Barra de contagem (auto-dismiss) */
.toast-progress {
    height: 3px;
    background: var(--color-surface-2);
}

.toast-progress-bar {
    height: 100%;
    width: 100%;
    background: currentColor;
    transform-origin: left;
    animation: toast-countdown 5s linear forwards;
}

.toast-success .toast-progress-bar {
    color: var(--color-success);
}

.toast-warning .toast-progress-bar {
    color: var(--color-warning);
}

.toast-danger .toast-progress-bar {
    color: var(--color-danger);
}

.toast-info .toast-progress-bar {
    color: var(--color-info);
}

@keyframes toast-countdown {
    to {
        transform: scaleX(0);
    }
}

@media (prefers-reduced-motion: reduce) {
    .toast-progress-bar {
        animation: none;
    }
}

/* Preview estatico (fora do fixed) */
.toast-ui-static {
    position: static;
    width: 100%;
    max-width: 420px;
    box-shadow: var(--shadow-sm);
}

/* =========================================================================
   Extensao local (nao vem do design system): entrada/saida suave.
   O componente Blazor mantem o elemento sempre no DOM (nunca some com @if) para
   poder animar a saida — visibilidade e controlada por esta classe, nao por
   display:none. A troca de toast usa @key no elemento raiz para forcar o
   Blazor a recriar o <div>, o que reinicia tanto esta transicao quanto a
   animacao da barra de contagem acima (senao ela so rodaria na primeira vez).
   ========================================================================= */
.toast-ui {
    opacity: 0;
    transform: translateY(-8px);
    pointer-events: none;
    transition: opacity var(--dur-base) var(--ease), transform var(--dur-base) var(--ease);
}

    .toast-ui.is-visible {
        opacity: 1;
        transform: translateY(0);
        pointer-events: auto;
    }

@media (prefers-reduced-motion: reduce) {
    .toast-ui {
        transition: opacity var(--dur-base) var(--ease);
        transform: none;
    }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — MODAL
   Vocabulario do essentials (.modal / .modal-header / .modal-title /
   .modal-subtitle / .modal-body / .modal-backdrop), refinado: independente de
   Bootstrap, token-only, dark, fechar com SVG inline (essentials usa <i> de
   fonte). Rodape com a REGRA de ordem dos botoes.
   ========================================================================= */
.modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: var(--z-modal);
    background: var(--color-overlay);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--sp-6);
}

.modal {
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 520px;
    background: var(--color-surface);
    color: var(--color-text);
    border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-lg);
}
/* Cabecalho e rodape em superficie levemente distinta do corpo — separa as
   faixas de acao/identificacao do conteudo sem depender so da borda. Sem
   overflow:hidden no .modal — ele cortava qualquer coisa que precisasse sair
   da caixa (ex.: o .select-menu do CustomInputSelect abrindo perto do fim do
   modal). O arredondamento dos cantos vem de cada extremidade abaixo. */
.modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-4) var(--sp-5);
    background: var(--color-surface);
    border-bottom: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
}

.modal-heading {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.modal-title {
    font-size: var(--fs-xl);
    font-weight: var(--fw-semibold);
    line-height: var(--lh-snug);
}

.modal-subtitle {
    font-size: var(--fs-sm);
    line-height: var(--lh-snug);
    color: var(--color-text-muted);
}

.modal-close {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 0;
    background: transparent;
    color: var(--color-text-muted);
    border-radius: var(--radius-md);
    cursor: pointer;
}

    .modal-close:hover {
        background: var(--color-surface-hover);
        color: var(--color-text);
    }

    .modal-close svg {
        width: 18px;
        height: 18px;
    }

.modal-body {
    padding: var(--sp-5);
    background: var(--color-surface);
    font-size: var(--fs-base);
    line-height: var(--lh-normal);
    color: var(--color-text-muted);
}

/* Fecha o canto de baixo quando nao ha .modal-footer (ele so existe entao). */
.modal-body:last-child {
    border-radius: 0 0 var(--radius-xl) var(--radius-xl);
}

form.modal-body {
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
}

.modal-footer {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-5);
    background: var(--color-surface-2);
    border-top: var(--border-w) solid var(--color-border);
    border-radius: 0 0 var(--radius-xl) var(--radius-xl);
}

/* Ordem dos botoes (REGRA) — o grupo fica SEMPRE alinhado a direita; muda so
   a ORDEM no DOM, nao o alinhamento da linha:
   - avancar (Salvar/Continuar): Cancelar a esquerda, confirmar (primario) a DIREITA */
.modal-footer-advance {
    justify-content: flex-end;
}

/* - destrutivo (Excluir): confirmar (perigo) a ESQUERDA, Cancelar a direita */
.modal-footer-destructive {
    justify-content: flex-end;
}

/* Preview estatico (fora do overlay) */
.modal-static {
    position: static;
    box-shadow: var(--shadow-md);
}

@media (max-width: 768px) {
    .modal {
        max-width: 100%;
    }
}

/* =========================================================================
   MODAL DE FOTO (visualizador) — .modal-photo
   Cabecalho com selo + contador, palco escuro (independente do tema) e
   rodape de ferramentas (zoom, girar, redefinir, baixar).
   ========================================================================= */
.modal-photo, .modal-video {
    max-width: 1080px;
}

.modal-photo-mark {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: var(--radius-lg);
    background: var(--color-primary-soft);
    color: var(--color-primary);
}

    .modal-photo-mark svg {
        width: 20px;
        height: 20px;
    }

.modal-photo-id {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    min-width: 0;
}

.modal-photo-count {
    flex: none;
    font-family: var(--font-mono);
    font-size: var(--fs-sm);
    color: var(--color-text-muted);
    background: var(--color-surface-2);
    border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-full);
    padding: var(--sp-1) var(--sp-3);
}

/* Palco — sempre escuro para nao competir com a foto */
.modal-photo-stage, .modal-video-stage {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--sp-6);
    min-height: 380px;
    background: var(--color-stage);
    overflow: hidden;
}

    .modal-photo-stage img, .modal-video-stage video, .modal-video-stage .video-frame {
        max-width: 100%;
        max-height: 62vh;
        object-fit: contain;
        border-radius: var(--radius-sm);
    }

.modal-photo-nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border: 0;
    border-radius: var(--radius-full);
    background: var(--color-stage-control);
    color: var(--color-on-stage);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease);
}

    .modal-photo-nav:hover {
        background: var(--color-stage-control-hover);
    }

    .modal-photo-nav:disabled {
        opacity: 0.35;
        cursor: not-allowed;
    }

    .modal-photo-nav svg {
        width: 20px;
        height: 20px;
    }

.modal-photo-nav-prev {
    left: var(--sp-4);
}

.modal-photo-nav-next {
    right: var(--sp-4);
}

/* Rodape de ferramentas */
.modal-photo .modal-footer {
    justify-content: space-between;
    gap: var(--sp-5);
    padding: var(--sp-4) var(--sp-5);
    flex-wrap: wrap;
}

.modal-photo-zoom {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    flex: 1 1 260px;
    min-width: 0;
}

.modal-photo-zoom-label {
    font-size: var(--fs-sm);
    font-weight: var(--fw-semibold);
    color: var(--color-text);
}

.modal-photo-zoom-value {
    font-family: var(--font-mono);
    font-size: var(--fs-sm);
    color: var(--color-text-muted);
    min-width: 4.5ch;
    text-align: right;
}

.modal-photo-tools {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

.modal-photo-tools-sep {
    width: var(--border-w);
    align-self: stretch;
    margin: var(--sp-1) var(--sp-1);
    background: var(--color-border);
}

/* Range tokenizado — reaproveitavel */
.range-control {
    flex: 1 1 auto;
    min-width: 120px;
    height: 20px;
    margin: 0;
    appearance: none;
    background: transparent;
    cursor: pointer;
}

    .range-control::-webkit-slider-runnable-track {
        height: 6px;
        border-radius: var(--radius-full);
        background: var(--color-surface-hover);
        border: var(--border-w) solid var(--color-border);
    }

    .range-control::-moz-range-track {
        height: 6px;
        border-radius: var(--radius-full);
        background: var(--color-surface-hover);
        border: var(--border-w) solid var(--color-border);
    }

    .range-control::-webkit-slider-thumb {
        appearance: none;
        width: 18px;
        height: 18px;
        margin-top: -7px;
        border-radius: var(--radius-full);
        background: var(--color-surface);
        border: var(--border-w) solid var(--color-border-strong);
        box-shadow: var(--shadow-xs);
    }

    .range-control::-moz-range-thumb {
        width: 18px;
        height: 18px;
        border-radius: var(--radius-full);
        background: var(--color-surface);
        border: var(--border-w) solid var(--color-border-strong);
        box-shadow: var(--shadow-xs);
    }

    .range-control:hover::-webkit-slider-thumb {
        border-color: var(--color-primary);
    }

    .range-control:hover::-moz-range-thumb {
        border-color: var(--color-primary);
    }

    .range-control:focus-visible {
        outline: none;
    }

        .range-control:focus-visible::-webkit-slider-thumb {
            box-shadow: 0 0 0 3px var(--color-focus-ring);
        }

        .range-control:focus-visible::-moz-range-thumb {
            box-shadow: 0 0 0 3px var(--color-focus-ring);
        }

/* =========================================================================
   MODAL DE VIDEO — .modal-video
   Mesma estrutura do visualizador de foto, sem zoom e sem rotacao:
   o rodape vira controle de reproducao (play, linha do tempo, tempo, som).
   ========================================================================= */
.modal-video .modal-footer {
    justify-content: space-between;
    gap: var(--sp-4);
    padding: var(--sp-4) var(--sp-5);
    flex-wrap: wrap;
}

.modal-video-transport {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    flex: 1 1 320px;
    min-width: 0;
}

.modal-video-time {
    font-family: var(--font-mono);
    font-size: var(--fs-sm);
    color: var(--color-text-muted);
    flex: none;
}

.modal-video-tools {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

.modal-video-volume {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    width: 120px;
}

    .modal-video-volume svg {
        width: 18px;
        height: 18px;
        flex: none;
        color: var(--color-text-muted);
    }

    .modal-video-volume .range-control {
        min-width: 72px;
    }
/* Play central sobre o palco */
.modal-video-play {
    position: absolute;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    height: 64px;
    border: 0;
    border-radius: var(--radius-full);
    background: var(--color-stage-control);
    color: var(--color-on-stage);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease);
}

    .modal-video-play:hover {
        background: var(--color-stage-control-hover);
    }

    .modal-video-play svg {
        width: 26px;
        height: 26px;
        margin-left: 3px;
    }

@media (max-width: 768px) {
    .modal-photo-stage, .modal-video-stage {
        min-height: 240px;
        padding: var(--sp-4);
    }

    .modal-video-volume {
        display: none;
    }

    .modal-photo .modal-footer {
        align-items: stretch;
    }

    .modal-photo-tools {
        justify-content: flex-end;
    }
}

/* =========================================================================
   Extensao local (nao vem do design system): entrada/saida suave.
   O componente Blazor mantem o backdrop montado por --dur-base extra ao
   fechar (Task.Delay em C#, sincronizado com esta duracao) antes de
   desmontar via @if, para poder animar a saida.
   ========================================================================= */
.modal-backdrop {
    opacity: 0;
    transition: opacity var(--dur-base) var(--ease);
}

    .modal-backdrop.is-open {
        opacity: 1;
    }

    .modal-backdrop .modal {
        transform: scale(0.96) translateY(8px);
        transition: transform var(--dur-base) var(--ease);
    }

    .modal-backdrop.is-open .modal {
        transform: scale(1) translateY(0);
    }

@media (prefers-reduced-motion: reduce) {
    .modal-backdrop .modal {
        transition: none;
        transform: none;
    }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — OFFCANVAS
   Vocabulario do essentials (OffCanvasInformation + OffCanvasSection):
   .offcanvas (+ .offcanvas-start|-end) / .offcanvas-header / .offcanvas-title /
   .offcanvas-body / .offcanvas-section + .offcanvas-row, refinado:
   token-only, dark-ready, fechar via SVG inline, desliza com transform
   (prefers-reduced-motion zera a duracao via tokens/motion.css).

   Painel lateral para visualizacao corrida e somente-leitura de dados
   (secoes com linhas rotulo/valor). Para edicao, usar modal ou tela —
   o offcanvas nao e' formulario.
   ========================================================================= */
.offcanvas-backdrop {
  position: fixed; inset: 0; z-index: var(--z-overlay); background: var(--color-overlay);
  opacity: 0; pointer-events: none; transition: opacity var(--dur-base) var(--ease);
}
.offcanvas-backdrop.is-open { opacity: 1; pointer-events: auto; }

.offcanvas {
  position: fixed; top: 0; bottom: 0; z-index: var(--z-modal);
  display: flex; flex-direction: column; width: 100%; max-width: 420px;
  background: var(--color-surface); color: var(--color-text); box-shadow: var(--shadow-lg);
  transition: transform var(--dur-base) var(--ease-out);
}
.offcanvas-end { right: 0; border-left: var(--border-w) solid var(--color-border); transform: translateX(100%); }
.offcanvas-start { left: 0; border-right: var(--border-w) solid var(--color-border); transform: translateX(-100%); }
.offcanvas.is-open { transform: translateX(0); }

.offcanvas-header { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5); border-bottom: var(--border-w) solid var(--color-border); }
.offcanvas-title { font-size: var(--fs-lg); font-weight: var(--fw-bold); letter-spacing: var(--ls-wide); text-transform: uppercase; }
.offcanvas-close { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: 0; background: transparent; color: var(--color-text-muted); border-radius: var(--radius-md); cursor: pointer; }
.offcanvas-close:hover { background: var(--color-surface-hover); color: var(--color-text); }
.offcanvas-close svg { width: 18px; height: 18px; }

.offcanvas-body { flex: 1; overflow-y: auto; padding: var(--sp-5); }

/* Secao: titulo full-bleed (sangra contra o padding do body) + lista corrida de linhas */
.offcanvas-section + .offcanvas-section { margin-top: var(--sp-5); }
.offcanvas-section-title {
  margin: 0 calc(var(--sp-5) * -1) var(--sp-3); padding: var(--sp-1) var(--sp-5);
  background: var(--color-surface-2); font-size: var(--fs-sm); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: var(--ls-wide); color: var(--color-text-muted);
}

.offcanvas-row { display: flex; flex-direction: column; gap: var(--sp-1); padding: var(--sp-3) 0; border-bottom: var(--border-w) solid var(--color-border); }
.offcanvas-row:last-child { border-bottom: 0; padding-bottom: 0; }
.offcanvas-row-label { font-size: var(--fs-xs); font-weight: var(--fw-semibold); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--color-text-subtle); }
.offcanvas-row-value { font-size: var(--fs-base); font-weight: var(--fw-semibold); color: var(--color-text); overflow-wrap: anywhere; }

@media (max-width: 480px) {
  .offcanvas { max-width: 100%; }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — OFFCANVAS DE FORMULARIO
   Variante do offcanvas para EDICAO: mesmo painel/cabecalho/secoes da base
   (offcanvas.css, obrigatorio junto), mais rodape de acoes fixo, campos de
   formulario (rotulo + input-container/selecao) e um bloco de METADADOS
   somente-leitura em duas colunas (comparacao). Diferente do offcanvas base
   (leitura corrida), este captura dados e persiste via Salvar.
   token-only, dark-ready. prefers-reduced-motion herdado da base.
   ========================================================================= */

/* Corpo do formulario: secoes empilhadas com respiro entre grupos de campo */
.offcanvas-form .offcanvas-section-title { color: var(--color-primary); }
.offcanvas-form-group + .offcanvas-form-group { margin-top: var(--sp-4); }

/* Lista de checkboxes (ex.: marcacoes de anomalia da foto) */
.offcanvas-check-list { display: flex; flex-direction: column; gap: var(--sp-3); }

/* Bloco de metadados somente-leitura — cartao em surface-2, duas colunas */
.offcanvas-meta { background: var(--color-surface-2); border: var(--border-w) solid var(--color-border); border-radius: var(--radius-lg); padding: 0 var(--sp-4); }
.offcanvas-meta-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-5); padding: var(--sp-4) 0; border-bottom: var(--border-w) solid var(--color-border); }
.offcanvas-meta-row:last-child { border-bottom: 0; }
.offcanvas-meta-item { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.offcanvas-meta-head { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--color-primary); }
.offcanvas-meta-icon { width: 16px; height: 16px; flex: none; color: var(--color-text-muted); }
.offcanvas-meta-value { font-size: var(--fs-sm); color: var(--color-text); overflow-wrap: anywhere; }
.offcanvas-meta-value.is-empty { color: var(--color-text-subtle); }

/* Rodape de acoes fixo — nao rola com o corpo */
.offcanvas-footer { flex: none; display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5); background: var(--color-surface-2); border-top: var(--border-w) solid var(--color-border); }
.offcanvas-footer-actions { display: flex; align-items: center; gap: var(--sp-3); }

@media (max-width: 480px) {
  .offcanvas-meta-row { grid-template-columns: 1fr; gap: var(--sp-4); }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — DIVIDER (separador)
   Linha de separacao entre blocos de conteudo. Raiz: <hr class="divider">.
   Com texto ou vertical, raiz nao-<hr> com role="separator".
   Token-only, dark-ready.
   ========================================================================= */
.divider {
  display: block; flex: none; height: var(--border-w); width: 100%;
  margin: var(--sp-6) 0; border: 0; padding: 0;
  background: var(--color-border); color: inherit;
}

/* Espacamento */
.divider-sm { margin: var(--sp-3) 0; }
.divider-lg { margin: var(--sp-9) 0; }
.divider-flush { margin: 0; }

/* Enfase: separa secoes principais */
.divider-strong { background: var(--color-border-strong); }

/* Com texto no meio ("ou", titulo de grupo) */
.divider-label {
  display: flex; align-items: center; gap: var(--sp-3);
  height: auto; background: none;
  font-size: var(--fs-xs); font-weight: var(--fw-semibold); text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--color-text-muted); line-height: 1;
}
.divider-label::before,
.divider-label::after { content: ""; flex: 1; height: var(--border-w); background: var(--color-border); }
.divider-label.divider-strong::before,
.divider-label.divider-strong::after { background: var(--color-border-strong); }
.divider-label.divider-start::before { flex: 0 0 var(--sp-4); }

/* Vertical: entre itens de uma linha (toolbar, meta) */
.divider-vertical {
  display: inline-block; align-self: stretch; width: var(--border-w); height: auto;
  min-height: 1em; margin: 0 var(--sp-2);
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — VISUALIZACAO DE REGISTRO
   Vocabulario do essentials (VisualizacaoRegistroTemplate: .entity-visualization
   / .ev-header / .ev-body / .ev-body-field), refinado: token-only, dark-ready.
   Uso: exibicao somente-leitura de um registro (cabecalho + campos rotulo/valor).
   ========================================================================= */
.entity-visualization {
    background: var(--color-surface);
    color: var(--color-text);
    border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: var(--sp-5);
}

    /* Erro de regra de negocio no topo do card (antes do cabecalho) */
    .entity-visualization > .alert:not([hidden]) {
        margin-bottom: var(--sp-4);
    }

    .entity-visualization .ev-header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--sp-3);
        flex-wrap: wrap;
    }

    .entity-visualization .ev-header-title {
        font-size: var(--fs-xl);
        font-weight: var(--fw-semibold);
        letter-spacing: var(--ls-tight);
    }

    .entity-visualization .ev-header-meta {
        display: inline-flex;
        align-items: center;
        gap: var(--sp-2);
    }

    .entity-visualization > .divider {
        margin: var(--sp-4) 0;
    }

    .entity-visualization .ev-body:not(:first-child) {
        padding-top: var(--sp-2);
    }

/* Vocabulario de campo leitura/valor — SEM prefixo de casca, para reuso fora do
   .entity-visualization (ex.: passo somente-leitura dentro do .stepper-panel).
   A casca (borda/sombra/padding) continua em .entity-visualization; estes sao
   so a grade e o par rotulo/valor. */
.ev-fields {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--sp-5);
}

.ev-body-field {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    min-width: 0;
}

    .ev-body-field.is-wide {
        grid-column: 1 / -1;
    }

.ev-body-field-label {
    font-size: var(--fs-xs);
    font-weight: var(--fw-semibold);
    letter-spacing: var(--ls-wide);
    text-transform: uppercase;
    color: var(--color-text-subtle);
}

.ev-body-field-value {
    font-size: var(--fs-base);
    font-weight: var(--fw-semibold);
    color: var(--color-text);
    overflow-wrap: anywhere;
}

    .ev-body-field-value.is-empty {
        font-weight: var(--fw-regular);
        font-style: italic;
        color: var(--color-text-subtle);
    }

@media (max-width: 768px) {
    .ev-fields {
        grid-template-columns: 1fr;
    }
}

/* Lista inline — rotulo a esquerda, valor alinhado a direita, uma linha por
   campo. Para resumo compacto (origem, metadados). Mesmo .ev-body-field. */
.ev-fields.is-inline {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
}

.ev-fields.is-inline .ev-body-field {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-1) var(--sp-4);
}

.ev-fields.is-inline .ev-body-field-label {
    font-size: var(--fs-sm);
    font-weight: var(--fw-regular);
    letter-spacing: normal;
    text-transform: none;
    color: var(--color-text-muted);
}

.ev-fields.is-inline .ev-body-field-value {
    font-size: var(--fs-sm);
    text-align: right;
    margin-left: auto;
}

.ev-body-field-value a {
    color: var(--color-link);
    text-decoration: none;
}

    .ev-body-field-value a:hover {
        color: var(--color-link-hover);
        text-decoration: underline;
    }

    .ev-body-field-value a:focus-visible {
        outline: none;
        border-radius: var(--radius-sm);
        box-shadow: 0 0 0 2px var(--color-focus-ring);
    }

.entity-visualization .ev-header-title-wrap {
    flex: 1;
    min-width: 0;
}

    .entity-visualization .ev-header-title-wrap .input-container {
        max-width: 420px;
    }

    .entity-visualization .ev-header-title-wrap .ev-header-title {
        font-size: var(--fs-xl);
        font-weight: var(--fw-semibold);
        letter-spacing: var(--ls-tight);
    }

.entity-visualization .ev-header-actions {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    flex-shrink: 0;
}

/* Edicao inline — o mesmo card alterna entre leitura e edicao.
   .is-editing no .entity-visualization troca .ev-body-field-value (texto)
   por .ev-body-field-edit (input-container), sem duplicar o card. */
.entity-visualization .ev-body-field-edit {
    display: none;
}

.entity-visualization.is-editing .ev-body-field-value {
    display: none;
}

.entity-visualization.is-editing .ev-body-field-edit {
    display: block;
}

.entity-visualization.is-editing .ev-body-field-label {
    display: none;
}

/* Campo desabilitado — nunca entra em edicao, mesmo com o card is-editing:
   .ev-body-field.is-disabled reverte a visibilidade que .is-editing forca,
   para rotulo e valor (o valor pode ser texto simples ou conteudo
   customizado, como uma badge — por isso "revert", nao um display fixo). */
.entity-visualization.is-editing .ev-body-field.is-disabled .ev-body-field-label {
    display: revert;
}

.entity-visualization.is-editing .ev-body-field.is-disabled .ev-body-field-value {
    display: revert;
}

/* Rotulo fixo — por padrao .is-editing esconde o .ev-body-field-label porque
   o .float-field carrega o proprio rotulo flutuante. Campos cujo controle de
   edicao NAO tem rotulo flutuante (toggle, badge editavel, conteudo custom)
   devem manter o rotulo do campo visivel: marcar com
   .ev-body-field.is-label-fixed. No Blazor: parametro ManterRotuloFixo
   adiciona esta classe. */
.entity-visualization.is-editing .ev-body-field.is-label-fixed .ev-body-field-label {
    display: revert;
}

/* Em edicao, campos com rotulo fixo (rotulo uppercase numa linha acima do
   controle) convivem na mesma grade com float-fields (rotulo flutuante, sem
   linha propria). So nesse caso alinhar os controles pela base mantem a
   linha reta; em linhas so de float-field o alinhamento pelo topo e o
   correto (senao uma mensagem de validacao em um campo empurraria os
   vizinhos para baixo). */
.entity-visualization.is-editing .ev-fields:has(.ev-body-field.is-label-fixed) {
    align-items: end;
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — TIMELINE / HISTORICO DE ATIVIDADES
   Nome oficial: .timeline. Lista vertical de eventos com marcador colorido,
   autor, horario e texto. Uso: historico de contatos no detalhe do registro.

     .timeline            -> <ol> sem marcador
     .timeline-item       -> <li>: coluna do marcador + conteudo
     .timeline-marker     -> ponto (a linha vertical e o ::before do item)
     .timeline-content    -> bloco de texto
     .timeline-head       -> titulo do evento + autor + horario
     .timeline-title / -author / -time / -text / -meta
     .timeline-day        -> separador de data ("Hoje", "12/08")
   Tipo do evento = classe somada no item, nomeada pelo SINAL (nao pelo
   negocio), pra servir a qualquer produto:
     ok / contato aceito      -> .timeline-item-success
     recusa                   -> .timeline-item-danger
     retorno agendado         -> .timeline-item-warning
     nota / sistema           -> .timeline-item-info  |  .timeline-item-neutral
   Estados: .is-current (evento em aberto), .is-skeleton (usa .skeleton),
   vazio -> .empty-state (nao ha vazio proprio de timeline).
   ========================================================================= */
.timeline {
  --tl-dot: 14px;
  --tl-color: var(--color-border-strong);
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column;
}
.timeline-item {
  position: relative; display: grid; grid-template-columns: var(--tl-dot) 1fr;
  gap: var(--sp-3); padding-bottom: var(--sp-5);
}
.timeline-item:last-child { padding-bottom: 0; }
/* Linha vertical — do marcador ate o proximo item */
.timeline-item:not(:last-child)::before {
  content: ""; position: absolute; left: calc(var(--tl-dot) / 2 - 1px);
  top: calc(var(--tl-dot) + var(--sp-1)); bottom: 2px; width: 2px;
  background: var(--color-border); border-radius: var(--radius-full);
}
.timeline-marker {
  position: relative; width: var(--tl-dot); height: var(--tl-dot); margin-top: 4px; flex: none;
  border-radius: var(--radius-full); background: var(--tl-color);
  box-shadow: 0 0 0 3px var(--color-surface);
}
.timeline-content { min-width: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.timeline-head { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.timeline-title { font-size: var(--fs-base); font-weight: var(--fw-semibold); color: var(--color-text); }
.timeline-author { font-size: var(--fs-sm); color: var(--color-text-muted); }
.timeline-author::before { content: "•"; margin-right: var(--sp-2); color: var(--color-text-subtle); }
.timeline-time { margin-left: auto; font-size: var(--fs-xs); color: var(--color-text-subtle); font-variant-numeric: tabular-nums; white-space: nowrap; }
.timeline-text { font-size: var(--fs-sm); line-height: var(--lh-normal); color: var(--color-text); text-wrap: pretty; }
.timeline-meta { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; font-size: var(--fs-xs); color: var(--color-text-subtle); margin-top: var(--sp-1); }

/* Tipo do evento (sinal) */
.timeline-item-success { --tl-color: var(--color-success); }
.timeline-item-danger  { --tl-color: var(--color-danger); }
.timeline-item-warning { --tl-color: var(--color-warning); }
.timeline-item-info    { --tl-color: var(--color-info); }
.timeline-item-neutral { --tl-color: var(--color-text-subtle); }
.timeline-item-primary { --tl-color: var(--color-primary); }
.timeline-item-success .timeline-title { color: var(--color-text); }

/* Evento em aberto — anel na cor do tipo */
.timeline-item.is-current .timeline-marker { box-shadow: 0 0 0 3px var(--color-surface), 0 0 0 6px color-mix(in oklab, var(--tl-color) 28%, transparent); }

/* Separador de data */
.timeline-day {
  display: flex; align-items: center; gap: var(--sp-3); margin: 0 0 var(--sp-4);
  font-size: var(--fs-xs); font-weight: var(--fw-semibold); letter-spacing: var(--ls-wide);
  text-transform: uppercase; color: var(--color-text-subtle);
}
.timeline-day::after { content: ""; flex: 1 1 auto; height: var(--border-w); background: var(--color-border); }
.timeline-item + .timeline-day { margin-top: var(--sp-5); }

/* Denso — dentro de offcanvas ou coluna estreita */
.timeline-compact .timeline-item { padding-bottom: var(--sp-4); gap: var(--sp-2); }
.timeline-compact .timeline-title { font-size: var(--fs-sm); }

/* Skeleton */
.timeline-item.is-skeleton .timeline-marker { background: var(--color-surface-hover); box-shadow: none; }
.timeline-item.is-skeleton .timeline-content { gap: var(--sp-2); }

@media (max-width: 640px) {
  .timeline-time { margin-left: 0; }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — ACOMPANHAMENTO DE REGISTRO (layout de tela)
   Terceiro arquetipo de tela, ao lado de "visualizacao/edicao de registro" e
   "workflow". Aqui o assunto NAO e o dado atual nem uma sequencia fechada de
   etapas: e a HISTORIA do registro e a PROXIMA ACAO. Serve a lead, proposta,
   ordem de servico, vistoria.

   Tres zonas, nesta ordem:
     1. Identidade  -> .page-head: titulo, .acomp-meta (situacao) e as acoes de
                       DESFECHO em .page-actions (ganho/perdido, cancelar/gerar).
     2. Situacao    -> .status-banner, largura total, acima da grade.
     3. Trabalho    -> .acomp-layout: .acomp-main (compositor + .timeline) e
                       .acomp-aside (a ficha, em .entity-visualization).

   Regra de acao (a que faltava): acao de DESFECHO vive no cabecalho da PAGINA;
   acao de EDICAO vive no cabecalho do CARD (.ev-header-actions, edicao inline).
   Nunca as duas no mesmo lugar, nunca editar o registro em modal aqui.
   Ordem da atividade: mais recente NO TOPO, junto do compositor.
   ========================================================================= */
.acomp-meta { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-top: var(--sp-2); font-size: var(--fs-sm); color: var(--color-text-muted); }
.acomp-meta-sep { color: var(--color-border-strong); }

.acomp-layout {
  display: grid; grid-template-columns: minmax(0, 1fr) 340px;
  gap: var(--sp-5); align-items: start; margin-top: var(--sp-5);
}
.acomp-main, .acomp-aside { display: flex; flex-direction: column; gap: var(--sp-5); min-width: 0; }
.acomp-aside { position: sticky; top: var(--sp-5); }

/* Compositor — registrar a proxima interacao. Sempre ACIMA da timeline.
   A escolha do resultado usa .segmented (escolha exclusiva, 2-5 rotulos curtos). */
.acomp-composer { display: flex; flex-direction: column; gap: var(--sp-4); }
.acomp-composer-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; }
.acomp-composer-hint { font-size: var(--fs-xs); color: var(--color-text-subtle); }

/* Responsivo — a ficha (contexto) sobe antes do trabalho na coluna unica.
   1200px esta fora da lista fechada de pontos de quebra da v3 (480, 640, 768,
   900, 1024) — CLAUDE.md da raiz. Usando 1024, o mais proximo abaixo. */
@media (max-width: 1024px) {
  .acomp-layout { grid-template-columns: 1fr; }
  .acomp-aside { position: static; order: -1; }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — TABS
   Padrao sublinhado (.tabs / .tab / .tab.is-active), refinado:
   token-only, dark-ready.
   ========================================================================= */
.tabs {
    display: flex;
    gap: var(--sp-1);
    border-bottom: var(--border-w) solid var(--color-border);
    overflow-x: auto;
    overflow-y: hidden;
}

.tab {
    appearance: none;
    background: none;
    border: 0;
    cursor: pointer;
    font-family: var(--font-sans);
    font-size: var(--fs-base);
    font-weight: var(--fw-medium);
    color: var(--color-text-muted);
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    white-space: nowrap;
    padding: var(--sp-3);
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}

    .tab:hover {
        color: var(--color-text);
    }

    .tab:focus-visible {
        outline: none;
        box-shadow: 0 0 0 3px var(--color-focus-ring);
        border-radius: var(--radius-sm);
    }

    .tab.is-active {
        color: var(--color-primary);
        border-bottom-color: var(--color-primary);
        font-weight: var(--fw-semibold);
    }

    .tab:disabled {
        color: var(--color-disabled-text);
        cursor: not-allowed;
    }

    .tab .tab-glyph {
        width: 16px;
        height: 16px;
        flex: none;
    }

.tab-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 18px;
    padding: 0 6px;
    border-radius: var(--radius-full);
    background: var(--color-surface-hover);
    color: var(--color-text-muted);
    font-size: var(--fs-xs);
    font-weight: var(--fw-semibold);
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

    .tab.is-active .tab-count {
        background: var(--color-primary-soft);
        color: var(--color-primary);
    }

    .tab:disabled .tab-count {
        background: var(--color-surface-2);
        color: var(--color-disabled-text);
    }

/* Extensao local (nao existe no tabs.css remoto do Design System) — aba com ajuda
   embutida (TabItem.TextoAjuda). Ver components/17-screen-help.card.html,
   secao "Ajuda por aba", no projeto Ibrascan. O .tab-item envolve o botao .tab e o
   gatilho .help-trigger lado a lado; a sublinha ativa migra do botao para o wrapper,
   senao ela cobriria so a largura do texto e pararia antes do "?". */
.tab-item {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}

    .tab-item .tab {
        border-bottom-color: transparent;
        margin-bottom: 0;
    }

    .tab-item:has(.tab.is-active) {
        border-bottom-color: var(--color-primary);
    }

/* Tambem nao existe no tabs.css remoto — so inline no card, respiro entre a barra
   .tabs e o conteudo da aba ativa. Vale para toda aba, com ou sem ajuda. */
.tab-panel {
    padding-top: var(--sp-4);
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — STEPPER (FORMULARIO MULTI-PASSO)
   Progresso horizontal no topo do formulario. Passo concluido e clicavel
   (volta pra revisar); passo futuro e desabilitado (nao se pula etapa).
     .stepper / .stepper-step   -> trilha e etapa (<ol>/<li>)
     .stepper-trigger           -> <button> da etapa (disabled = travado)
     .stepper-marker            -> numero (futuro/atual) ou check (concluido)
     .stepper-progress          -> "Passo 2 de 4" (visivel no mobile)
     .stepper-panel             -> corpo do passo; .stepper-fields = grade
     .stepper-nav               -> rodape: status do rascunho + Voltar/Continuar
   Estado por classe somada: .is-done, .is-current, .is-reached, .is-invalid.

   NAVEGACAO POR INTERVALO LIBERADO (high-water mark). A trilha e navegavel
   livremente ate a etapa mais avancada ja alcancada; etapas alem dessa ficam
   travadas. Isso separa "concluido" de "navegavel":
     .is-done    -> etapa ATRAS da atual, ja concluida (check). Navegavel.
     .is-current -> etapa atual.
     .is-reached -> etapa A FRENTE da atual, mas dentro do intervalo liberado
                    (ja foi visitada; voltou pra tras). Navegavel, ainda nao
                    concluida -> mostra o numero, marcador contornado.
     (sem classe) -> etapa alem do intervalo liberado: TRAVADA, <button> disabled.
   Assim, estando na etapa 1 com o intervalo liberado ate a 2, a etapa 2 segue
   clicavel (.is-reached) e da pra voltar pra ela. O Blazor aplica .is-reached
   as etapas entre a atual (exclusive) e o high-water mark (inclusive) e so
   poe disabled nas que passam do teto liberado.
   ========================================================================= */

/* Trilha */
.stepper { display: flex; align-items: center; gap: 0; margin: 0; padding: 0; list-style: none; }
.stepper-step { display: flex; align-items: center; flex: 1 1 auto; min-width: 0; }
.stepper-step:last-child { flex: 0 0 auto; }

/* Conector apos cada etapa (menos a ultima) — toda etapa = rotulo + conector,
   entao o espaco se divide igual entre elas. Pintado quando a proxima etapa
   ja foi alcancada. */
.stepper-step:not(:last-child)::after {
  content: ""; flex: 1 1 var(--sp-8); min-width: var(--sp-4); height: 2px;
  margin: 0 var(--sp-3); border-radius: var(--radius-full); background: var(--color-border);
}
.stepper-step:has(+ .stepper-step.is-done)::after,
.stepper-step:has(+ .stepper-step.is-current)::after,
.stepper-step:has(+ .stepper-step.is-reached)::after { background: var(--color-primary); }

/* Botao da etapa */
.stepper-trigger {
  display: inline-flex; align-items: center; gap: var(--sp-3); min-width: 0;
  flex: 0 1 auto; padding: var(--sp-2); border: 0; border-radius: var(--radius-md); background: transparent;
  font-family: var(--font-sans); text-align: left; color: var(--color-text-subtle); cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.stepper-trigger:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--color-focus-ring); }
.stepper-trigger:disabled { cursor: not-allowed; }
.stepper-step.is-done .stepper-trigger,
.stepper-step.is-current .stepper-trigger,
.stepper-step.is-reached .stepper-trigger { color: var(--color-text); }
.stepper-step.is-done .stepper-trigger:hover,
.stepper-step.is-reached .stepper-trigger:hover { background: var(--color-surface-hover); }

/* Marcador */
.stepper-marker {
  flex: none; display: grid; place-items: center; width: 28px; height: 28px;
  border: 2px solid var(--color-border-strong); border-radius: var(--radius-full);
  background: var(--color-surface); color: var(--color-text-subtle);
  font-size: var(--fs-sm); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums;
}
.stepper-marker svg { width: 16px; height: 16px; }
.stepper-step.is-done .stepper-marker { background: var(--color-primary); border-color: var(--color-primary); color: var(--color-on-primary); }
.stepper-step.is-current .stepper-marker { background: var(--color-primary-soft); border-color: var(--color-primary); color: var(--color-primary); }
/* Liberada a frente da atual: contornada no primario (visitada, nao concluida) */
.stepper-step.is-reached .stepper-marker { background: var(--color-surface); border-color: var(--color-primary); color: var(--color-primary); }
.stepper-step.is-invalid .stepper-marker { background: var(--color-danger-soft); border-color: var(--color-danger); color: var(--color-danger); }

/* Rotulo */
.stepper-label { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.stepper-title { font-size: var(--fs-sm); font-weight: var(--fw-medium); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stepper-step.is-current .stepper-title { font-weight: var(--fw-semibold); color: var(--color-primary); }
.stepper-step.is-invalid .stepper-title { color: var(--color-danger); }
.stepper-hint { font-size: var(--fs-xs); color: var(--color-text-subtle); white-space: nowrap; }

/* Contador textual — redundante no desktop, essencial no mobile */
.stepper-progress { display: none; margin: 0; font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--color-text-muted); margin-bottom: var(--sp-3); }

/* Stepper no cabecalho do card do formulario (seletor contextual) */
.card-header:has(> .stepper) { flex-wrap: wrap; min-width: 0; }
.card-header > .stepper { flex: 1 1 auto; }
.card-header > .stepper-progress { flex: 1 1 100%; margin-bottom: 0; }

/* Corpo do passo */
.stepper-panel { display: flex; flex-direction: column; gap: var(--sp-5); }
/* Varios blocos num mesmo passo (listas de itens): ritmo e separacao */
.stepper-panel + .stepper-panel { margin-top: var(--sp-6); padding-top: var(--sp-6); border-top: var(--border-w) solid var(--color-border); }
/* Acao de "adicionar linha" dentro do bloco: tamanho do conteudo, nao da coluna */
.stepper-panel > .btn-action { align-self: flex-start; }
.stepper-panel[hidden] { display: none; }
.stepper-panel-head { display: flex; flex-direction: column; gap: var(--sp-1); }
/* Eyebrow "ETAPA X DE Y" — rotulo de posicao acima do titulo, sempre visivel.
   Usa o primario da marca (dirige o fluxo funcional). Quando presente, o
   cabecalho ganha um filete inferior separando-o dos campos. */
.stepper-panel-eyebrow { margin: 0; font-size: var(--fs-xs); font-weight: var(--fw-semibold); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--color-primary); }
.stepper-panel-head:has(> .stepper-panel-eyebrow) { gap: var(--sp-2); padding-bottom: var(--sp-4); border-bottom: var(--border-w) solid var(--color-border); }
.stepper-panel-title { margin: 0; font-size: var(--fs-lg); font-weight: var(--fw-semibold); letter-spacing: var(--ls-tight); }
.stepper-panel-note { margin: 0; font-size: var(--fs-sm); color: var(--color-text-muted); max-width: 64ch; }
.stepper-fields[hidden] { display: none; }
.stepper-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--sp-5); }
.stepper-fields .is-wide { grid-column: 1 / -1; }
/* GRADE EXPLICITA opcional: .stepper-grid troca o auto-fit por 6 colunas iguais.
   E AUTOSSUFICIENTE (display+gap proprios) e PREFIXADA, entao vai no elemento
   que e PAI DIRETO dos campos -- pode ser o proprio .stepper-fields OU um <form>
   dentro do painel (.stepper-panel > form.stepper-grid > campos). Monte as
   linhas com spans por campo, sem ficar preso ao limite do auto-fit:
     2 por linha -> dois .col-3    |  3 por linha -> tres .col-2
     2 + 4, 4 + 2, etc.           |  .col-6 (ou .is-wide) = linha inteira
   Some 6 por linha e a grade quebra sozinha na proxima. Em telas estreitas
   (<=768px) vira coluna unica. Os spans so valem em filho DIRETO da grade;
   com um wrapper no meio, poe .stepper-grid nesse wrapper. */
.stepper-grid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--sp-5); }
.stepper-grid > .col-2 { grid-column: span 2; }
.stepper-grid > .col-3 { grid-column: span 3; }
.stepper-grid > .col-4 { grid-column: span 4; }
.stepper-grid > .col-6,
.stepper-grid > .is-wide { grid-column: 1 / -1; }

/* Erro de regra de negocio acima do passo (alert no topo do card-body) */
.alert:not([hidden]) ~ .stepper-panel { margin-top: var(--sp-5); }

/* Rodape de navegacao — some no .card-footer; status a esquerda,
   Voltar + Continuar a direita (ordem canonica: avancar = primario a direita) */
.stepper-nav { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.stepper-nav-status { display: inline-flex; align-items: center; gap: var(--sp-2); margin-right: auto; font-size: var(--fs-sm); color: var(--color-text-subtle); }
/* Cluster de acao a esquerda (alternativa ao status): Voltar + acao destrutiva
   "Cancelar cadastro" (btn-action-danger-transparent). As acoes de avancar
   (Salvar e sair / Salvar e continuar) ficam a direita em .stepper-nav-actions,
   o primario por ultimo (ordem canonica: avancar = primario a direita). */
.stepper-nav-lead { display: inline-flex; align-items: center; gap: var(--sp-2); margin-right: auto; flex-wrap: wrap; }
.stepper-nav-status svg { width: 16px; height: 16px; flex: none; }
.stepper-nav-status.is-saved { color: var(--color-success); }
.stepper-nav-actions { display: inline-flex; align-items: center; justify-content: flex-end; gap: var(--sp-3); flex-wrap: wrap; }

/* Adaptacao pra baixo: primeiro cai a dica, depois os rotulos nao-atuais.
   O contador textual assume o papel de indicar onde se esta. 1200px esta fora
   da lista fechada de pontos de quebra da v3 (480, 640, 768, 900, 1024) —
   CLAUDE.md da raiz. Usando 1024, o mais proximo abaixo — mesmo limite que o
   bloco seguinte ja usava, entao os dois se fundem num so @media. */
@media (max-width: 1024px) {
  .stepper-hint:not(.viewport-guard-desk *){ display: none; }
  .stepper-progress:not(.viewport-guard-desk *){ display: block; }
  .stepper-step:not(.is-current):not(.viewport-guard-desk *) .stepper-label{ display: none; }
}
@media (max-width: 768px) {
  .stepper-fields:not(.viewport-guard-desk *){ grid-template-columns: 1fr; }
  .stepper-grid:not(.viewport-guard-desk *){ grid-template-columns: 1fr; }
  .stepper-grid:not(.viewport-guard-desk *) > *{ grid-column: auto; }
  .stepper-grid:not(.viewport-guard-desk *) > .is-wide{ grid-column: 1 / -1; }
  .stepper-nav-status:not(.viewport-guard-desk *){ width: 100%; margin-right: 0; }
  .stepper-nav-lead:not(.viewport-guard-desk *){ width: 100%; margin-right: 0; justify-content: space-between; }
  .stepper-nav-actions:not(.viewport-guard-desk *){ width: 100%; }
  .stepper-nav-actions:not(.viewport-guard-desk *) .btn-action{ flex: 1 1 auto; }
  /*:not(.viewport-guard-desk *) Tres acoes nao cabem numa linha de celular: o primario ocupa a sua */
  .stepper-nav-actions .btn-action-primary{ flex-basis: 100%; }
}

/* EXCEDENTE (+X) — trilha HORIZONTAL com muitas etapas. As etapas futuras que
   nao cabem colapsam num indicador +X ao final ("faltam X"), entao as visiveis
   nunca cortam o rotulo, em qualquer largura. Nao e etapa navegavel: no app o
   +X abre a lista das restantes. O Blazor monta a janela e calcula o excedente:
     janela = etapas ate a atual (com um teto), resto vira +X.
   Marcado por .stepper-more no <li> extra ao final da trilha. */
.stepper-more { flex: 0 0 auto; }
.stepper-more .stepper-trigger { color: var(--color-text-subtle); }
.stepper-more .stepper-marker { width: auto; min-width: 28px; height: 28px; padding: 0 var(--sp-2); border-style: dashed; background: var(--color-surface); color: var(--color-text); }
.stepper-more .stepper-title { font-weight: var(--fw-medium); }
.stepper-more .stepper-trigger:hover { background: var(--color-surface-hover); }
.stepper-more .stepper-trigger:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--color-focus-ring); }
/* O conector que chega ao +X e tracejado: sinaliza que ha mais etapas a frente */
.stepper-step:has(+ .stepper-more)::after { background: none; border-top: 2px dashed var(--color-border); border-radius: 0; height: 0; }

/* Celular: a trilha deixa de ser rail de marcadores e vira BARRA SEGMENTADA —
   um segmento de largura igual por etapa. Nao depende da quantidade de etapas:
   4, 6 ou 10 passos sempre couberam na largura disponivel, sem rolagem
   horizontal e sem rotulo cortado. Quem nomeia a posicao e o contador
   (.stepper-progress, "Passo 3 de 6") + o titulo do painel.
   Segmento pintado = etapa alcancada (concluidas + atual). */
@media (max-width: 640px) {
  .stepper-more:not(.viewport-guard-desk *){ display: none; }
  .stepper:not(.viewport-guard-desk *){ gap: var(--sp-1); align-items: stretch; }
  .stepper-step:not(.viewport-guard-desk *),
  .stepper-step:last-child:not(.viewport-guard-desk *){ flex: 1 1 0; min-width: 0; }
  .stepper-step:not(.viewport-guard-desk *)::after{ display: none; }
  .stepper-trigger:not(.viewport-guard-desk *){ display: grid; align-content: center; width: 100%; min-height: 44px; padding: 0; gap: 0; }
  .stepper-trigger:not(.viewport-guard-desk *) .stepper-label{ display: none; }
  .stepper-marker:not(.viewport-guard-desk *){ width: 100%; height: 6px; border: 0; border-radius: var(--radius-full); background: var(--color-border); font-size: 0; }
  .stepper-marker:not(.viewport-guard-desk *) svg{ display: none; }
  .stepper-step.is-done:not(.viewport-guard-desk *) .stepper-marker,
  .stepper-step.is-current:not(.viewport-guard-desk *) .stepper-marker{ background: var(--color-primary); }
  /* Segmento liberado a frente: pintado parcialmente (contorno primario sobre trilho) */
  .stepper-step.is-reached:not(.viewport-guard-desk *) .stepper-marker{ background: var(--color-primary-soft); box-shadow: inset 0 0 0 1px var(--color-primary); }
  .stepper-step.is-invalid:not(.viewport-guard-desk *) .stepper-marker{ background: var(--color-danger); }
  .stepper-step.is-done:not(.viewport-guard-desk *) .stepper-trigger:hover,
  .stepper-step.is-reached:not(.viewport-guard-desk *) .stepper-trigger:hover{ background: transparent; }
  .stepper-progress:not(.viewport-guard-desk *){ font-size: var(--fs-base); font-weight: var(--fw-semibold); color: var(--color-text); }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — BREADCRUMB
   Base no essentials, refinado: separador via SVG mask (era fonte de icone
   FontAwesome /f105), token-only.
   ========================================================================= */
.breadcrumb {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--sp-2);
    font-size: var(--fs-sm);
    color: var(--color-text-subtle);
}

.breadcrumb-item {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
}

    .breadcrumb-item a {
        color: var(--color-text-muted);
        text-decoration: none;
    }

        .breadcrumb-item a:hover {
            color: var(--color-link);
        }

    .breadcrumb-item + .breadcrumb-item::before {
        content: "";
        width: 14px;
        height: 14px;
        flex: none;
        background-color: var(--color-border-strong);
        -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 18 15 12 9 6'/%3E%3C/svg%3E") center / contain no-repeat;
        mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 18 15 12 9 6'/%3E%3C/svg%3E") center / contain no-repeat;
    }

.breadcrumb-current {
    color: var(--color-text);
    font-weight: var(--fw-medium);
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — ALERTA
   Novo (gap no essentials). Uso principal: erro de REGRA DE NEGOCIO no topo
   do form/tela (distinto da validacao de campo, que usa .validation-message).
   ========================================================================= */
.alert {
    display: flex;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--radius-md);
    border: var(--border-w) solid var(--color-border);
    background: var(--color-surface-2);
    font-size: var(--fs-base);
    color: var(--color-text);
}

    .alert[hidden] {
        display: none;
    }

.alert-icon {
    width: 18px;
    height: 18px;
    flex: none;
    margin-top: 3px;
}

.alert-content {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.alert-title {
    font-weight: var(--fw-semibold);
}

.alert-close {
    margin-left: auto;
    flex: none;
    border: 0;
    background: transparent;
    color: currentColor;
    opacity: 0.7;
    cursor: pointer;
    padding: 0;
}

    .alert-close:hover {
        opacity: 1;
    }

    .alert-close svg {
        width: 16px;
        height: 16px;
    }

.alert-success {
    background: var(--color-success-soft);
    border-color: transparent;
}

    .alert-success .alert-icon, .alert-success .alert-title {
        color: var(--color-success);
    }

.alert-warning {
    background: var(--color-warning-soft);
    border-color: transparent;
}

    .alert-warning .alert-icon, .alert-warning .alert-title {
        color: var(--color-warning);
    }

.alert-danger {
    background: var(--color-danger-soft);
    border-color: transparent;
}

    .alert-danger .alert-icon, .alert-danger .alert-title {
        color: var(--color-danger);
    }

.alert-info {
    background: var(--color-info-soft);
    border-color: transparent;
}

    .alert-info .alert-icon, .alert-info .alert-title {
        color: var(--color-info);
    }
/* =========================================================================
   Section — bloco titulado de uma tela: titulo uppercase acima, conteudo
   (card, entity-visualization, tabela) e nota opcional abaixo.
   .section > .section-title + conteudo + .section-note
   ========================================================================= */
.section { display: flex; flex-direction: column; gap: var(--sp-3); min-width: 0; }
.section-title { margin: 0; font-size: var(--fs-xs); font-weight: var(--fw-semibold); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--color-text-subtle); }
.section-note { margin: 0; font-size: var(--fs-sm); color: var(--color-text-subtle); max-width: 80ch; text-wrap: pretty; }
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — METRIC CARD (KPI)
   Numero grande + rotulo + variacao, para telas de relatorio/dashboard.
   Nao substitui .card (registro/lista); e um cartao de resumo agregado.
   Token-only, dark-ready.
   ========================================================================= */
.metric-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--sp-4); }

.metric-card {
  background: var(--color-surface); border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
  padding: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-2);
}
.metric-card-label { font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--color-text-muted); }
.metric-card-value { font-size: var(--fs-3xl); font-weight: var(--fw-semibold); letter-spacing: var(--ls-tight); font-variant-numeric: tabular-nums; color: var(--color-text); }
.metric-card-footer { display: flex; align-items: center; gap: var(--sp-2); min-height: 1.2em; }
.metric-card-delta { display: inline-flex; align-items: center; gap: 2px; font-size: var(--fs-xs); font-weight: var(--fw-semibold); }
.metric-card-delta svg { width: 14px; height: 14px; }
.metric-card-delta-up { color: var(--color-success); }
.metric-card-delta-down { color: var(--color-danger); }
.metric-card-delta-flat { color: var(--color-text-muted); }
.metric-card-sub { font-size: var(--fs-xs); color: var(--color-text-muted); }

/* Skeleton usa as formas oficiais de skeleton.css (sk-line/sk-title) direto no markup */
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — BAR CHART (barras horizontais empilhadas)
   Uma linha por categoria (ex.: cada loja ou unidade), segmentada por status/sinal. Ordenar as
   linhas por total = ranking, sem precisar de componente separado. Segmento e
   <button> — clicavel (filtra/navega) e focavel; tooltip via .has-tooltip
   (tooltip.css), sem mecanismo proprio. A trilha NAO corta o conteudo
   (overflow visible), senao o balao do tooltip some; o arredondamento fica
   nas pontas, nos proprios segmentos. Token-only, dark-ready.
   ========================================================================= */

.bar-chart { display: flex; flex-direction: column; gap: var(--sp-4); }

.bar-chart-legend { display: flex; flex-wrap: wrap; gap: var(--sp-4); }
.bar-chart-legend-item { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-xs); color: var(--color-text-muted); }
.bar-chart-legend-dot { width: 8px; height: 8px; border-radius: var(--radius-full); flex: none; background: var(--color-text-subtle); }

.bar-chart-rows { display: flex; flex-direction: column; gap: var(--sp-3); }

/* A coluna do total dimensiona pelo numero (milhar com separador cabe sem cortar). */
.bar-chart-row { display: grid; grid-template-columns: minmax(0, 148px) minmax(0, 1fr) minmax(2.75rem, max-content); align-items: center; gap: var(--sp-3); }
/* Rotulo nunca corta: quebra em duas linhas em vez de reticencias. */
.bar-chart-row-label { font-size: var(--fs-sm); line-height: var(--lh-tight); color: var(--color-text); overflow-wrap: anywhere; text-wrap: pretty; }
.bar-chart-row-total { font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--color-text); text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

.bar-chart-track { display: flex; height: 22px; border-radius: var(--radius-md); background: var(--color-surface-2); }
.bar-chart-segment {
  border: none; padding: 0; cursor: pointer; min-width: 3px;
  /* Largura proporcional, vinda do componente pela propriedade customizada --segmento. */
  flex-basis: var(--segmento, 0%);
  transition: filter var(--dur-fast) var(--ease-out);
}
.bar-chart-segment:first-child { border-top-left-radius: var(--radius-md); border-bottom-left-radius: var(--radius-md); }
.bar-chart-segment:last-child { border-top-right-radius: var(--radius-md); border-bottom-right-radius: var(--radius-md); }
.bar-chart-segment:hover, .bar-chart-segment:focus-visible { filter: brightness(0.92); }
.bar-chart-segment:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--color-focus-ring); }

/* Sinal — mesmos tokens do badge/metric-card-delta */
.bar-chart-segment-info     { background: var(--color-info); }
.bar-chart-segment-success  { background: var(--color-success); }
.bar-chart-segment-warning  { background: var(--color-warning); }
.bar-chart-segment-danger   { background: var(--color-danger); }
.bar-chart-segment-neutral  { background: light-dark(var(--neutral-400), var(--neutral-500)); }
.bar-chart-legend-dot-info    { background: var(--color-info); }
.bar-chart-legend-dot-success { background: var(--color-success); }
.bar-chart-legend-dot-warning { background: var(--color-warning); }
.bar-chart-legend-dot-danger  { background: var(--color-danger); }
.bar-chart-legend-dot-neutral { background: light-dark(var(--neutral-400), var(--neutral-500)); }

/* Skeleton — usa as formas de skeleton.css direto no markup, sem classe propria */
.bar-chart-row .skeleton.sk-line { height: 22px; border-radius: var(--radius-md); }

@media (max-width: 640px) {
  .bar-chart-row { grid-template-columns: minmax(0, 96px) minmax(0, 1fr) minmax(2.25rem, max-content); }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — RATING
   Seleção de 1-5 estrelas (satisfação/feedback). Interativo (botão, estado
   via classe .is-filled setada em runtime) e somente-leitura (.rating-readonly,
   para exibir uma nota já registrada). Token-only, sem cor literal.
   ========================================================================= */
.rating { display: inline-flex; align-items: center; gap: var(--sp-1); }
.rating-star {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; padding: 0; border: 0; border-radius: var(--radius-md);
  background: transparent; color: var(--color-border-strong); cursor: pointer;
  transition: color var(--dur-fast) var(--ease);
}
.rating-star svg { width: 26px; height: 26px; fill: none; stroke: currentColor; stroke-width: 1.6; }
.rating-star:hover { color: var(--color-warning); }
.rating-star:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--color-focus-ring); }
.rating-star.is-filled { color: var(--color-warning); }
.rating-star.is-filled svg { fill: currentColor; }

.rating-value { font-size: var(--fs-sm); color: var(--color-text-muted); margin-inline-start: var(--sp-1); }

/* Tamanho maior — destaque em popup de feedback */
.rating-lg .rating-star { width: 48px; height: 48px; }
.rating-lg .rating-star svg { width: 32px; height: 32px; }

/* Somente-leitura — nota já registrada, sem interação */
.rating-readonly .rating-star { width: 20px; height: 20px; cursor: default; }
.rating-readonly .rating-star svg { width: 16px; height: 16px; }
.rating-readonly .rating-star:hover { color: var(--color-border-strong); }
.rating-readonly .rating-star.is-filled:hover { color: var(--color-warning); }
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — ALERT BANNER (comunicado do sistema)
   Faixa de comunicado no topo do PRODUTO, acima de tudo: atravessa sidebar e
   topbar, largura total da janela. Nao e alerta de tela (.alert, no miolo do
   form) nem situacao de registro (.status-banner): fala do SERVICO, vale para
   qualquer tela. Sai quando o comunicado sai (sistema) ou o usuario fecha
   pelo X (.alert-banner-close) — o fechamento e por sessao, nao resolve o
   comunicado; ele reaparece na proxima sessao/tela se o sistema mantiver o
   sinal.
   Uma faixa por vez. Publicada pelo sistema, nunca pela tela.
   ========================================================================= */
.alert-banner {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-3);
    flex: none;
    padding: var(--sp-3) var(--sp-9);
    z-index: var(--z-sticky);
    font-size: var(--fs-base);
    font-weight: var(--fw-medium);
    line-height: var(--lh-normal);
    color: var(--color-text);
    background: var(--color-surface-2);
    border-bottom: 2px solid var(--color-border);
}

.alert-banner-close {
    position: absolute;
    top: 50%;
    right: var(--sp-4);
    transform: translateY(-50%);
    flex: none;
    border: 0;
    background: transparent;
    color: currentColor;
    opacity: 0.7;
    cursor: pointer;
    padding: var(--sp-1);
}

.alert-banner-close:hover {
    opacity: 1;
}

.alert-banner-close svg {
    display: block;
    width: 16px;
    height: 16px;
}

.alert-banner[hidden] {
    display: none;
}

.alert-banner-icon {
    width: 18px;
    height: 18px;
    flex: none;
}

.alert-banner-text {
    min-width: 0;
    text-wrap: pretty;
}

/* Sinais — mesmos papeis semanticos do .alert */
.alert-banner-warning {
    background: var(--color-warning-soft);
    border-bottom-color: var(--color-warning);
}

    .alert-banner-warning .alert-banner-icon {
        color: var(--color-warning);
    }

.alert-banner-danger {
    background: var(--color-danger-soft);
    border-bottom-color: var(--color-danger);
}

    .alert-banner-danger .alert-banner-icon {
        color: var(--color-danger);
    }

.alert-banner-info {
    background: var(--color-info-soft);
    border-bottom-color: var(--color-info);
}

    .alert-banner-info .alert-banner-icon {
        color: var(--color-info);
    }

.alert-banner-success {
    background: var(--color-success-soft);
    border-bottom-color: var(--color-success);
}

    .alert-banner-success .alert-banner-icon {
        color: var(--color-success);
    }

/* -------------------------------------------------------------------------
   MOLDURA — a faixa fica ACIMA do .app-shell, entao a altura do shell deixa
   de ser 100vh e passa a ser o que sobra. Envolver faixa + shell nesta
   moldura (vale tambem sem faixa: o shell continua ocupando a janela).
   ------------------------------------------------------------------------- */
.app-banner-frame {
    display: flex;
    flex-direction: column;
    height: 100vh;
    overflow: hidden;
}

    /* Altura definida na moldura: o shell fica com o que sobra e o miolo volta a
       ser o unico elemento que rola (topbar sticky na coluna, nao no documento). */
    .app-banner-frame > .app-shell {
        flex: 1 1 auto;
        min-height: 0;
        height: 100%;
        grid-template-rows: minmax(0, 1fr);
    }

        .app-banner-frame > .app-shell > .content {
            height: 100%;
            min-height: 0;
        }

@media (max-width: 640px) {
    .alert-banner {
        justify-content: flex-start;
        align-items: flex-start;
        padding: var(--sp-3) var(--sp-9) var(--sp-3) var(--sp-4);
    }

    .alert-banner-icon {
        margin-top: 1px;
    }

    .alert-banner-close {
        top: var(--sp-3);
        right: var(--sp-3);
        transform: none;
    }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — STATUS DO SISTEMA (topbar)
   Gatilho a esquerda da identidade do usuario no topbar: resume o mesmo sinal
   do .alert-banner (verde quando nao ha comunicado). Mensagem no padrao de
   tooltip de ajuda do DS (.has-tooltip.has-tooltip-help, tooltip.css) —
   clique alterna .is-shown, igual ao padrao "copiavel" de placa/chassi.
   ========================================================================= */
.system-status-trigger {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--control-h); height: var(--control-h); flex: none;
  border: 0; border-radius: var(--radius-md); background: none; cursor: pointer;
  color: var(--color-success);
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.system-status-trigger:hover, .system-status-trigger.is-shown { background: var(--color-surface-hover); }
.system-status-icon { width: 20px; height: 20px; }
/* Sem icone escolhido pelo produto, o gatilho e um ponto na cor do sinal. */
.system-status-dot { width: 10px; height: 10px; border-radius: var(--radius-full); background: currentColor; }

.system-status-trigger.system-status-warning { color: var(--color-warning); }
.system-status-trigger.system-status-danger  { color: var(--color-danger); }
.system-status-trigger.system-status-info    { color: var(--color-info); }
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — FAIXA DE SITUACAO
   Nome oficial: .status-banner. Faixa larga no topo da tela que declara em que
   situacao o registro esta AGORA e o que se espera a seguir. Nao e alerta:
   .alert e evento (algo aconteceu / falhou); .status-banner e estado permanente
   enquanto durar a situacao.
     .status-banner       -> faixa
     .status-banner-icon  -> selo do sinal (SVG inline dentro)
     .status-banner-title -> a situacao ("Proposta assinada")
     .status-banner-text  -> o que se espera a seguir
     .status-banner-actions-> acao ligada a situacao (opcional)
   Sinal por classe somada: -success / -info / -warning / -danger / -neutral.
   ========================================================================= */
.status-banner {
    --sb-color: var(--color-text-subtle);
    --sb-soft: var(--color-surface-2);
    display: flex; align-items: flex-start; gap: var(--sp-4);
    padding: var(--sp-4) var(--sp-5);
    background: var(--sb-soft); color: var(--color-text);
    border: var(--border-w) solid color-mix(in oklab, var(--sb-color) 32%, transparent);
    border-radius: var(--radius-lg);
}
.status-banner-icon {
    display: inline-flex; align-items: center; justify-content: center; flex: none;
    width: 36px; height: 36px; border-radius: var(--radius-full);
    background: var(--color-surface); color: var(--sb-color);
}
.status-banner-icon svg { width: 20px; height: 20px; }
.status-banner-content { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.status-banner-title { font-size: var(--fs-base); font-weight: var(--fw-semibold); letter-spacing: var(--ls-tight); }
.status-banner-text { font-size: var(--fs-sm); color: var(--color-text-muted); text-wrap: pretty; }
.status-banner-actions { display: inline-flex; align-items: center; gap: var(--sp-2); flex: none; }

.status-banner-success { --sb-color: var(--color-success); --sb-soft: var(--color-success-soft); }
.status-banner-info    { --sb-color: var(--color-info);    --sb-soft: var(--color-info-soft); }
.status-banner-warning { --sb-color: var(--color-warning); --sb-soft: var(--color-warning-soft); }
.status-banner-danger  { --sb-color: var(--color-danger);  --sb-soft: var(--color-danger-soft); }
.status-banner-neutral { --sb-color: var(--color-text-subtle); --sb-soft: var(--color-surface-2); }

@media (max-width: 768px) {
    .status-banner { flex-wrap: wrap; }
    .status-banner-actions { width: 100%; }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — AJUDA (TELA E BLOCO)
   Explica, na propria tela, o que ela faz e o que ela afeta. Nao e alerta
   (.alert = evento) nem situacao do registro (.status-banner = estado do
   dado): ajuda e texto sobre a INTERFACE — estavel, dispensavel, desligavel.

   Dois niveis, mesma anatomia e a mesma chave global:
     .help-note                  -> ajuda da TELA: faixa azul sob o titulo
     .help-note.help-note-block  -> ajuda de um BLOCO: faixa cinza dentro dele
   O "?" ao lado do titulo correspondente (.help-title) fica sempre visivel e
   liga/desliga a faixa; o "x" da faixa desliga tambem. Cada "?" aponta para o
   id da sua faixa por data-help-target.

   Chave global do usuario (menu do usuario, como o tema): data-help="off" no
   <html> apaga todo .screen-help. Uma ajuda de tela por tela; ajuda de bloco so
   quando o bloco tem regra propria — nunca a mesma frase nos dois niveis.
   Referencia: components/17-screen-help.card.html · telas/05-ajuda-em-uso.card.html
   ========================================================================= */

/* Chave global — preferencia do usuario, no menu do usuario, como o tema */
:root[data-help="off"] .screen-help {
    display: none;
}

/* Dispensada pelo usuario nesta tela — classe, nunca [hidden]: quem controla
   `hidden` em [data-state*] e o estado do elemento, nao a ajuda. */
.help-note.is-dismissed {
    display: none;
}

/* ---- Faixa da tela ---- */
.help-note {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    margin: 0 0 var(--sp-5);
    padding: var(--sp-3) var(--sp-4);
    border: var(--border-w) solid var(--color-accent-soft);
    border-radius: var(--radius-md);
    background: var(--color-accent-soft);
    font-size: var(--fs-sm);
    color: var(--color-text-muted);
}
/* Colada no titulo: absorve a margem inferior do .page-head */
.page-head + .help-note {
    margin-top: calc(var(--sp-2) - var(--sp-5));
}

.help-note-glyph {
    width: 16px;
    height: 16px;
    flex: none;
    margin-top: 2px;
    color: var(--color-accent);
}

.help-note-text {
    flex: 1;
    text-wrap: pretty;
}

    .help-note-text strong {
        color: var(--color-text);
        font-weight: var(--fw-semibold);
    }

/* ---- Faixa de bloco — cinza e mais discreta: hierarquia visivel entre
   "o que a tela faz" (azul, uma vez) e "a regra deste bloco" (cinza, n vezes) ---- */
.help-note-block {
    border-color: var(--color-border);
    background: var(--color-surface-2);
}

    .help-note-block .help-note-glyph {
        color: var(--color-text-subtle);
    }
/* Dentro do cabecalho do bloco: titulo (e acoes) na primeira linha, a faixa
   logo abaixo dele, no MESMO bloco — nao no corpo. O cabecalho ja e cinza,
   entao a faixa aqui usa a superficie do card para se distinguir. */
.card-header:has(> .help-note-block) {
    flex-wrap: wrap;
}

.card-header > .help-note-block {
    flex: 0 0 100%;
    margin: 0;
    background: var(--color-surface);
}

/* ---- Fechar — a ajuda nunca prende a tela ---- */
.help-close {
    display: inline-grid;
    place-items: center;
    flex: none;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-sm);
    background: none;
    color: var(--color-text-subtle);
    cursor: pointer;
}

    .help-close svg {
        width: 14px;
        height: 14px;
    }

    .help-close:hover {
        background: var(--color-surface-hover);
        color: var(--color-text);
    }

.help-note .help-close {
    margin-top: -1px;
    margin-inline-start: auto;
}

/* ---- Gatilho "?" ao lado do titulo (da tela ou do bloco) — SEMPRE visivel:
   liga e desliga a ajuda correspondente; aria-expanded diz em que estado esta ---- */
.help-title {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

.help-trigger {
    display: inline-grid;
    place-items: center;
    flex: none;
    width: 22px;
    height: 22px;
    padding: 0;
    border: var(--border-w) solid var(--color-border-strong);
    border-radius: var(--radius-full);
    background: var(--color-surface);
    color: var(--color-text-subtle);
    cursor: pointer;
    transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}

    .help-trigger svg {
        width: 14px;
        height: 14px;
    }

    .help-trigger:hover {
        border-color: var(--color-primary);
        color: var(--color-primary);
    }

    .help-trigger[aria-expanded="true"] {
        border-color: var(--color-primary-border);
        background: var(--color-primary-soft);
        color: var(--color-primary);
    }

@media (prefers-reduced-motion: reduce) {
    .help-trigger {
        transition-duration: 0s;
    }
}

/* Dentro de container flex com gap, a margem da faixa nao se aplica */
.stepper-panel > .help-note {
    margin-bottom: 0;
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — LOGIN / AUTENTICACAO
   Nome oficial: .auth-*. Tela de acesso: card centralizado sobre o fundo da
   aplicacao, marca, campos, submit com is-loading e mensagens.
   REGRA DE OURO (auth): SEM empty e SEM skeleton — so normal, loading e erro.
     - erro de credencial = regra de negocio -> .alert.alert-danger no TOPO do card
     - campo obrigatorio/formato = validacao -> .invalid + .validation-message

     .auth-shell    -> fundo de tela cheia, centraliza o card
     .auth-card     -> cartao do formulario
     .auth-brand    -> marca (mesmo tratamento do .sidebar-brand)
     .auth-eyebrow  -> nome do portal acima do titulo (opcional)
     .auth-title / -sub
     .auth-panel-media -> foto opcional do painel de marca (split)
     .auth-form     -> pilha de campos (.field)
     .auth-row      -> linha "lembrar-me" + "esqueci minha senha"
     .auth-link     -> link secundario
     .auth-foot     -> rodape (versao, suporte)
   Serve tambem a recuperacao de senha e primeiro acesso (mesmo shell/card).
   ========================================================================= */
.auth-shell {
  display: grid; place-items: center; min-height: 100dvh;
  padding: var(--sp-6); background: var(--color-bg); color: var(--color-text);
}
.auth-card {
  width: 100%; max-width: 25rem;
  padding: clamp(var(--sp-6), 4vw, var(--sp-8));
  background: var(--color-surface); border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius-xl); box-shadow: var(--shadow-md);
}

/* Marca — lockup horizontal (imagem do tema, troca sozinha no escuro) */
.auth-brand { display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-6); }
.auth-logo { display: block; height: 34px; aspect-ratio: var(--logo-lockup-ratio); background: var(--logo-lockup) center / contain no-repeat; }
.auth-mark { width: 48px; height: 48px; flex: none; border-radius: var(--radius-lg); background: var(--color-primary); box-shadow: var(--shadow-sm); }
.auth-name { font-family: var(--font-display); font-size: var(--fs-2xl); font-weight: 400; letter-spacing: var(--ls-tight); line-height: 1; }

/* Cabecalho do formulario */
.auth-head { text-align: center; margin-bottom: var(--sp-6); }
/* Nome do portal/produto acima do titulo (quando o mesmo login serve varios portais) */
.auth-eyebrow { margin: 0 0 var(--sp-2); font-size: var(--fs-xs); font-weight: var(--fw-semibold); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--color-primary); }
.auth-title { font-size: var(--fs-xl); font-weight: var(--fw-semibold); letter-spacing: var(--ls-tight); }
.auth-title.help-title { justify-content: center; }
.auth-sub { margin-top: var(--sp-1); font-size: var(--fs-sm); color: var(--color-text-muted); text-wrap: pretty; }

/* Erro de regra de negocio — sempre no topo, antes dos campos */
.auth-card .alert { margin-bottom: var(--sp-5); }

/* Formulario */
.auth-form { display: flex; flex-direction: column; gap: var(--sp-4); }
.auth-card .field { display: block; min-width: 0; }
.auth-row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; }
.auth-link { color: var(--color-link); font-size: var(--fs-sm); text-decoration: none; }
.auth-link:hover { color: var(--color-link-hover); text-decoration: underline; }
.auth-actions { display: flex; flex-direction: column; gap: var(--sp-3); margin-top: var(--sp-1); }
.auth-card .btn-action-block { height: var(--control-h-lg); font-size: var(--fs-base); }

/* Espera do servidor: campos e acoes secundarias travados */
.auth-form.is-busy { cursor: progress; }
.auth-form.is-busy .input-container { background: var(--color-surface-2); }
.auth-form.is-busy .auth-link { pointer-events: none; opacity: 0.6; }

/* Rodape */
.auth-foot { margin-top: var(--sp-6); text-align: center; font-size: var(--fs-xs); color: var(--color-text-subtle); }
.auth-foot .auth-link { font-size: var(--fs-xs); }

@media (max-width: 480px) {
  .auth-shell { padding: var(--sp-4); align-items: start; padding-top: var(--sp-8); }
  .auth-card { border: 0; box-shadow: none; background: transparent; padding-inline: 0; }
}

/* =========================================================================
   COMPOSICOES DE TELA — o .auth-card e o mesmo; muda a moldura.
     B) .auth-shell-split -> PADRAO de login: painel de marca + formulario
     A) .auth-shell (acima) -> card centralizado; serve recuperacao de senha,
        primeiro acesso e o fallback de <=900px do split
   ========================================================================= */

/* B) Dividida ------------------------------------------------------------ */
.auth-shell-split { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); place-items: stretch; padding: 0; }
.auth-panel {
  display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-8);
  padding: clamp(var(--sp-6), 4vw, var(--sp-9));
  background: var(--color-primary); color: var(--color-on-primary);
  position: relative; isolation: isolate; overflow: hidden;
}
/* Foto opcional no painel: <img class="auth-panel-media" alt=""> como primeiro filho.
   O veu de marca (::before) garante contraste do texto sobre qualquer foto. */
.auth-panel-media { position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%; object-fit: cover; }
.auth-panel:has(> .auth-panel-media)::before { content: ""; position: absolute; inset: 0; z-index: -1; background: color-mix(in oklab, var(--color-primary) 78%, transparent); }
.auth-panel .auth-brand { flex-direction: row; align-items: center; gap: var(--sp-3); margin: 0; }
.auth-panel .auth-logo { height: clamp(4rem, 6vw, 5.5rem); background-image: var(--logo-lockup-invert); }
.auth-panel-claim { max-width: 26ch; font-family: var(--font-display); font-size: clamp(var(--fs-2xl), 3vw, var(--fs-4xl)); font-weight: 400; line-height: var(--lh-tight); letter-spacing: var(--ls-tight); text-wrap: balance; }
.auth-panel-note { max-width: 42ch; font-size: var(--fs-sm); opacity: 0.82; text-wrap: pretty; }
.auth-panel-foot { display: flex; align-items: center; gap: var(--sp-3); font-size: var(--fs-xs); opacity: 0.75; }
.auth-split-main { display: grid; place-items: center; padding: clamp(var(--sp-6), 4vw, var(--sp-9)); background: var(--color-surface); }
.auth-shell-split .auth-card { border: 0; box-shadow: none; background: transparent; padding: 0; max-width: 23rem; }
.auth-shell-split .auth-card .auth-brand { display: none; }
.auth-shell-split .auth-head { text-align: start; }

@media (max-width: 900px) {
  .auth-shell-split { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .auth-panel { flex-direction: row; align-items: center; justify-content: space-between; gap: var(--sp-4); padding: var(--sp-5) var(--sp-6); }
  .auth-panel-claim, .auth-panel-note { display: none; }
  .auth-panel .auth-logo { height: 40px; }
  .auth-panel-foot { font-size: var(--fs-xs); }
  .auth-split-main { padding: var(--sp-6) var(--sp-5) var(--sp-8); align-items: start; }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — PAGINA DE STATUS DO SISTEMA
   Pagina publica e autonoma (sem shell) com a saude do sistema: situacao
   geral, servicos monitorados e historico de incidentes. Distinto de
   .status-banner (situacao PERMANENTE de um REGISTRO de negocio, dentro do
   app): aqui o assunto e a saude do SISTEMA, publico, atualizado por polling.

     .status-page          -> moldura de tela cheia (sem sidebar/topbar)
     .status-page-inner    -> coluna de leitura centralizada
     .status-page-head     -> marca + titulo da pagina
     .status-page-brand / -logo
     .status-page-title
     .status-page-foot     -> rodape (fuso horario etc.)

     .status-overview        -> faixa de situacao geral (hero)
     .status-overview-icon / -content / -title / -text / -meta / -time
   Sinal por classe somada, mesmo vocabulario do .status-banner:
     -success / -warning / -danger / -neutral

     .service-status-list  -> <ul> de servicos monitorados (dentro de .card)
     .service-status-row   -> <li>: indicador + nome/descricao + uptime + badge
     .service-status-dot   -> ponto de sinal (o "balaozinho"); sinal por
                              classe somada na ROW: -warning / -danger / -neutral
     .service-status-info  -> coluna nome + descricao
     .service-status-name / -desc
     .service-status-uptime -> mini-historico (barras) + percentual
     .service-status-bars / -bar (modificadores -warning / -danger)
     .service-status-uptime-value
   O selo textual de status usa .badge (badge-success/-warning/-danger +
   badge-dot), ja existente — nao duplica vocabulario. Skeleton de linha usa
   .skeleton/.sk-* ja existentes.

   Historico de incidentes reaproveita .timeline / .timeline-item (ver
   16-timeline.card.html) — sem componente novo.

   Estados: normal, vazio (.empty-state), skeleton (.skeleton/.sk-*), loading
   (botao Atualizar em is-loading) e erro (.empty-state-danger). Pagina e
   somente leitura — sem estado de validacao.
   ========================================================================= */
.status-page { min-height: 100dvh; background: var(--color-bg); color: var(--color-text); padding: var(--sp-8) var(--sp-5) var(--sp-10); }
.status-page-inner { max-width: 46rem; margin: 0 auto; display: flex; flex-direction: column; gap: var(--sp-6); }

.status-page-head { display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); text-align: center; }
.status-page-brand { display: flex; }
.status-page-logo { display: block; height: 28px; aspect-ratio: var(--logo-lockup-ratio); background: var(--logo-lockup) center / contain no-repeat; }
.status-page-title { font-family: var(--font-display); font-size: var(--fs-2xl); font-weight: 400; letter-spacing: var(--ls-tight); }
.status-page-foot { text-align: center; font-size: var(--fs-xs); color: var(--color-text-subtle); }

/* Situacao geral (hero) */
.status-overview {
  --so-color: var(--color-text-subtle); --so-soft: var(--color-surface-2);
  display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-6); background: var(--so-soft);
  border: var(--border-w) solid color-mix(in oklab, var(--so-color) 30%, transparent);
  border-radius: var(--radius-xl);
}
.status-overview-icon {
  display: grid; place-items: center; flex: none; width: 52px; height: 52px;
  border-radius: var(--radius-full); background: var(--color-surface); color: var(--so-color);
  box-shadow: var(--shadow-sm);
}
.status-overview-icon svg { width: 26px; height: 26px; }
.status-overview-content { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.status-overview-title { font-size: var(--fs-xl); font-weight: var(--fw-semibold); letter-spacing: var(--ls-tight); }
.status-overview-text { font-size: var(--fs-sm); color: var(--color-text-muted); text-wrap: pretty; }
.status-overview-meta { display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-2); flex: none; }
.status-overview-time { font-size: var(--fs-xs); color: var(--color-text-subtle); white-space: nowrap; }

.status-overview-success { --so-color: var(--color-success); --so-soft: var(--color-success-soft); }
.status-overview-warning { --so-color: var(--color-warning); --so-soft: var(--color-warning-soft); }
.status-overview-danger  { --so-color: var(--color-danger);  --so-soft: var(--color-danger-soft); }
.status-overview-neutral { --so-color: var(--color-text-subtle); --so-soft: var(--color-surface-2); }

/* Lista de servicos */
.service-status-list { list-style: none; margin: 0; padding: 0; }
.service-status-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto;
  align-items: center; gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
}
.service-status-row + .service-status-row { border-top: var(--border-w) solid var(--color-border); }
.service-status-dot {
  --ssd-color: var(--color-success);
  width: 10px; height: 10px; border-radius: var(--radius-full); flex: none;
  background: var(--ssd-color); box-shadow: 0 0 0 4px color-mix(in oklab, var(--ssd-color) 18%, transparent);
}
.service-status-row-warning .service-status-dot { --ssd-color: var(--color-warning); }
.service-status-row-danger  .service-status-dot { --ssd-color: var(--color-danger); }
.service-status-row-neutral .service-status-dot { --ssd-color: var(--color-text-subtle); }
.service-status-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.service-status-name { font-size: var(--fs-base); font-weight: var(--fw-semibold); }
.service-status-desc { font-size: var(--fs-sm); color: var(--color-text-muted); }
.service-status-uptime { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; flex: none; }
.service-status-bars { display: flex; align-items: flex-end; gap: 2px; }
.service-status-bar { width: 5px; height: 18px; border-radius: 2px; background: var(--color-success); }
.service-status-bar-warning { background: var(--color-warning); }
.service-status-bar-danger { background: var(--color-danger); }
.service-status-uptime-value { font-size: var(--fs-xs); color: var(--color-text-subtle); font-variant-numeric: tabular-nums; }
.service-status-badge { flex: none; }

@media (max-width: 640px) {
  .status-overview { flex-wrap: wrap; }
  .status-overview-meta { width: 100%; flex-direction: row; align-items: center; justify-content: space-between; }
  .service-status-row { grid-template-columns: auto minmax(0,1fr) auto; }
  .service-status-uptime { display: none; }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — CRASH DO APLICATIVO (AppErrorOverlay)
   Overlay de tela cheia para exceção não tratada (equivalente ao aviso nativo
   do host de app). Fica ACIMA de qualquer modal/toast (--z-toast): um crash
   invalida o que estava aberto. Sem X e sem fechar pelo backdrop — só as duas
   ações do rodapé decidem o que acontece a seguir.

     .app-error          -> overlay de tela cheia, oculto por padrão
     .app-global-error   -> classe somada que exibe o overlay (mesmo padrão de .is-open)
     .app-error-panel    -> cartão (mesma superfície do Modal)
     .app-error-mark     -> selo de alerta (--color-danger-soft)
     .app-error-actions  -> Recarregar (secundário) + Tentar novamente (primário, à direita)

   Recarregar = reload completo da página. Tentar novamente = só fecha o
   overlay, sem reload — o app continua de onde estava. Token-only, dark-ready.

   Integração Blazor: bool no componente raiz (ex.: IsGlobalError) soma a
   classe .app-global-error no mesmo elemento — igual .is-open em
   dropdown/offcanvas/accordion. Nada de id fixo, nada de style inline
   setado por JS. A centralização do painel usa position:absolute + inset +
   margin:auto (funciona com o parent em block OU flex).
   ========================================================================= */
.app-error {
  position: fixed; inset: 0; z-index: var(--z-toast); background: var(--color-overlay);
  display: none;
}
.app-error.app-global-error { display: block; }
.app-error-panel {
  position: absolute; inset: var(--sp-6); margin: auto; height: max-content;
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-5);
  width: 100%; max-width: 420px; text-align: center; padding: var(--sp-7) var(--sp-6);
  background: var(--color-surface); color: var(--color-text);
  border: var(--border-w) solid var(--color-border); border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
}
.app-error-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 52px; height: 52px; flex: none; border-radius: var(--radius-full);
  background: var(--color-danger-soft); color: var(--color-danger);
}
.app-error-mark svg { width: 26px; height: 26px; }
.app-error-heading { display: flex; flex-direction: column; gap: var(--sp-2); }
.app-error-title { font-size: var(--fs-xl); font-weight: var(--fw-semibold); line-height: var(--lh-snug); }
.app-error-text { font-size: var(--fs-base); line-height: var(--lh-normal); color: var(--color-text-muted); }
.app-error-actions { display: flex; align-items: center; justify-content: center; gap: var(--sp-3); }

@media (max-width: 480px) {
  .app-error-panel { max-width: 100%; }
  .app-error-actions { flex-direction: column-reverse; align-self: stretch; }
  .app-error-actions .btn-action { width: 100%; }
}
/* =========================================================================
   ESSENTIALS.WEBBLAZOR V3 — TIMER
   Extensao local (nao vem do design system): contagem regressiva simples.
   ========================================================================= */
.timer {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    font-variant-numeric: tabular-nums;
}

.timer-icone {
    flex: none;
    width: 16px;
    height: 16px;
    color: var(--color-text-muted);
}

.timer-tempo {
    font-size: var(--fs-sm);
    font-weight: var(--fw-medium);
    color: var(--color-text);
}
/* =========================================================================
   ESSENTIALS.WEBBLAZOR V3 — CLIPBOARD
   Extensao local (nao vem do design system): botao de copiar acoplado a
   um conteudo qualquer.
   ========================================================================= */
.clipboard {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
}

.clipboard-botao {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 1.75rem;
    height: 1.75rem;
    border: 0;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--color-text-subtle);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}

    .clipboard-botao:hover {
        background: var(--color-surface-hover);
        color: var(--color-text);
    }

    .clipboard-botao:focus-visible {
        outline: 2px solid var(--color-focus-ring);
        outline-offset: 2px;
    }

.clipboard-icone {
    width: 16px;
    height: 16px;
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — TELA DE CARREGAMENTO (BOOT)
   Splash de tela cheia obrigatorio no carregamento inicial de QUALQUER
   produto que herde este DS (o primeiro acesso, com WASM baixando/
   inicializando, e o caso mais lento — mas a peca cobre todo carregamento
   inicial da tela). No app Blazor, vai como conteudo de fallback dentro de
   <div id="app"> no index.html — o Blazor o substitui ao terminar.

     .app-boot            -> overlay de tela cheia, centralizado
     .app-boot-mark/name  -> simbolo da marca (--brand-simbolo) + nome
     .app-boot-progress   -> trilha; .is-indeterminate (padrao) ou .is-determinate
     .app-boot-bar        -> preenchimento
     .app-boot-status     -> linha de apoio ("Preparando o aplicativo…")

   Estrutura, tokens e acessibilidade sao fixos e vem daqui. A ANIMACAO do
   .app-boot-mark (@keyframes app-boot-breathe abaixo) e so a REFERENCIA do
   DS — cada produto cria a propria, do jeito que melhor combinar com o
   proprio simbolo (girar, desenhar o traco, morph), trocando a declaracao
   `animation` e o `@keyframes` nesta mesma classe. Regra fixa ao trocar:
   usar os tokens de `--dur-*`/`--ease` (nao segundos soltos) e manter o
   fallback de `prefers-reduced-motion` no fim do arquivo.

   Token-only, dark-ready.
   ========================================================================= */
.app-boot {
  position: fixed; inset: 0; z-index: var(--z-modal);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-7); padding: var(--sp-6); background: var(--color-bg); color: var(--color-text);
}
.app-boot-brand { display: flex; flex-direction: column; align-items: center; gap: var(--sp-4); }
.app-boot-mark {
  width: 72px; height: 72px; flex: none;
  background-image: light-dark(var(--brand-simbolo), var(--brand-simbolo-branco));
  background-size: contain; background-repeat: no-repeat; background-position: center;
  animation: app-boot-breathe 2.4s var(--ease) infinite;
}
.app-boot-name { font-family: var(--font-display); font-size: var(--fs-4xl); letter-spacing: var(--ls-tight); line-height: 1; }

.app-boot-progress {
  width: 260px; max-width: 72vw; height: 4px; overflow: hidden;
  border-radius: var(--radius-full); background: var(--color-surface-hover);
}
.app-boot-bar { display: block; height: 100%; border-radius: inherit; background: var(--color-primary); }
/* Indeterminado (padrao no boot: nao ha % confiavel) — desliza */
.app-boot-progress.is-indeterminate .app-boot-bar { width: 40%; animation: app-boot-slide 1.15s var(--ease) infinite; }
/* Determinado — quando ha progresso real; JS ajusta --boot-progress (0..100%) */
.app-boot-progress.is-determinate .app-boot-bar { width: var(--boot-progress, 0%); transition: width var(--dur-base) var(--ease); }

.app-boot-status { font-size: var(--fs-sm); color: var(--color-text-muted); }
.app-boot-status[data-percent]::after { content: " " attr(data-percent) "%"; font-variant-numeric: tabular-nums; }
/* Falha no download do aplicativo — mensagem + acao de recarregar */
.app-boot-actions { display: flex; align-items: center; gap: var(--sp-2); }
.app-boot-status-danger { color: var(--color-danger); }

@keyframes app-boot-slide { 0% { transform: translateX(-100%); } 100% { transform: translateX(340%); } }
@keyframes app-boot-breathe { 50% { transform: scale(1.06); opacity: 0.85; } }

/* Movimento reduzido: sem deslizar/pulsar espacial — mantem feedback via opacidade */
@media (prefers-reduced-motion: reduce) {
  .app-boot-mark { animation: none; }
  .app-boot-progress.is-indeterminate .app-boot-bar { width: 100%; animation: app-boot-fade 1.2s ease-in-out infinite; }
}
@keyframes app-boot-fade { 50% { opacity: 0.4; } }
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — CANAIS DE ERRO NAO TRATADO
   Dois canais, dois momentos: #blazor-error-ui e revelado pelo host quando
   uma excecao escapa com o app rodando; #arranque-erro-ui e revelado pelo
   catch do Blazor.start() quando o bundle nao sobe.
   Antes da v3 o produto copiava a faixa de rodape do template para o proprio
   app.css, porque a v3 nao estilizava nenhum dos dois — sem display:none a
   div nascia visivel em toda pagina. Agora e a fundacao que estiliza.
   ATENCAO: o host escreve style="display: block" INLINE no elemento. Por isso
   a centralizacao nao pode depender de flex nem de grade — o display forcado
   as desmontaria na hora exata em que a faixa serve para alguma coisa.
   inset + margin:auto + height:fit-content centram sob display:block.
   O escurecimento do fundo e box-shadow com espalhamento, nao elemento a
   parte: box-shadow pinta fora da caixa, entao nao cobre o proprio cartao, e
   nao exige marcacao que o produto teria de escrever.
   ========================================================================= */
#blazor-error-ui,
#arranque-erro-ui {
    display: none;
    position: fixed;
    inset: 0;
    margin: auto;
    width: min(30rem, calc(100% - var(--sp-8)));
    height: fit-content;
    z-index: var(--z-modal);
    box-sizing: border-box;
    padding: var(--sp-6);
    background: var(--color-surface);
    color: var(--color-text);
    border: var(--border-w) solid var(--color-border);
    border-top: 3px solid var(--color-danger);
    border-radius: var(--radius-xl);
    box-shadow: 0 0 0 100vmax var(--color-overlay), var(--shadow-lg);
    font-size: var(--fs-base);
    line-height: var(--lh-normal);
    text-align: center;
}

/* Acao em linha propria. O pai tem display:block forcado pelo host e o texto
   do template e no corpo do elemento, sem embrulho — inline-block com
   margin-top nao quebra linha, e o botao cola no fim da frase. Bloco com
   width:fit-content e margem automatica cai na linha seguinte e centraliza,
   sem depender de flex nem de grade, que o display forcado desmontaria. */
    #blazor-error-ui .reload,
    #blazor-error-ui .dismiss,
    #arranque-erro-ui .recarregar {
        display: block;
        width: fit-content;
        margin: var(--sp-5) auto 0;
        padding: var(--sp-3) var(--sp-5);
        border: var(--border-w) solid transparent;
        border-radius: var(--radius-lg);
        font-size: var(--fs-base);
        font-weight: var(--fw-semibold);
        line-height: var(--lh-snug);
        text-decoration: none;
        cursor: pointer;
    }

    #blazor-error-ui .reload,
    #arranque-erro-ui .recarregar {
        background: var(--color-primary-fill);
        color: var(--color-on-primary-fill);
    }

        #blazor-error-ui .reload:hover,
        #arranque-erro-ui .recarregar:hover {
            background: var(--color-primary-fill-hover);
        }

/* Dispensar existe no contrato do template e fica secundario de proposito:
   depois de excecao nao tratada o estado do app e suspeito, e continuar nele
   e escolha, nao caminho recomendado. */
    #blazor-error-ui .dismiss {
        background: transparent;
        color: var(--color-text-muted);
        border-color: var(--color-border);
        margin-top: var(--sp-3);
    }

        #blazor-error-ui .dismiss:hover {
            background: var(--color-surface-hover);
            color: var(--color-text);
        }

    #blazor-error-ui .reload:focus-visible,
    #blazor-error-ui .dismiss:focus-visible,
    #arranque-erro-ui .recarregar:focus-visible {
        outline: 2px solid var(--color-focus-ring);
        outline-offset: 2px;
    }

/* Faixa do componente ErrorBoundary. Marcacao do framework, nao do produto:
   estilo dela e da fundacao pelo mesmo motivo dos dois canais acima. */
.blazor-error-boundary {
    padding: var(--sp-4) var(--sp-5);
    background: var(--color-danger-soft);
    color: var(--color-text);
    border: var(--border-w) solid var(--color-danger);
    border-radius: var(--radius-lg);
    font-size: var(--fs-sm);
    line-height: var(--lh-snug);
}

    .blazor-error-boundary::after {
        content: "Ocorreu um erro ao exibir esta parte da tela.";
    }
.contencao-de-erro {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-4);
    padding: var(--sp-8) var(--sp-4);
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — MEDIA GRID (grade de midias)
   Grade responsiva de fotos e videos: miniatura + rotulo +
   acao de visualizar. Token-only, dark-ready, com estados (normal, selecao,
   aprovada/reprovada, erro, skeleton e vazio) e visualizador em tela cheia.
   ========================================================================= */
.media-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 17rem), 1fr)); gap: var(--sp-4); }
.media-grid-sm { grid-template-columns: repeat(auto-fill, minmax(min(100%, 11rem), 1fr)); }
.media-grid-lg { grid-template-columns: repeat(auto-fill, minmax(min(100%, 24rem), 1fr)); }

/* ---- Cartao ---- */
.media-card {
  display: flex; flex-direction: column; gap: var(--sp-3); min-width: 0; margin: 0; padding: var(--sp-3);
  background: var(--color-surface); color: var(--color-text);
  border: var(--border-w) solid var(--color-border); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.media-card:hover { border-color: var(--color-border-strong); box-shadow: var(--shadow-md); transform: translateY(-1px); }
.media-card:focus-within { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 3px var(--color-focus-ring); }
.media-card.is-selected { border-color: var(--color-primary); box-shadow: 0 0 0 2px var(--color-primary-border); }

/* ---- Miniatura ---- */
.media-card .media-thumb {
  position: relative; display: grid; place-items: center; overflow: hidden;
  aspect-ratio: 4 / 3; border-radius: var(--radius-md); background: var(--color-surface-2);
  border: var(--border-w) solid var(--color-border);
}
.media-card .media-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.media-grid-tall .media-thumb { aspect-ratio: 3 / 4; }
.media-grid-square .media-thumb { aspect-ratio: 1 / 1; }

/* Placeholder listrado — usado enquanto nao ha arquivo/preview real */
.media-card .media-placeholder {
  width: 100%; height: 100%; display: grid; place-items: center; gap: var(--sp-2);
  font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--color-text-subtle);
  text-align: center; padding: var(--sp-3);
  background-image: repeating-linear-gradient(135deg, var(--color-surface-hover) 0 8px, transparent 8px 16px);
}

/* Sobreposicoes da miniatura */
.media-card .media-flag {
  position: absolute; top: var(--sp-2); left: var(--sp-2); z-index: 1;
  display: inline-flex; align-items: center; gap: 5px; line-height: 1; white-space: nowrap;
  padding: 4px 8px; border-radius: var(--radius-full);
  font-size: var(--fs-xs); font-weight: var(--fw-semibold);
  background: var(--color-surface); color: var(--color-text-muted);
  border: var(--border-w) solid var(--color-border); box-shadow: var(--shadow-sm);
}
.media-card .media-flag svg { width: 13px; height: 13px; flex: none; }
.media-card .media-flag-danger { color: var(--color-danger); border-color: var(--color-danger); }
.media-card .media-flag-success { color: var(--color-success); border-color: var(--color-success); }
.media-card .media-flag-accent { color: var(--color-accent); border-color: var(--color-accent); }

.media-card .media-meta {
  position: absolute; right: var(--sp-2); bottom: var(--sp-2); z-index: 1;
  padding: 3px 7px; border-radius: var(--radius-sm);
  font-size: var(--fs-xs); font-weight: var(--fw-medium); font-variant-numeric: tabular-nums;
  background: var(--color-overlay); color: var(--neutral-0);
}

.media-card .media-play {
  position: absolute; z-index: 1; width: 44px; height: 44px; display: grid; place-items: center;
  border: 0; border-radius: var(--radius-full); cursor: pointer;
  background: var(--color-overlay); color: var(--neutral-0);
  transition: transform var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.media-card .media-play svg { width: 20px; height: 20px; margin-left: 2px; }
.media-card:hover .media-play { transform: scale(1.06); background: var(--color-primary); color: var(--color-on-primary); }
.media-card .media-play:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--color-focus-ring); }

/* Selecao em lote */
.media-card .media-select { position: absolute; top: var(--sp-2); right: var(--sp-2); z-index: 1; width: 18px; height: 18px; accent-color: var(--color-primary); cursor: pointer; }

/* Estados da propria midia */
.media-card.is-rejected .media-thumb { border-color: var(--color-danger); }
.media-card.is-approved .media-thumb { border-color: var(--color-success); }
.media-card .media-thumb.is-error {
  background: var(--color-danger-soft); border-color: var(--color-danger); border-style: dashed;
  color: var(--color-danger); font-size: var(--fs-sm); text-align: center; padding: var(--sp-4);
}
.media-card .media-thumb.is-error svg { width: 22px; height: 22px; margin-bottom: var(--sp-2); }

/* ---- Rodape do cartao ---- */
.media-card .media-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); min-width: 0; }
.media-card .media-heading { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.media-card .media-label { font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--color-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.media-card .media-sublabel { font-size: var(--fs-xs); color: var(--color-text-subtle); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.media-card .media-actions { display: inline-flex; align-items: center; gap: var(--sp-1); flex: none; }
.media-card .media-action {
  appearance: none; width: 32px; height: 32px; display: grid; place-items: center; flex: none;
  background: transparent; border: 0; border-radius: var(--radius-md); cursor: pointer;
  color: var(--color-text-muted); transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.media-card .media-action:hover { background: var(--color-surface-hover); color: var(--color-primary); }
.media-card .media-action:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--color-focus-ring); }
.media-card .media-action svg { width: 18px; height: 18px; }
.media-card .media-action-danger:hover { background: var(--color-danger-soft); color: var(--color-danger); }

/* ---- Vazio ---- */
.media-empty {
  grid-column: 1 / -1; display: flex; flex-direction: column; align-items: center; gap: var(--sp-2);
  padding: var(--sp-8) var(--sp-5); text-align: center;
  border: var(--border-w) dashed var(--color-border-strong); border-radius: var(--radius-lg);
  background: var(--color-surface-2); color: var(--color-text-muted);
}
.media-empty svg { width: 28px; height: 28px; color: var(--color-text-subtle); }
.media-empty .media-empty-title { font-size: var(--fs-base); font-weight: var(--fw-semibold); color: var(--color-text); }
.media-empty .media-empty-text { font-size: var(--fs-sm); max-width: 42ch; }

/* ---- Skeleton ---- */
.media-card.is-skeleton { pointer-events: none; }
.media-card.is-skeleton:hover { transform: none; box-shadow: var(--shadow-sm); border-color: var(--color-border); }
.media-card .media-skeleton { position: relative; overflow: hidden; background: var(--color-surface-hover); border-radius: var(--radius-sm); }
.media-card .media-thumb.media-skeleton { border-radius: var(--radius-md); }
.media-card .media-skeleton::after {
  content: ""; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, var(--color-surface-2), transparent);
  animation: media-skeleton-shine 1.2s infinite;
}
.media-card .media-skeleton-line { height: 12px; width: 60%; }
.media-card .media-skeleton-action { height: 24px; width: 24px; border-radius: var(--radius-md); }
@keyframes media-skeleton-shine { to { transform: translateX(100%); } }

/* ---- Visualizador (lightbox) ---- */
.media-viewer {
  position: fixed; inset: 0; z-index: var(--z-modal); display: none;
  flex-direction: column; gap: var(--sp-4); padding: var(--sp-5);
  background: var(--color-overlay); backdrop-filter: blur(2px);
}
.media-viewer.is-open { display: flex; }
.media-viewer .media-viewer-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); color: var(--neutral-0); }
.media-viewer .media-viewer-title { font-size: var(--fs-lg); font-weight: var(--fw-semibold); }
.media-viewer .media-viewer-counter { font-size: var(--fs-sm); opacity: 0.75; font-variant-numeric: tabular-nums; }
.media-viewer .media-viewer-stage { flex: 1; display: flex; align-items: center; justify-content: center; gap: var(--sp-4); min-height: 0; }
.media-viewer .media-viewer-figure {
  max-width: min(1100px, 100%); max-height: 100%; overflow: auto;
  display: flex; aspect-ratio: 4 / 3; width: 100%;
  background: var(--color-surface); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
}
.media-viewer .media-viewer-figure video { flex: none; margin: auto; width: 100%; height: 100%; object-fit: contain; }
.media-viewer .media-viewer-nav {
  appearance: none; width: 44px; height: 44px; flex: none; display: grid; place-items: center; cursor: pointer;
  border: var(--border-w) solid var(--color-border); border-radius: var(--radius-full);
  background: var(--color-surface); color: var(--color-text);
}
.media-viewer .media-viewer-nav:hover:not([aria-disabled="true"]) { background: var(--color-surface-hover); }
.media-viewer .media-viewer-nav:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--color-focus-ring); }
.media-viewer .media-viewer-nav svg { width: 20px; height: 20px; }
.media-viewer .media-viewer-close {
  appearance: none; display: inline-flex; align-items: center; gap: var(--sp-2); cursor: pointer;
  height: var(--control-h-sm); padding: 0 var(--sp-3); font-family: inherit; font-size: var(--fs-sm);
  background: var(--color-surface); color: var(--color-text);
  border: var(--border-w) solid var(--color-border); border-radius: var(--radius-md);
}
.media-viewer .media-viewer-close:hover { background: var(--color-surface-hover); }
.media-viewer .media-viewer-close svg { width: 16px; height: 16px; }

.media-viewer .media-viewer-figure:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--color-focus-ring); }
.media-viewer .media-viewer-pan {
  position: relative; flex: none; margin: auto; container-type: size;
  width: calc(100% * var(--media-zoom, 1)); height: calc(100% * var(--media-zoom, 1));
}
.media-viewer .media-viewer-pan img {
  position: absolute; top: 50%; left: 50%; object-fit: contain;
  width: 100%; height: 100%;
  transform: translate(-50%, -50%) rotate(var(--media-rotate, 0deg));
}
.media-viewer .media-viewer-pan img.is-sideways { width: 100cqh; height: 100cqw; }
.media-viewer .media-viewer-tools {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--sp-2);
}
.media-viewer .media-viewer-tool {
  appearance: none; display: inline-flex; align-items: center; gap: var(--sp-2); cursor: pointer;
  height: var(--control-h-sm); padding: 0 var(--sp-3); font-family: inherit; font-size: var(--fs-sm);
  background: var(--color-surface); color: var(--color-text);
  border: var(--border-w) solid var(--color-border); border-radius: var(--radius-md);
}
.media-viewer .media-viewer-tool:hover:not([aria-disabled="true"]) { background: var(--color-surface-hover); }
.media-viewer .media-viewer-tool:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--color-focus-ring); }
.media-viewer .media-viewer-tool[aria-disabled="true"],
.media-viewer .media-viewer-nav[aria-disabled="true"] { cursor: not-allowed; opacity: 0.5; }
.media-viewer .media-viewer-tool svg { width: 16px; height: 16px; }
.media-viewer .media-viewer-zoom-value {
  min-width: 4ch; text-align: center; color: var(--neutral-0); font-size: var(--fs-sm); font-variant-numeric: tabular-nums;
}

@media (max-width: 640px) {
  .media-viewer { padding: var(--sp-3); }
  .media-viewer .media-viewer-stage { flex-direction: column; }
}
@media (prefers-reduced-motion: reduce) {
  .media-card, .media-card .media-play, .media-card .media-action { transition-duration: 0s; }
  .media-card:hover { transform: none; }
  .media-card:hover .media-play { transform: none; }
  .media-card .media-skeleton::after { animation: none; }
}
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — BARRA DE PROGRESSO
   Progresso linear para acoes com duracao mensuravel (upload, importacao,
   compactacao, exportacao) e para indicar carga sem % confiavel.

     .progress             -> bloco (cabecalho opcional + trilha)
     .progress-header      -> linha rotulo + valor (opcional)
     .progress-label       -> descricao da tarefa
     .progress-value       -> percentual/contagem (tabular-nums)
     .progress-track       -> trilha
     .progress-bar         -> preenchimento; largura via --progress (0..100%)

   Tamanhos:   .progress-sm | (base) | .progress-lg
   Sinais:     .progress-success | -warning | -danger | -accent  (padrao: primario)
   Estados:    .is-indeterminate (carga sem %) | .is-paused (mantem largura, sem transicao)

   O percentual e valor de runtime: no Blazor, --progress e aria-valuenow sao
   binding; aqui o card ajusta via data-value (nunca style= inline no markup).
   Token-only, dark-ready, com fallback de movimento reduzido.
   ========================================================================= */
.progress { display: flex; flex-direction: column; gap: var(--sp-2); width: 100%; }

.progress-header {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3);
  font-size: var(--fs-sm); line-height: var(--lh-tight);
}
.progress-label { color: var(--color-text); font-weight: var(--fw-medium); }
.progress-value { color: var(--color-text-muted); font-variant-numeric: tabular-nums; flex: none; }

.progress-track {
  position: relative; width: 100%; height: 8px; overflow: hidden;
  border-radius: var(--radius-full); background: var(--color-surface-hover);
}
.progress-bar {
  display: block; height: 100%; width: var(--progress, 0%); border-radius: inherit;
  background: var(--color-primary); transition: width var(--dur-slow) var(--ease);
}

/* Tamanhos */
.progress-sm .progress-track { height: 4px; }
.progress-lg .progress-track { height: 12px; }

/* Sinais */
.progress-success .progress-bar { background: var(--color-success); }
.progress-warning .progress-bar { background: var(--color-warning); }
.progress-danger  .progress-bar { background: var(--color-danger); }
.progress-accent  .progress-bar { background: var(--color-accent); }

/* Indeterminado — carga sem % confiavel: segmento desliza pela trilha */
.progress.is-indeterminate .progress-bar {
  width: 40%; animation: progress-slide 1.15s var(--ease) infinite;
}
/* Pausado — congela a largura atual (sem animar a mudanca) */
.progress.is-paused .progress-bar { transition: none; }

/* Empilhado — varios segmentos numa trilha (composicao de status) */
.progress-stacked .progress-track { display: flex; }
.progress-stacked .progress-bar { width: var(--progress, 0%); border-radius: 0; transition: width var(--dur-slow) var(--ease); }
.progress-stacked .progress-bar:first-child { border-top-left-radius: inherit; border-bottom-left-radius: inherit; }
.progress-stacked .progress-bar:last-child  { border-top-right-radius: inherit; border-bottom-right-radius: inherit; }
.progress-bar-success { background: var(--color-success); }
.progress-bar-warning { background: var(--color-warning); }
.progress-bar-danger  { background: var(--color-danger); }

@keyframes progress-slide { 0% { transform: translateX(-110%); } 100% { transform: translateX(360%); } }

/* Movimento reduzido: sem deslizar — carga sinalizada por opacidade */
@media (prefers-reduced-motion: reduce) {
  .progress.is-indeterminate .progress-bar { width: 100%; animation: progress-fade 1.2s ease-in-out infinite; }
}
@keyframes progress-fade { 50% { opacity: 0.4; } }
/* =========================================================================
   IBRASCAN DESIGN SYSTEM — NOTICE LIST (informativos do sistema)
   Lista de comunicados publicados pelo sistema, lida dentro de um .card:
   sinal + titulo + uma linha de texto + quando. Nao e timeline (historico de
   um registro) nem alerta de tela (.alert, evento do que o usuario acabou de
   fazer) nem faixa global (.alert-banner, servico agora).
   Item nao lido chama atencao por .is-unread; nada pisca nem fecha.
   ========================================================================= */
.notice-list {
    display: flex;
    flex-direction: column;
    list-style: none;
    margin: 0;
    padding: 0;
}

.notice-item {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    padding: var(--sp-4) var(--sp-5);
    border-top: var(--border-w) solid var(--color-border);
}

.notice-list > .notice-item:first-child {
    border-top: 0;
}

.notice-list > .notice-item:last-child {
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

/* Sinal do informativo — quadrado suave, cor so por token */
.notice-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 34px;
    height: 34px;
    border-radius: var(--radius-md);
    background: var(--color-surface-2);
    color: var(--color-text-muted);
}

    .notice-icon svg {
        width: 18px;
        height: 18px;
    }

.notice-icon-info {
    background: var(--color-info-soft);
    color: var(--color-info);
}

.notice-icon-warning {
    background: var(--color-warning-soft);
    color: var(--color-warning);
}

.notice-icon-danger {
    background: var(--color-danger-soft);
    color: var(--color-danger);
}

.notice-icon-success {
    background: var(--color-success-soft);
    color: var(--color-success);
}

.notice-body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1 1 auto;
}

.notice-title {
    margin: 0;
    font-size: var(--fs-base);
    font-weight: var(--fw-semibold);
    line-height: var(--lh-tight);
    color: var(--color-text);
}

.notice-text {
    margin: 0;
    font-size: var(--fs-sm);
    color: var(--color-text-muted);
    text-wrap: pretty;
}

.notice-time {
    flex: none;
    font-size: var(--fs-xs);
    color: var(--color-text-subtle);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* Escopo do informativo (unidade, regiao ou estado a que se aplica) — so em listas que
   reunem publicacoes de mais de um escopo (ex.: historico filtravel). Uma
   lista de escopo unico nao usa esta linha. */
.notice-scope {
    font-size: var(--fs-xs);
    color: var(--color-text-subtle);
}

/* Nao lido: marca no titulo e fundo levemente destacado — o que chama a
   atencao do usuario ao abrir a tela. Lido nao muda de estrutura. */
.notice-item.is-unread {
    background: var(--color-primary-soft);
}

    .notice-item.is-unread .notice-title::after {
        content: "";
        display: inline-block;
        vertical-align: middle;
        width: 7px;
        height: 7px;
        margin-left: var(--sp-2);
        border-radius: var(--radius-full);
        background: var(--color-primary);
    }

/* Item que abre o informativo completo: o <li> continua sendo o item da lista
   e o <a> ocupa a linha inteira dentro dele, com o mesmo espacamento. */
.notice-item.has-link {
    padding: 0;
}

    .notice-item.has-link:hover {
        background: var(--color-surface-hover);
    }

.notice-link {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    flex: 1 1 auto;
    min-width: 0;
    padding: var(--sp-4) var(--sp-5);
    text-decoration: none;
    color: inherit;
}

    .notice-link:focus-visible {
        outline: 2px solid var(--color-primary);
        outline-offset: -2px;
    }

@media (max-width: 640px) {
    .notice-item,
    .notice-link {
        flex-wrap: wrap;
        padding: var(--sp-4);
    }

    .notice-item.has-link {
        padding: 0;
    }

    .notice-time {
        width: 100%;
        padding-left: calc(34px + var(--sp-3));
    }
}
