/* =============================================================================
   COMPONENTES — camada de componentes do design system
   Projeto: renovacao-certificado-campinas (gêmeo GENESIS) · fase de linguagem visual
   Origem: design/01-institucional-denso.html (direção escolhida pelo dono em 03/08/2026)

   TESE DA DIREÇÃO 01 — terminal de operação.
     · alta densidade: a operadora passa o dia aqui, densidade é respeito ao tempo dela;
     · hierarquia por TIPOGRAFIA E PESO, não por cor e caixa;
     · cromia contida: o cinza domina, a cor só aparece onde carrega significado;
     · régua de 1px no lugar de sombra;
     · número tabular em coluna, serifada no cabeçalho, mono nos identificadores.
   Nada aqui foi inventado: todo valor foi extraído da maquete 01.

   DEPENDE DE tokens.css (agente irmão). Este arquivo NÃO define cor nenhuma:
   se o valor é cor, vem de token. Duplicar a paleta aqui criaria a segunda fonte
   de verdade que esta fase existe para impedir. A lista fechada de tokens
   consumidos está em "CONTRATO DE TOKENS" logo abaixo — exemplos.html confere
   essa lista em tempo de carga e denuncia o que faltar.

   ORDEM DE CARGA (obrigatória):
     <link rel="stylesheet" href="tokens.css">
     <link rel="stylesheet" href="componentes.css">

   NOMENCLATURA: toda classe deste arquivo começa com `ds-`. Sem seletor de
   elemento solto (exceto dentro de .ds-table), sem !important, sem id.
   O prefixo é o que permite um gate perguntar "essa classe é do sistema ou é
   CSS de ocasião?" — e é o que impede colisão com o CSS do legado no cutover.

   MAPA maquete 01 → sistema (para o porte da F3 ser mecânico):
     .panel      → .ds-panel        .kpi     → .ds-kpi        .btn    → .ds-btn
     .cyclebar   → .ds-cyclebar     .cyc     → .ds-cyc        .chip   → .ds-badge
     .notice     → .ds-notice       .meter   → .ds-meter      .wbar   → .ds-wbar
     .filterbar  → .ds-filterbar    .legend  → .ds-legend     table   → .ds-table
     .num/.mono/.eyebrow/.dim       → .ds-num/.ds-mono/.ds-eyebrow/.ds-dim

   SUMÁRIO
     00 · Contrato de tokens          08 · Medidores (meta, janela, progresso)
     01 · Escala local (medida/tipo)  09 · Badge de estado
     02 · Base e utilitários          10 · Legenda
     03 · Foco e alvo de clique       11 · Campo de formulário e select
     04 · Painel / cartão             12 · Notice (alerta / faixa de aviso)
     05 · Tabela densa                13 · Alternadores sol/lua e textura
     06 · Abas de ciclo (12 + Todos)  14 · Filtros
     07 · Indicadores (KPI)           15 · Contraste forçado · impressão · movimento
   ============================================================================= */


/* =============================================================================
   00 · CONTRATO DE TOKENS — o que este arquivo exige de tokens.css
   Se um destes sumir, componente quebra. exemplos.html mostra faixa vermelha
   listando os ausentes; não há fallback silencioso, de propósito.

     tipografia   --font-ui  --font-serif  --font-mono
     superfícies  --plane  --surface  --surface-alt  --surface-sunk
     tinta        --ink  --ink-2  --ink-3
     réguas       --rule  --rule-strong  --grid
     séries       --s-renovado  --s-pendente  --s-aberto  --s-ramp-100
     status       --st-good  --st-good-tx  --st-warn  --st-serious
                  --st-crit  --st-crit-tx
     foco         --focus

   REGRA DE PALETA: os valores acima foram validados contra daltonismo e
   contraste (skill dataviz) nos dois modos. Alterar um valor de cor sem
   revalidar é violação. Este arquivo nunca faz color-mix() com hue novo —
   só mistura com --ink/--surface (neutros), o que preserva a validação.
   ============================================================================= */


/* =============================================================================
   01 · ESCALA LOCAL — medida, tipo, raio
   Extraída da maquete 01, não inventada. Declarada em :where(:root) para ter
   especificidade ZERO: se tokens.css definir estes mesmos nomes, tokens.css vence.
   ============================================================================= */
:where(:root){
  /* espaço — a densidade da direção 01 vive nesta escala curta */
  --ds-sp-1: 2px;
  --ds-sp-2: 3px;
  --ds-sp-3: 4px;
  --ds-sp-4: 5px;
  --ds-sp-5: 6px;
  --ds-sp-6: 8px;
  --ds-sp-7: 10px;
  --ds-sp-8: 12px;
  --ds-sp-9: 16px;

  /* tipo — a maquete usa meio-pixel de propósito; é o que dá a densidade */
  --ds-text-micro:   9.5px;   /* tick de eixo, th */
  --ds-text-eyebrow: 10px;    /* rótulo caixa-alta */
  --ds-text-note:    10.5px;  /* nota de rodapé de painel */
  --ds-text-ctl:     11px;    /* controle: botão, select, aba */
  --ds-text-body:    11.5px;  /* corpo de tabela */
  --ds-text-base:    12px;    /* corpo da página */
  --ds-text-lede:    12.5px;  /* linha-fina serifada */
  --ds-text-h2:      13.5px;  /* título de painel (serifada) */
  --ds-text-h1:      15px;    /* wordmark (serifada) */
  --ds-text-kpi:     20px;    /* indicador */
  --ds-text-hero:    44px;    /* indicador herói */

  --ds-lh:       1.35;
  --ds-lh-ctl:   1.5;
  --ds-track:    .07em;       /* letter-spacing de caixa-alta */
  --ds-track-lg: .09em;

  --ds-radius:    2px;        /* controles */
  --ds-radius-sm: 1px;        /* marcadores, trilhos */
  --ds-rule:      1px;        /* NUNCA sombra: a régua de 1px é a estrutura */

  /* alvo de clique — ver seção 03 */
  --ds-hit: 24px;

  /* deslocamento do topo para cabeçalho fixo de tabela; a F3 ajusta para a
     altura do masthead quando a tabela rolar junto com a página */
  --ds-sticky-top: 0px;
  /* altura máxima da região rolável de tabela; `none` = rola com a página */
  --ds-table-h: none;
}


/* =============================================================================
   02 · BASE E UTILITÁRIOS
   .ds-root vai no <body> (ou no contêiner do app). Não estilizamos <body> direto:
   este CSS ainda pode conviver com o legado durante o cutover.
   ============================================================================= */
.ds-root{
  background: var(--plane);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: var(--ds-text-base);
  line-height: var(--ds-lh);
  -webkit-font-smoothing: antialiased;
}

/* número: SEMPRE tabular. Coluna de número que dança é erro de leitura. */
.ds-num{ font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }

/* mono: identificador (protocolo, documento mascarado, hash) — nunca prosa */
.ds-mono{
  font-family: var(--font-mono);
  font-size: var(--ds-text-ctl);
  letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
}

/* rótulo caixa-alta acima de um valor */
.ds-eyebrow{
  font-size: var(--ds-text-eyebrow);
  letter-spacing: var(--ds-track-lg);
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 600;
}

/* serifada: reservada a título e linha-fina. É carater da direção, não enfeite. */
.ds-serif{ font-family: var(--font-serif); }

.ds-dim{ color: var(--ink-2); }
.ds-dimmer{ color: var(--ink-3); }

/* só para leitor de tela */
.ds-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;
}

/* valor que NÃO EXISTE — não é zero, é ausência. O antídoto da mentira gráfica:
   use em "sem base" no lugar de renderizar 0 / 0%. */
.ds-indisponivel{
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  font-style: normal;
}
.ds-indisponivel::before{ content: "—"; }

/* delta (variação) — cor + sinal textual, nunca cor sozinha */
.ds-delta{
  display: inline-flex; align-items: center; gap: var(--ds-sp-2);
  font-variant-numeric: tabular-nums;
}
.ds-delta--bom{ color: var(--st-good-tx); }
.ds-delta--ruim{ color: var(--st-crit-tx); }
.ds-delta--bom::before{ content: "▲"; font-size: .8em; }
.ds-delta--ruim::before{ content: "▼"; font-size: .8em; }


/* =============================================================================
   03 · FOCO E ALVO DE CLIQUE  (R-SEC-11)
   Foco visível em TUDO que recebe teclado. Regra única, aplicada na raiz do
   sistema, para não depender de alguém lembrar componente a componente.

   ALVO: a maquete usa controle de ~21px de altura. O dono decidiu que a tela é
   visível para TODO o time — mais gente, mais dispositivo. Subimos o mínimo para
   24px (WCAG 2.2 · Target Size Minimum) e 32px em ponteiro grosso. É o ÚNICO
   desvio deliberado de valor da maquete neste arquivo, e custa 3px de altura.
   ============================================================================= */
.ds-root :focus-visible,
.ds-root:focus-visible{
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}
/* o alvo pintado de tinta precisa do respiro invertido para o foco não sumir */
.ds-btn[aria-pressed="true"]:focus-visible,
.ds-cyc[aria-pressed="true"]:focus-visible,
.ds-btn--primario:focus-visible{ outline-offset: 2px; }

.ds-btn, .ds-cyc, .ds-input, .ds-select, .ds-toggle{ min-height: var(--ds-hit); }
@media (pointer: coarse){
  :where(:root){ --ds-hit: 32px; }
}


/* =============================================================================
   04 · PAINEL / CARTÃO — régua de 1px, NUNCA sombra
   Estrutura: <section class="ds-panel">
                <header class="ds-panel__head"> <h2> <span class=ds-panel__sub>
                                                <span class=ds-panel__tools>
                <div class="ds-panel__body">
                <p class="ds-panel__note">
   ============================================================================= */
.ds-panel{
  background: var(--surface);
  border: var(--ds-rule) solid var(--rule);
  min-width: 0;                     /* sobrevive dentro de grid: sem estouro lateral */
}
.ds-panel__head{
  display: flex; align-items: baseline; gap: var(--ds-sp-7); flex-wrap: wrap;
  padding: var(--ds-sp-5) var(--ds-sp-7) var(--ds-sp-4);
  border-bottom: var(--ds-rule) solid var(--rule);
}
.ds-panel__head h2,
.ds-panel__title{
  font-family: var(--font-serif);
  font-size: var(--ds-text-h2);
  font-weight: 600;
  letter-spacing: .01em;
}
.ds-panel__sub{ font-size: var(--ds-text-note); color: var(--ink-3); min-width: 0; }
.ds-panel__tools{
  margin-left: auto; display: flex; gap: var(--ds-sp-5); align-items: center;
}
.ds-panel__body{ padding: var(--ds-sp-6) var(--ds-sp-7) var(--ds-sp-7); }
.ds-panel__note{
  font-size: var(--ds-text-note); color: var(--ink-3);
  padding: 0 var(--ds-sp-7) var(--ds-sp-6);
}
.ds-panel__note b{ color: var(--ink-2); font-weight: 600; }

/* grade padrão de painéis: 1 coluna até 1180px, 1.62fr/1fr acima */
.ds-grid{ display: grid; grid-template-columns: 1fr; gap: var(--ds-sp-7); }
@media (min-width: 1180px){
  .ds-grid{ grid-template-columns: minmax(0, 1.62fr) minmax(0, 1fr); }
}
.ds-stack{
  display: flex; flex-direction: column; gap: var(--ds-sp-7); min-width: 0;
}


/* =============================================================================
   05 · TABELA DENSA — número tabular, cabeçalho fixo
   <div class="ds-tablewrap" tabindex="0" role="region" aria-label="…">
     <table class="ds-table"> … </table>
   </div>
   `tabindex="0"` não é enfeite: região que rola precisa ser alcançável pelo teclado.

   border-collapse: separate + border-spacing 0 é PROPOSITAL — com `collapse`
   a borda do <th> grudado (sticky) some no Chrome/Safari. A aparência é idêntica.
   ============================================================================= */
.ds-tablewrap{
  overflow: auto;
  max-height: var(--ds-table-h);
  overscroll-behavior: contain;
}
.ds-tablewrap:focus-visible{ outline: 2px solid var(--focus); outline-offset: -2px; }

.ds-table{
  border-collapse: separate; border-spacing: 0;
  width: 100%;
  font-size: var(--ds-text-body);
}
.ds-table caption{
  text-align: left;
  font-size: var(--ds-text-eyebrow);
  letter-spacing: var(--ds-track);
  text-transform: uppercase;
  color: var(--ink-3);
  padding: var(--ds-sp-5) var(--ds-sp-7) var(--ds-sp-3);
}
.ds-table th,
.ds-table td{
  padding: var(--ds-sp-2) var(--ds-sp-6);
  text-align: left;
  border-bottom: var(--ds-rule) solid var(--grid);
  white-space: nowrap;
}
.ds-table thead th{
  position: sticky; top: var(--ds-sticky-top); z-index: 2;
  background: var(--surface-alt);
  font-size: var(--ds-text-micro);
  letter-spacing: var(--ds-track);
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 600;
  border-bottom: 0;
  /* a régua do cabeçalho vai de box-shadow para não descolar ao grudar */
  box-shadow: inset 0 -1px 0 var(--rule-strong);
}
.ds-table tbody tr:hover > *{ background: var(--surface-alt); }
.ds-table tbody tr:last-child > *{ border-bottom: 0; }

/* coluna numérica: direita + tabular. Toda coluna de número usa .ds-n. */
.ds-table .ds-n{ text-align: right; font-variant-numeric: tabular-nums; }

/* totais grudados no rodapé da região rolável */
.ds-table tfoot td,
.ds-table tfoot th{
  position: sticky; bottom: 0; z-index: 2;
  background: var(--surface-alt);
  font-weight: 600;
  border-bottom: 0;
  box-shadow: inset 0 1px 0 var(--rule-strong);
}

/* linha selecionada — marca de tinta à esquerda, não só fundo */
.ds-table tbody tr[aria-selected="true"] > *{ background: var(--surface-alt); }
.ds-table tbody tr[aria-selected="true"] > :first-child{
  box-shadow: inset 2px 0 0 var(--ink);
}
.ds-table--clicavel tbody tr{ cursor: pointer; }

/* tabela embutida que abre/fecha sob um painel */
.ds-tablewrap--inline{ border-top: var(--ds-rule) solid var(--rule); }
.ds-tablewrap[hidden]{ display: none; }


/* =============================================================================
   06 · ABAS DE CICLO — as 12 do exercício + "Todos"
   <nav class="ds-cyclebar" aria-label="Ciclo em foco">
     <span class="ds-cyclebar__lab">Ciclo</span>
     <button class="ds-cyc" aria-pressed="false">
       <i class="ds-state ds-state--fechada" aria-hidden="true"></i>Jan
     </button> …
   O estado do mês entra como MARCA DE FORMA (ver seção 09) e como texto no
   aria-label. Nunca só como cor.
   ============================================================================= */
.ds-cyclebar{
  background: var(--surface);
  border: var(--ds-rule) solid var(--rule);
  display: flex; gap: var(--ds-sp-3); align-items: center; flex-wrap: wrap;
  padding: var(--ds-sp-4) var(--ds-sp-6);
}
.ds-cyclebar__lab{
  font-size: var(--ds-text-eyebrow);
  letter-spacing: var(--ds-track);
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 600;
  margin-right: var(--ds-sp-1);
}
.ds-cyclebar__legend{
  margin-left: auto;
  font-size: var(--ds-text-eyebrow);
  color: var(--ink-3);
  display: flex; gap: var(--ds-sp-7); flex-wrap: wrap;
}
.ds-cyclebar__legend span{ display: inline-flex; align-items: center; gap: var(--ds-sp-3); }

.ds-cyc{
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--ds-sp-4);
  background: var(--surface);
  color: var(--ink);
  border: var(--ds-rule) solid var(--rule-strong);
  border-radius: var(--ds-radius);
  padding: var(--ds-sp-1) var(--ds-sp-5);
  font: inherit;
  font-size: var(--ds-text-ctl);
  line-height: var(--ds-lh-ctl);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
.ds-cyc:hover{ background: var(--surface-alt); }
.ds-cyc[aria-pressed="true"]{
  background: var(--ink); color: var(--surface); border-color: var(--ink);
}
/* a marca vazada precisa inverter junto com o botão selecionado */
.ds-cyc[aria-pressed="true"] .ds-state--sem-base{ border-color: var(--surface); }
.ds-cyc[disabled],
.ds-cyc[aria-disabled="true"]{
  color: var(--ink-3); border-color: var(--rule); cursor: not-allowed;
  background: var(--surface-alt);
}


/* =============================================================================
   07 · INDICADORES (KPI) — o número grande com rótulo
   <section class="ds-kpis">
     <div class="ds-kpi ds-kpi--heroi"> <div class=ds-kpi__lab> <div class=ds-kpi__val>
                                        <div class=ds-kpi__foot>
   Separador é régua de 1px entre células, não caixa por célula.
   ============================================================================= */
.ds-kpis{
  background: var(--surface);
  border: var(--ds-rule) solid var(--rule);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
}
.ds-kpi{
  padding: var(--ds-sp-6) var(--ds-sp-8) 9px;
  border-left: var(--ds-rule) solid var(--rule);
  min-width: 0;
}
.ds-kpi:first-child{ border-left: 0; }
.ds-kpi__lab{
  font-size: var(--ds-text-eyebrow);
  letter-spacing: var(--ds-track);
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 600;
}
.ds-kpi__val{
  font-size: var(--ds-text-kpi);
  font-weight: 600;
  letter-spacing: -.015em;
  line-height: 1.15;
  margin-top: var(--ds-sp-1);
  font-variant-numeric: tabular-nums;
}
.ds-kpi__foot{
  font-size: var(--ds-text-note); color: var(--ink-2); margin-top: var(--ds-sp-1);
}
.ds-kpi--heroi{
  grid-column: span 2;
  background: var(--surface-alt);
  border-left: 0;
  border-right: var(--ds-rule) solid var(--rule);
}
.ds-kpi--heroi .ds-kpi__val{
  font-size: var(--ds-text-hero);
  letter-spacing: -.03em;
  line-height: 1;
}
@media (max-width: 520px){
  .ds-kpi--heroi{ grid-column: span 1; }
  .ds-kpi--heroi .ds-kpi__val{ font-size: 36px; }
}
/* indicador de ciclo que não apura: o valor não é 0, é ausência (ver .ds-indisponivel) */
.ds-kpi--sem-apuracao .ds-kpi__val{ color: var(--ink-3); }


/* =============================================================================
   08 · MEDIDORES — três coisas diferentes, três formas diferentes
     .ds-meter    taxa de renovação contra a meta (DADO — usa cor de série)
     .ds-wbar     quanto da janela já passou (TEMPO — cinza, nunca cor de série)
     .ds-progress progresso de tarefa: upload/importação (TEMPO — com rótulo %)

   Confundir os três é como a maquete mente: pintar "17 dias decorridos" com a
   mesma cor de "6,5% renovado" faz o leitor somar coisas que não se somam.
   ============================================================================= */

/* --- taxa contra meta ------------------------------------------------------ */
.ds-meter{
  position: relative;
  width: 64px; height: 7px;
  background: var(--s-ramp-100);            /* trilho = passo claro do mesmo azul */
  border-radius: var(--ds-radius-sm);
  display: inline-block; vertical-align: middle;
}
.ds-meter__fill{
  position: absolute; inset: 0 auto 0 0;
  background: var(--s-renovado);
  border-radius: 0 var(--ds-radius) var(--ds-radius) 0;
  display: block;
}
/* PARCIAL: janela ainda aberta, o número só sobe. Hachura = "não é o final". */
.ds-meter__fill--parcial{
  background-image: repeating-linear-gradient(45deg,
    var(--surface) 0 1.2px, transparent 1.2px 3.6px);
}
/* marca de referência (média dos ciclos fechados / meta) */
.ds-meter__mark{
  position: absolute; top: -2px; bottom: -2px; width: 1px;
  background: var(--ink-3);
}
/* NÃO ABRIU: trilho neutro e vazio — 0% aqui é "não começou", não "fracassou" */
.ds-meter--nao-abriu{ background: var(--surface-sunk); }
/* SEM BASE: não existe medidor. Contorno tracejado, nada dentro.
   Se a F3 renderizar barra cheia de 0% aqui, é mentira gráfica. */
.ds-meter--sem-base{
  background: transparent;
  border: 1px dashed var(--rule-strong);
  height: 9px;
}
.ds-meter--sem-base .ds-meter__fill{ display: none; }

/* --- janela decorrida (tempo) ---------------------------------------------- */
.ds-wbar{
  position: relative; display: block;
  width: 100%; max-width: 120px; height: 5px;
  background: var(--surface-sunk);
  border-radius: var(--ds-radius-sm);
  overflow: hidden;
  margin-top: var(--ds-sp-4);
}
.ds-wbar__fill{
  position: absolute; inset: 0 auto 0 0;
  background: var(--ink-3);                 /* cinza: tempo NUNCA é série de dados */
  display: block;
}
.ds-wbar--tabela{
  width: 58px; margin-top: 0; display: inline-block; vertical-align: middle;
}
.ds-wbar__txt{
  font-size: var(--ds-text-eyebrow);
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  margin-left: var(--ds-sp-5);
  white-space: nowrap;
}

/* --- progresso de tarefa (importação) -------------------------------------- */
.ds-progress{
  display: flex; align-items: center; gap: var(--ds-sp-6);
  font-size: var(--ds-text-ctl);
}
.ds-progress__track{
  position: relative; flex: 1 1 auto; min-width: 0;
  height: 6px;
  background: var(--surface-sunk);
  border-radius: var(--ds-radius-sm);
  overflow: hidden;
}
.ds-progress__fill{
  position: absolute; inset: 0 auto 0 0;
  background: var(--s-renovado);
  display: block;
  transition: width .18s linear;
}
/* o valor em texto é OBRIGATÓRIO: barra sem número não informa nada a quem
   usa leitor de tela nem a quem não distingue o preenchimento */
.ds-progress__val{
  font-variant-numeric: tabular-nums; color: var(--ink-2); white-space: nowrap;
}
.ds-progress--indeterminado .ds-progress__fill{
  width: 34%;
  animation: ds-indeterminado 1.1s ease-in-out infinite;
}
@keyframes ds-indeterminado{
  0%{ transform: translateX(-100%); }
  100%{ transform: translateX(320%); }
}
.ds-progress--erro .ds-progress__fill{ background: var(--st-crit); }
.ds-progress--concluido .ds-progress__fill{ background: var(--st-good); }


/* =============================================================================
   09 · BADGE DE ESTADO — cor + FORMA + texto, sempre os três  (R-SEC-11)
   <span class="ds-badge">
     <i class="ds-state ds-state--em-curso" aria-hidden="true"></i>Em curso · parcial
   </span>

   .ds-state é a marca de forma, reutilizada em legenda, aba de ciclo e tabela.
   As formas são distinguíveis SEM cor:
     renovado / fechada  quadrado cheio
     pendente            quadrado cheio (outra série)
     em curso            quadrado HACHURADO 45°  — "parcial, ainda sobe"
     não abriu           quadrado cheio neutro
     sem base            quadrado VAZADO tracejado — "não existe número"

   Os QUATRO estados de mês existem porque pintá-los igual é o pior defeito
   possível nesta tela. Agosto a 6,5% não é o pior mês do ano: é uma janela de
   17 dias. A classe carrega o estado; o texto ao lado o explica; nunca omita o texto.
   ============================================================================= */
.ds-badge{
  display: inline-flex; align-items: center; gap: var(--ds-sp-4);
  font-size: var(--ds-text-ctl);
  white-space: nowrap;
}
.ds-state{
  width: 8px; height: 8px; border-radius: var(--ds-radius-sm);
  flex: none; display: block;
  border: 1px solid transparent;   /* reserva a caixa: vazado e cheio alinham igual */
}
.ds-state--renovado,
.ds-state--fechada{ background: var(--s-renovado); }
.ds-state--pendente{ background: var(--s-pendente); }
.ds-state--em-curso{
  background: var(--s-pendente);
  background-image: repeating-linear-gradient(45deg,
    var(--surface) 0 1.2px, transparent 1.2px 3.4px);
}
.ds-state--nao-abriu{ background: var(--s-aberto); }
.ds-state--sem-base{ background: transparent; border: 1px dashed var(--rule-strong); }

/* marca menor, para dentro de aba/legenda */
.ds-state--mini{ width: 7px; height: 7px; }

/* sinalizadores de texto — cor acompanha PESO e ícone, nunca vai sozinha */
.ds-flag{
  color: var(--st-crit-tx); font-weight: 600;
  display: inline-flex; align-items: center; gap: var(--ds-sp-2);
}
.ds-ok{ color: var(--st-good-tx); font-weight: 600; }
.ds-flag svg, .ds-ok svg{ flex: none; }

/* canal de textura (opt-in / impressão / daltonismo): 45° para renovado,
   135° para pendente. Ativa em <html data-texture="on">. */
[data-texture="on"] .ds-state--renovado,
[data-texture="on"] .ds-state--fechada,
[data-texture="on"] .ds-swatch[data-tex="a"]{
  background-image: repeating-linear-gradient(45deg,
    var(--surface) 0 1.5px, transparent 1.5px 4px);
}
[data-texture="on"] .ds-state--pendente,
[data-texture="on"] .ds-swatch[data-tex="b"]{
  background-image: repeating-linear-gradient(135deg,
    var(--surface) 0 1.5px, transparent 1.5px 4px);
}


/* =============================================================================
   10 · LEGENDA
   ============================================================================= */
.ds-legend{ display: flex; gap: var(--ds-sp-8); flex-wrap: wrap; align-items: center; }
.ds-legend__item{
  display: inline-flex; align-items: center; gap: var(--ds-sp-4);
  font-size: var(--ds-text-note); color: var(--ink-2);
}
.ds-swatch{ width: 9px; height: 9px; flex: none; border-radius: var(--ds-radius-sm); }
.ds-swatch--linha{ width: 12px; height: 2px; border-radius: 0; }
.ds-swatch--tracejado{ background: transparent; border: 1px dashed var(--rule-strong); }


/* =============================================================================
   11 · BOTÃO
     .ds-btn                secundário — o padrão da direção 01
     .ds-btn--primario      tinta cheia: a ação principal do formulário
     .ds-btn--miudo         controle de painel (caixa-alta, 10px)
     .ds-btn--exportar      secundário com ícone; ver aviso abaixo
   ============================================================================= */
.ds-btn{
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--ds-sp-4);
  background: var(--surface);
  color: var(--ink);
  border: var(--ds-rule) solid var(--rule-strong);
  border-radius: var(--ds-radius);
  padding: var(--ds-sp-1) var(--ds-sp-6);
  font: inherit;
  font-size: var(--ds-text-ctl);
  line-height: var(--ds-lh-ctl);
  cursor: pointer;
  text-decoration: none;      /* serve também para <a class="ds-btn"> */
  white-space: nowrap;
}
.ds-btn:hover{ background: var(--surface-alt); }
.ds-btn:active{ background: var(--surface-sunk); }
.ds-btn[aria-pressed="true"]{
  background: var(--ink); color: var(--surface); border-color: var(--ink);
}

.ds-btn--primario{
  background: var(--ink); color: var(--surface); border-color: var(--ink);
  font-weight: 600;
  padding-inline: var(--ds-sp-8);
}
.ds-btn--primario:hover{ background: var(--ink-2); border-color: var(--ink-2); }
.ds-btn--primario:active{ background: var(--ink); }

.ds-btn--miudo{
  padding: 1px var(--ds-sp-5);
  font-size: var(--ds-text-eyebrow);
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.ds-btn--miudo[aria-pressed="true"]{ color: var(--surface); }

.ds-btn--bloco{ width: 100%; }

/* DESABILITADO — vale para [disabled] e para [aria-disabled="true"].
   Prefira aria-disabled quando quiser que o motivo continue alcançável pelo
   teclado (o botão recebe foco e o title/descrição é lido).

   ARMADILHA DESTE PROJETO: já houve maquete que mostrava 0% e habilitava
   "exportar 1.335 clientes" que sequer haviam vencido. Em ciclo `nao-abriu` ou
   `sem-base` o exportar fica desabilitado E diz por quê (use .ds-btn__motivo). */
.ds-btn[disabled],
.ds-btn[aria-disabled="true"]{
  color: var(--ink-3);
  background: var(--surface-alt);
  border-color: var(--rule);
  cursor: not-allowed;
}
.ds-btn--primario[disabled],
.ds-btn--primario[aria-disabled="true"]{
  background: var(--surface-sunk); color: var(--ink-3); border-color: var(--rule-strong);
}
.ds-btn[disabled]:hover,
.ds-btn[aria-disabled="true"]:hover{ background: var(--surface-alt); }

.ds-btn__motivo{
  font-size: var(--ds-text-eyebrow);
  color: var(--ink-3);
  margin-left: var(--ds-sp-5);
}

/* ocupado: o texto muda junto (aria-busy), não só o cursor */
.ds-btn[aria-busy="true"]{ cursor: progress; color: var(--ink-3); }

.ds-btn svg{ flex: none; }
/* grupo de botões colado, régua compartilhada */
.ds-btngroup{ display: inline-flex; }
.ds-btngroup .ds-btn{ border-radius: 0; margin-left: -1px; }
.ds-btngroup .ds-btn:first-child{ border-radius: var(--ds-radius) 0 0 var(--ds-radius); margin-left: 0; }
.ds-btngroup .ds-btn:last-child{ border-radius: 0 var(--ds-radius) var(--ds-radius) 0; }
.ds-btngroup .ds-btn:focus-visible{ position: relative; z-index: 1; }


/* =============================================================================
   12 · CAMPO DE FORMULÁRIO E SELECT
   <div class="ds-field">
     <label class="ds-label" for="email">E-mail</label>
     <input class="ds-input" id="email" type="email"
            aria-describedby="email-hint email-err" aria-invalid="true">
     <p class="ds-hint" id="email-hint">…</p>
     <p class="ds-erro" id="email-err">…</p>
   </div>
   O erro NUNCA é só a borda vermelha: é borda + texto com ícone, ligado por
   aria-describedby e marcado com aria-invalid.
   ============================================================================= */
.ds-field{ display: flex; flex-direction: column; gap: var(--ds-sp-2); min-width: 0; }
.ds-fieldset{ border: 0; padding: 0; margin: 0; display: grid; gap: var(--ds-sp-7); }
.ds-legend-form{
  font-size: var(--ds-text-eyebrow);
  letter-spacing: var(--ds-track);
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 600;
  padding: 0;
}
.ds-label{
  font-size: var(--ds-text-eyebrow);
  letter-spacing: var(--ds-track);
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 600;
}
.ds-label__obrig{ color: var(--st-crit-tx); margin-left: 2px; }

.ds-input,
.ds-select,
.ds-textarea{
  background: var(--surface);
  color: var(--ink);
  border: var(--ds-rule) solid var(--rule-strong);
  border-radius: var(--ds-radius);
  padding: var(--ds-sp-3) var(--ds-sp-6);
  font: inherit;
  font-size: var(--ds-text-ctl);
  line-height: var(--ds-lh-ctl);
  width: 100%;
  min-width: 0;
}
.ds-textarea{ min-height: 64px; resize: vertical; white-space: pre-wrap; }
.ds-input::placeholder,
.ds-textarea::placeholder{ color: var(--ink-3); }
.ds-input:hover,
.ds-select:hover,
.ds-textarea:hover{ border-color: var(--ink-3); }

/* campo de documento/protocolo: mono e tabular */
.ds-input--mono{
  font-family: var(--font-mono);
  letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
}

.ds-select{
  cursor: pointer;
  appearance: none;
  padding-right: 22px;
  /* a seta da maquete: dois triângulos em currentColor, sem imagem externa */
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 12px) 50%, calc(100% - 8px) 50%;
  background-size: 4px 4px, 4px 4px;
  background-repeat: no-repeat;
}
.ds-select--auto{ width: auto; }

.ds-input[disabled],
.ds-select[disabled],
.ds-textarea[disabled]{
  background: var(--surface-alt);
  color: var(--ink-3);
  border-color: var(--rule);
  cursor: not-allowed;
}
.ds-input[readonly]{ background: var(--surface-alt); color: var(--ink-2); }

.ds-input[aria-invalid="true"],
.ds-select[aria-invalid="true"],
.ds-textarea[aria-invalid="true"]{
  border-color: var(--st-crit);
  box-shadow: inset 2px 0 0 var(--st-crit);   /* marca de forma além da cor */
}

.ds-hint{ font-size: var(--ds-text-eyebrow); color: var(--ink-3); }
.ds-erro{
  font-size: var(--ds-text-eyebrow);
  color: var(--st-crit-tx);
  font-weight: 600;
  display: flex; align-items: center; gap: var(--ds-sp-3);
}
.ds-erro svg{ flex: none; }

/* campo de arquivo (tela importar) */
.ds-file{
  display: flex; align-items: center; gap: var(--ds-sp-6);
  border: 1px dashed var(--rule-strong);
  border-radius: var(--ds-radius);
  background: var(--surface-alt);
  padding: var(--ds-sp-6) var(--ds-sp-7);
  font-size: var(--ds-text-ctl);
  color: var(--ink-2);
  flex-wrap: wrap;
}
.ds-file input[type="file"]{ font: inherit; font-size: var(--ds-text-ctl); min-width: 0; }
.ds-file:focus-within{ border-color: var(--focus); border-style: solid; }

/* cartão de autenticação (tela de login) — mesmo painel, largura curta e centrado.
   É a ÚNICA superfície centralizada do sistema: um formulário de 2 campos. */
.ds-authwrap{
  min-height: 100dvh;
  display: flex; align-items: center; justify-content: center;
  padding: var(--ds-sp-9);
}
.ds-auth{ width: 100%; max-width: 340px; }
.ds-auth .ds-panel__body{ padding: var(--ds-sp-8); display: grid; gap: var(--ds-sp-7); }


/* =============================================================================
   13 · NOTICE — alerta / faixa de aviso
   <div class="ds-notice ds-notice--curso" role="status">
     <span class="ds-notice__tag">Em curso</span>
     <p>…</p>
   </div>
   A faixa de 3px à esquerda é o canal de cor. O TAG textual é obrigatório: é ele
   que diz o estado para quem não vê a faixa. `role="status"` para informativo,
   `role="alert"` só para o que exige ação imediata (alert interrompe o leitor).
   ============================================================================= */
.ds-notice{
  display: flex; gap: 9px; align-items: flex-start;
  background: var(--surface);
  border: var(--ds-rule) solid var(--rule);
  border-left: 3px solid var(--rule-strong);
  padding: var(--ds-sp-5) var(--ds-sp-7);
  font-size: var(--ds-text-body);
  flex-wrap: wrap;
}
.ds-notice__tag{
  font-size: var(--ds-text-eyebrow);
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-2);
  white-space: nowrap;
  display: inline-flex; align-items: center; gap: var(--ds-sp-3);
}
.ds-notice p{ color: var(--ink-2); min-width: 0; }
.ds-notice b{ color: var(--ink); font-variant-numeric: tabular-nums; }
.ds-notice svg{ flex: none; }
.ds-notice__acao{ margin-left: auto; display: flex; gap: var(--ds-sp-5); align-items: center; }

/* estados do ciclo — mesmas cores das séries, para o aviso e o gráfico contarem
   a mesma história */
.ds-notice--fechada{ border-left-color: var(--s-renovado); }
.ds-notice--curso{ border-left-color: var(--s-pendente); }
.ds-notice--nao-abriu{ border-left-color: var(--s-aberto); }
.ds-notice--sem-base{ border-left-color: var(--rule-strong); border-left-style: dashed; }

/* estados de sistema */
.ds-notice--erro{ border-left-color: var(--st-crit); }
.ds-notice--erro .ds-notice__tag{ color: var(--st-crit-tx); }
.ds-notice--atencao{ border-left-color: var(--st-warn); }
.ds-notice--sucesso{ border-left-color: var(--st-good); }
.ds-notice--sucesso .ds-notice__tag{ color: var(--st-good-tx); }
.ds-notice[hidden]{ display: none; }


/* =============================================================================
   14 · ALTERNADORES — sol/lua e textura
   <button class="ds-btn ds-btn--miudo ds-toggle" id="btn-tema" title="Alternar tema">
     <svg class="ds-ico-lua">…</svg><svg class="ds-ico-sol">…</svg>
     <span class="ds-sr-only">Alternar tema</span>
   </button>
   Claro é o padrão. Lua aparece no claro (o que você VAI ativar); sol no escuro.
   O botão não é um ícone mudo: tem rótulo para leitor de tela e title no hover.
   ============================================================================= */
.ds-toggle{ padding-inline: var(--ds-sp-5); }
.ds-ico-sol{ display: none; }
.ds-ico-lua{ display: inline-block; vertical-align: middle; }
:root[data-theme="dark"] .ds-ico-lua{ display: none; }
:root[data-theme="dark"] .ds-ico-sol{ display: inline-block; vertical-align: middle; }
@media (prefers-color-scheme: dark){
  :root:where(:not([data-theme="light"])) .ds-ico-lua{ display: none; }
  :root:where(:not([data-theme="light"])) .ds-ico-sol{ display: inline-block; vertical-align: middle; }
}


/* =============================================================================
   15 · BARRA DE FILTRO
   ============================================================================= */
.ds-filterbar{
  display: flex; gap: var(--ds-sp-6); align-items: center; flex-wrap: wrap;
  padding: var(--ds-sp-5) var(--ds-sp-7);
  border-bottom: var(--ds-rule) solid var(--rule);
  background: var(--surface-alt);
}
.ds-filterbar__grp{ display: flex; gap: var(--ds-sp-4); align-items: center; }
.ds-filterbar__grp .ds-label{ white-space: nowrap; }
.ds-filterbar__count{
  margin-left: auto;
  font-size: var(--ds-text-ctl);
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}


/* =============================================================================
   16 · MASTHEAD E RODAPÉ — moldura das três telas
   ============================================================================= */
.ds-masthead{
  background: var(--surface);
  border-bottom: var(--ds-rule) solid var(--rule-strong);
  position: sticky; top: 0; z-index: 40;
}
.ds-masthead__row{
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 7px var(--ds-sp-9);
  border-bottom: var(--ds-rule) solid var(--rule);
}
.ds-wordmark{
  font-family: var(--font-serif);
  font-size: var(--ds-text-h1);
  letter-spacing: .01em;
  font-weight: 600;
  white-space: nowrap;
  min-width: 0;
}
.ds-wordmark span{ color: var(--ink-2); font-weight: 400; }
@media (max-width: 400px){
  .ds-wordmark{ white-space: normal; }
  .ds-wordmark span{ display: block; }
}
.ds-mastmeta{ display: flex; gap: var(--ds-sp-8); margin-left: auto; align-items: center; flex-wrap: wrap; }
.ds-mastmeta dl{ display: flex; gap: var(--ds-sp-5); align-items: baseline; margin: 0; }
.ds-mastmeta dt{
  font-size: var(--ds-text-eyebrow);
  letter-spacing: var(--ds-track);
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
}
.ds-mastmeta dd{
  margin: 0;
  font-size: var(--ds-text-ctl);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  white-space: nowrap;
}
.ds-vr{ width: 1px; height: 15px; background: var(--rule); }
@media (max-width: 760px){ .ds-vr{ display: none; } }

.ds-main{ padding: var(--ds-sp-7); max-width: 1720px; margin: 0 auto; }
.ds-footer{
  padding: var(--ds-sp-6) var(--ds-sp-8) 20px;
  font-size: var(--ds-text-note);
  color: var(--ink-3);
  max-width: 1720px; margin: 0 auto;
  display: flex; gap: var(--ds-sp-9); flex-wrap: wrap;
}
.ds-footer b{ color: var(--ink-2); font-weight: 600; }


/* =============================================================================
   17 · CONTRASTE FORÇADO · IMPRESSÃO · MOVIMENTO
   ============================================================================= */
@media (forced-colors: active){
  .ds-panel, .ds-kpis, .ds-notice, .ds-cyclebar, .ds-auth{ border: 1px solid CanvasText; }
  .ds-btn, .ds-cyc, .ds-input, .ds-select{ border: 1px solid CanvasText; }
  .ds-state{ border: 1px solid CanvasText; forced-color-adjust: none; }
  .ds-meter, .ds-wbar__fill, .ds-progress__fill{ forced-color-adjust: none; }
}
@media print{
  .ds-root{ background: #fff; }
  .ds-masthead{ position: static; }
  .ds-panel__tools, .ds-filterbar .ds-btn, .ds-toggle{ display: none; }
  .ds-panel{ break-inside: avoid; }
  .ds-table thead th, .ds-table tfoot td{ position: static; }
  /* no papel não há cor: a textura vira o único canal */
  .ds-state--renovado, .ds-state--fechada{
    background-image: repeating-linear-gradient(45deg, #fff 0 1.5px, transparent 1.5px 4px);
  }
  .ds-state--pendente, .ds-state--em-curso{
    background-image: repeating-linear-gradient(135deg, #fff 0 1.5px, transparent 1.5px 4px);
  }
}
@media (prefers-reduced-motion: reduce){
  .ds-root *, .ds-root *::before, .ds-root *::after{
    transition: none !important;
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
  }
}
