/* ===================================================================
   EFICÁCIA CRM — ds-listagem.css
   FASE 1 (proposta-design §4 "Listagens" e §6.2) — a folha da MOLDURA
   DE LISTAGEM: cabeçalho vivo · faixa de KPIs · filtros (drawer/bottom
   sheet em mobile) · chips de filtro ativo · barra de resultados ·
   tabela em desktop ↔ cartões em mobile · paginação · estados vazios.

   Par de estreia: a listagem de contratos (`mod-contratos.js`). Nasce
   genérica de propósito — são 30 ecrãs à espera da mesma moldura.

   Depende de: ds-tokens.css (paleta, --sp-*, --txt-*, --r-*, --sh-*).

   ===================================================================
   AS DUAS DECISÕES QUE EXPLICAM TUDO O QUE VEM A SEGUIR
   ===================================================================

   1) FAMÍLIA PRÓPRIA `ds-lst-*`, TABELA PRÓPRIA

      A tabela desta folha NÃO usa `.ds-table`. Não é capricho: o
      `.ds-table` do design-system.css vive FORA de camada e comanda o
      `display` das suas células em `@media (min-width:768px)`. Uma
      regra escrita aqui, em `@layer listagem`, perde sempre para ela —
      `@layer` decide antes da especificidade e o CSS sem camada ganha
      a qualquer camada. Para controlar a prioridade de colunas seria
      preciso `!important` (já há 335 na app; são o problema) ou uma
      guerra de seletores.

      Com família própria não há adversário: `.ds-lst-tab` e as suas
      células são só nossas, e a troca tabela↔cartões acontece onde nós
      decidirmos.

      O que continua a vir do design system, porque já funciona e não
      colide: `.ds-btn`, `.ds-icon-btn`, `.ds-badge`, `.ds-input`,
      `.ds-filter*`, `.ds-th-sortable`/`.ds-sort-ind`, `.ds-empty`,
      `.ds-pagination`.

   2) A TROCA TABELA↔CARTÕES ACONTECE A 1024 px, NÃO A 768

      Medido no browser, não estimado: a listagem de contratos tem 7
      colunas + ações e a tabela ocupava **1450 px** — em TODOS os
      viewports. O contentor útil é de 761 px a 834 px, 951 px a
      1024 px e 935 px a 1280 px (a sidebar come 272 px a partir dos
      ~1100 px). Resultado: a coluna ESTADO começava ao pixel 1211 e
      **nunca** estava visível sem arrastar a tabela para o lado.

      Duas correções, juntas:
        · cartões até aos 1023 px — no cartão cabe tudo (código,
          estado, cliente, marca, datas, alerta), sem scroll lateral;
        · a partir dos 1024 px, `table-layout: fixed` com larguras
          declaradas que somam menos do que os 935 px do pior caso, e
          truncagem com reticências no que não couber.

      É por isso que o único breakpoint de layout aqui é 1024. Os
      outros (480/640) só reorganizam o cartão.

   ===================================================================
   MOBILE-FIRST (§5.1) — só `min-width`
   ===================================================================
   Base = 320-390 px. As duas únicas exceções permitidas, e usadas no
   fim: `pointer: coarse` e `prefers-reduced-motion`.
   =================================================================== */

@layer listagem {

    /* ===============================================================
       0. RAIZ
       =============================================================== */

    .ds-lst {
        display: flex;
        flex-direction: column;
        gap: var(--sp-4);
        min-width: 0;

        --lst-ctrl: 44px;
        /* alvo de toque mínimo (WCAG 2.5.5) */
        --lst-estado: var(--ink-300);
        /* cor da faixa de identidade da linha */
    }

    /* §5.6 — a regra que resolve 80 % dos bugs de mobile: um item de
       flex/grid nunca cresce acima do pai. */
    .ds-lst *,
    .ds-lst *::before,
    .ds-lst *::after {
        min-width: 0;
    }

    .ds-lst-ico {
        flex-shrink: 0;
        width: 16px;
        height: 16px;
    }

    /* ===============================================================
       1. CABEÇALHO — ícone + título + CONTADOR VIVO + ações (§4.1)
       O subtítulo nunca é decorativo: diz sempre quantos há e quantos
       se estão a ver ("238 contratos · 10 a mostrar").
       =============================================================== */

    .ds-lst-cab {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr);
        align-items: center;
        gap: var(--sp-3);
        padding-bottom: var(--sp-1);
    }

    .ds-lst-cab-ico {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 40px;
        height: 40px;
        border-radius: var(--r-lg);
        background: var(--brand-50);
        color: var(--brand-600);
        flex-shrink: 0;
    }

    .ds-lst-cab-ico .ds-lst-ico {
        width: 20px;
        height: 20px;
    }

    .ds-lst-cab-txt {
        min-width: 0;
    }

    .ds-lst-titulo {
        margin: 0;
        font-size: var(--txt-xl);
        font-weight: var(--fw-extra);
        letter-spacing: var(--track-tight);
        color: var(--text-1);
        line-height: 1.2;
    }

    .ds-lst-sub {
        margin: 2px 0 0;
        font-size: var(--txt-sm);
        color: var(--text-3);
        font-variant-numeric: var(--num-tabular);
    }

    /* Em mobile as ações passam para baixo, à largura toda: são alvos
       de toque, não enfeites de canto. */
    .ds-lst-cab-acoes {
        grid-column: 1 / -1;
        display: flex;
        flex-wrap: wrap;
        gap: var(--sp-2);
    }

    .ds-lst-cab-acoes>* {
        flex: 1 1 auto;
        min-height: var(--lst-ctrl);
    }

    @media (min-width: 640px) {
        .ds-lst-cab {
            grid-template-columns: auto minmax(0, 1fr) auto;
        }

        .ds-lst-cab-acoes {
            grid-column: auto;
            flex-wrap: nowrap;
        }

        .ds-lst-cab-acoes>* {
            flex: 0 0 auto;
        }
    }

    @media (min-width: 1024px) {
        .ds-lst-titulo {
            font-size: var(--txt-2xl);
        }
    }

    /* ===============================================================
       2. FAIXA DE KPIs (§4.2) — cada um é um filtro em profundidade
       Clicáveis: levam à lista já filtrada por esse estado. O ativo
       fica marcado com `aria-pressed` E com cor — nunca só com cor.
       =============================================================== */

    .ds-lst-kpis {
        display: flex;
        gap: var(--sp-2);
        overflow-x: auto;
        scrollbar-width: none;
        padding-bottom: var(--sp-1);
        -webkit-overflow-scrolling: touch;
    }

    .ds-lst-kpis::-webkit-scrollbar {
        display: none;
    }

    .ds-lst-kpi {
        display: flex;
        flex-direction: column;
        gap: 2px;
        flex: 0 0 auto;
        min-width: 96px;
        min-height: var(--lst-ctrl);
        padding: var(--sp-2) var(--sp-3);
        border: 1px solid var(--border);
        border-radius: var(--r-lg);
        background: var(--surface);
        color: var(--text-2);
        text-align: left;
        cursor: pointer;
        transition: border-color .16s ease, box-shadow .16s ease, background .16s ease;

        --kpi-cor: var(--ink-400);
    }

    .ds-lst-kpi:hover {
        border-color: var(--border-strong);
        box-shadow: var(--sh-2);
    }

    .ds-lst-kpi[aria-pressed="true"] {
        border-color: var(--kpi-cor);
        background: var(--surface-alt);
        box-shadow: inset 0 -2px 0 var(--kpi-cor);
    }

    .ds-lst-kpi-n {
        font-size: var(--txt-xl);
        font-weight: var(--fw-extra);
        line-height: 1.05;
        letter-spacing: var(--track-tight);
        font-variant-numeric: var(--num-tabular);
        color: var(--text-1);
    }

    /* Nada de texto abaixo de 12 px no telemóvel: é o mínimo legível da
       auditoria (e da vida real). A densidade de 11 px fica para o
       desktop, onde o ecrã está a 60 cm dos olhos, não a 30. */
    .ds-lst-kpi-rot {
        display: flex;
        align-items: center;
        gap: 6px;
        font-size: var(--txt-sm);
        font-weight: var(--fw-bold);
        text-transform: uppercase;
        letter-spacing: var(--track-caps);
        color: var(--text-3);
        white-space: nowrap;
    }

    @media (min-width: 1024px) {
        .ds-lst-kpi-rot {
            font-size: var(--txt-xs);
        }
    }

    .ds-lst-kpi-rot::before {
        content: "";
        width: 7px;
        height: 7px;
        border-radius: var(--r-full);
        background: var(--kpi-cor);
        flex-shrink: 0;
    }

    /* Paleta dos 7 estados de contrato (server/routes/contratos.js
       ESTADO_COR). Fica aqui e não no JS porque é aparência. */
    .ds-lst-kpi[data-cor="red"] {
        --kpi-cor: var(--brand-500);
    }

    .ds-lst-kpi[data-cor="blue"] {
        --kpi-cor: var(--info-500);
    }

    .ds-lst-kpi[data-cor="gray"] {
        --kpi-cor: var(--ink-400);
    }

    .ds-lst-kpi[data-cor="amber"] {
        --kpi-cor: var(--warning-500);
    }

    .ds-lst-kpi[data-cor="indigo"] {
        --kpi-cor: #6366f1;
    }

    .ds-lst-kpi[data-cor="green"] {
        --kpi-cor: var(--success-500);
    }

    .ds-lst-kpi[data-cor="dark"] {
        --kpi-cor: var(--ink-700);
    }

    /* ===============================================================
       2b. O PAINEL «ANÁLISE» — UM desenho para os dez módulos
       ===============================================================
       O cliente pediu simetria e tinha razão: havia dez painéis
       diferentes («Painel do módulo», «Análise do catálogo», «Ver
       detalhe», «Ver análise e filas de trabalho»), com quatro ícones
       e três posições para os KPIs. Agora há um: faixa de KPIs SEMPRE
       visível (§2, acima) e, logo a seguir, este painel dobrável.

       A casca vem toda de `MOD.listagem.painelAnalise()`. Aqui só se
       decide como é que ela se vê — e vê-se igual em toda a app.

       O botão inteiro é o alvo: 100 % de largura e ≥44 px de altura
       (WCAG 2.5.5). Num telemóvel ninguém acerta numa seta de 16 px.
       =============================================================== */

    .ds-analise {
        display: flex;
        flex-direction: column;
        gap: var(--sp-3);
    }

    .ds-analise[hidden] {
        display: none;
    }

    .ds-analise-toggle {
        display: flex;
        align-items: center;
        gap: var(--sp-2);
        width: 100%;
        min-height: var(--lst-ctrl, 44px);
        padding: var(--sp-2) var(--sp-3);
        border: 1px solid var(--border);
        border-radius: var(--r-lg);
        background: var(--surface);
        color: var(--text-2);
        font-family: inherit;
        font-size: var(--txt-base);
        font-weight: var(--fw-bold);
        text-align: left;
        cursor: pointer;
        transition: border-color .16s ease, background .16s ease;
    }

    .ds-analise-toggle:hover {
        border-color: var(--border-strong);
        background: var(--surface-alt, var(--surface));
    }

    /* O ícone `activity` a vermelho da marca: é ele que o cliente
       reconhece como «isto é a análise» — o mesmo em dez ecrãs. */
    .ds-analise-ico {
        display: inline-flex;
        flex: 0 0 auto;
        color: var(--brand-500);
    }

    .ds-analise-txt {
        display: flex;
        flex-direction: column;
        gap: 1px;
        flex: 1 1 auto;
        min-width: 0;
    }

    .ds-analise-txt strong {
        font-weight: var(--fw-bold);
        color: var(--text-1);
    }

    /* Com o painel fechado esta linha é a ÚNICA informação do painel:
       diz o que há para fazer sem obrigar a abrir nada. */
    .ds-analise-sub {
        font-size: var(--txt-sm);
        font-weight: var(--fw-regular, 400);
        color: var(--text-3);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .ds-analise-sub:empty {
        display: none;
    }

    .ds-analise-chev {
        display: inline-flex;
        flex: 0 0 auto;
        color: var(--text-3);
        transition: transform .18s ease;
    }

    .ds-analise-toggle[aria-expanded="true"] .ds-analise-chev {
        transform: rotate(180deg);
    }

    .ds-analise-corpo {
        display: flex;
        flex-direction: column;
        gap: var(--sp-3);
        min-width: 0;
    }

    .ds-analise-corpo[hidden] {
        display: none;
    }

    /* Mensagens de serviço do painel (a calcular / falhou) — antes cada
       módulo tinha a sua classe e o seu tamanho de letra. */
    .ds-analise-nota,
    .ds-analise-erro {
        display: flex;
        align-items: center;
        gap: var(--sp-2);
        flex-wrap: wrap;
        padding: var(--sp-4);
        margin: 0;
        color: var(--text-3);
        font-size: var(--txt-base);
    }

    .ds-analise-erro {
        color: var(--brand-600);
    }

    @media (prefers-reduced-motion: reduce) {
        .ds-analise-toggle,
        .ds-analise-chev {
            transition: none;
        }
    }

    /* ===============================================================
       3. CHIPS DE FILTRO ATIVO (§4.5) — o que está aplicado, e o X
       =============================================================== */

    .ds-lst-chips {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: var(--sp-2);
    }

    .ds-lst-chips:empty {
        display: none;
    }

    /* O X de cada chip é um alvo de toque a sério (44 px, WCAG 2.5.5):
       remover um filtro por engano custa uma pesquisa inteira. A partir
       dos 768 px, onde há rato, o chip encolhe para a densidade normal. */
    .ds-lst-chip {
        display: inline-flex;
        align-items: center;
        gap: var(--sp-1);
        max-width: 100%;
        min-height: var(--lst-ctrl);
        padding: 0 0 0 12px;
        border: 1px solid var(--brand-200);
        border-radius: var(--r-full);
        background: var(--brand-50);
        color: var(--brand-700);
        font-size: var(--txt-sm);
        font-weight: var(--fw-semibold);
    }

    .ds-lst-chip-txt {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .ds-lst-chip-x {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: var(--lst-ctrl);
        height: var(--lst-ctrl);
        border: 0;
        border-radius: var(--r-full);
        background: transparent;
        color: inherit;
        cursor: pointer;
        flex-shrink: 0;
    }

    .ds-lst-chip-x:hover {
        background: var(--brand-100);
    }

    @media (min-width: 768px) {
        .ds-lst-chip {
            min-height: 28px;
            padding: 0 2px 0 10px;
            font-size: var(--txt-xs);
        }

        .ds-lst-chip-x {
            width: 24px;
            height: 24px;
        }
    }

    /* ===============================================================
       4. BARRA DE RESULTADOS — contagem + ordenação em curso
       =============================================================== */

    .ds-lst-barra {
        display: flex;
        flex-wrap: wrap;
        align-items: baseline;
        justify-content: space-between;
        gap: var(--sp-2);
        font-size: var(--txt-sm);
        color: var(--text-3);
    }

    .ds-lst-barra strong {
        color: var(--text-1);
        font-variant-numeric: var(--num-tabular);
    }

    .ds-lst-barra-ord {
        display: none;
    }

    @media (min-width: 768px) {
        .ds-lst-barra-ord {
            display: inline;
        }
    }

    /* ===============================================================
       5. RESULTADO — CARTÕES (base, < 1024 px)
       A MESMA tabela do desktop, reorganizada por CSS: um só markup,
       uma só fonte de verdade, zero re-render ao rodar o telemóvel.
       Colocação explícita célula a célula (nada de
       `grid-template-areas`: a armadilha documentada pelo Shoperfil —
       uma linha com um número de áreas diferente faz o browser
       descartar a regra inteira e o cartão colapsa).
       =============================================================== */

    .ds-lst-tabwrap {
        min-width: 0;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    .ds-lst-tab {
        width: 100%;
        border-collapse: separate;
        border-spacing: 0;
    }

    .ds-lst-tab,
    .ds-lst-tab tbody {
        display: block;
    }

    .ds-lst-tab thead {
        display: none;
    }

    .ds-lst-tab tbody {
        display: flex;
        flex-direction: column;
        gap: var(--sp-3);
    }

    .ds-lst-linha {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: start;
        gap: var(--sp-1) var(--sp-3);
        position: relative;
        padding: var(--sp-3) var(--sp-4);
        padding-left: calc(var(--sp-4) + 3px);
        border: 1px solid var(--border);
        border-radius: var(--r-xl);
        background: var(--surface);
        box-shadow: var(--sh-1);
        overflow: hidden;
        transition: box-shadow .16s ease, border-color .16s ease;
    }

    /* Faixa de identidade de 3 px na cor do estado: é o fio que liga
       visualmente a linha da lista à ficha (§4.3). */
    .ds-lst-linha::before {
        content: "";
        position: absolute;
        inset: 0 auto 0 0;
        width: 3px;
        background: var(--lst-estado);
    }

    .ds-lst-tab tbody tr.ds-lst-linha:hover {
        border-color: var(--border-strong);
        box-shadow: var(--sh-2);
    }

    .ds-lst-linha[data-clicavel="1"] {
        cursor: pointer;
    }

    .ds-lst-c {
        display: block;
        min-width: 0;
        font-size: var(--txt-sm);
        color: var(--text-2);
    }

    /* O rótulo da coluna vira eyebrow do valor — só onde ajuda. */
    .ds-lst-c[data-rot]::before {
        content: attr(data-rot);
        display: block;
        font-size: var(--txt-2xs);
        font-weight: var(--fw-bold);
        text-transform: uppercase;
        letter-spacing: var(--track-caps);
        color: var(--text-3);
    }

    .ds-lst-c--codigo {
        grid-column: 1;
        grid-row: 1;
    }

    .ds-lst-c--estado {
        grid-column: 2;
        grid-row: 1;
        justify-self: end;
        text-align: right;
    }

    .ds-lst-c--cliente {
        grid-column: 1 / -1;
        grid-row: 2;
    }

    .ds-lst-c--marca {
        grid-column: 1 / -1;
        grid-row: 3;
    }

    .ds-lst-c--proposta {
        grid-column: 1 / -1;
        grid-row: 4;
    }

    .ds-lst-c--inicio {
        grid-column: 1;
        grid-row: 5;
    }

    .ds-lst-c--fim {
        grid-column: 2;
        grid-row: 5;
        text-align: right;
    }

    .ds-lst-c--acoes {
        grid-column: 1 / -1;
        grid-row: 6;
        display: flex;
        justify-content: flex-end;
        gap: var(--sp-1);
        padding-top: var(--sp-2);
        margin-top: var(--sp-1);
        border-top: 1px solid var(--border);
    }

    /* Código e estado mandam no cartão: sem eyebrow, tamanho maior. */
    .ds-lst-c--codigo[data-rot]::before,
    .ds-lst-c--estado[data-rot]::before,
    .ds-lst-c--cliente[data-rot]::before,
    .ds-lst-c--acoes[data-rot]::before {
        content: none;
    }

    .ds-lst-cod {
        display: block;
        font-family: var(--font-mono);
        font-size: var(--txt-lg);
        font-weight: var(--fw-bold);
        letter-spacing: var(--track-tight);
        color: var(--text-1);
    }

    .ds-lst-forte {
        display: block;
        font-weight: var(--fw-semibold);
        color: var(--text-1);
        overflow-wrap: anywhere;
    }

    .ds-lst-ref {
        font-family: var(--font-mono);
        font-size: var(--txt-sm);
        color: var(--brand-700);
    }

    .ds-lst-nota {
        display: block;
        font-size: var(--txt-sm);
        color: var(--text-3);
        font-variant-numeric: var(--num-tabular);
    }

    /* `--ink-300` é a cor das BORDAS: em texto dava 1.63:1, ou seja, uma
       célula que parecia vazia por bug e não por não haver dado. Com
       `--text-3` (5.63:1) o traço lê-se, e continua mais leve do que o
       valor real ao lado — que é toda a intenção. */
    .ds-lst-vazio-cel {
        color: var(--text-3);
    }

    /* Sinal de alerta na célula-herói: o mesmo vocabulário de níveis
       de `MOD.alertas`, em versão de uma linha (§3.3c). */
    .ds-lst-sinal {
        display: inline-flex;
        align-items: center;
        gap: 5px;
        margin-top: 4px;
        max-width: 100%;
        padding: 2px 8px;
        border-radius: var(--r-full);
        font-size: var(--txt-sm);
        font-weight: var(--fw-semibold);
        line-height: 1.5;
        background: var(--ink-100);
        color: var(--text-2);
    }

    .ds-lst-sinal-txt {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .ds-lst-sinal--aviso {
        background: var(--warning-50);
        color: var(--warning-700);
    }

    .ds-lst-sinal--critico {
        background: var(--danger-50);
        color: var(--danger-700);
    }

    .ds-lst-sinal--acao {
        background: var(--brand-50);
        color: var(--brand-700);
    }

    /* Cartões a 2 colunas no tablet: a partir dos 640 px uma coluna
       única deixa metade do ecrã em branco. */
    @media (min-width: 640px) and (max-width: 1023.98px) {
        .ds-lst-tab tbody {
            display: grid;
            grid-template-columns: repeat(2, minmax(0, 1fr));
            align-items: stretch;
        }
    }

    /* ===============================================================
       6. RESULTADO — TABELA (>= 1024 px)
       `table-layout: fixed`: as larguras são as declaradas, não as que
       o conteúdo pedir. É o que impede uma marca comprida de esticar
       a tabela para 1450 px e empurrar o ESTADO para fora do ecrã.
       Soma: 96+104+auto+140+92+104+118+96 = 750 px + Cliente, dentro
       dos 935 px do pior caso (1280 px com sidebar).
       =============================================================== */

    @media (min-width: 1024px) {

        .ds-lst-tabwrap {
            border: 1px solid var(--border);
            border-radius: var(--r-xl);
            background: var(--surface);
            box-shadow: var(--sh-1);
        }

        .ds-lst-tab {
            display: table;
            width: 100%;
            table-layout: fixed;
        }

        .ds-lst-tab tbody {
            display: table-row-group;
        }

        .ds-lst-tab thead {
            display: table-header-group;
        }

        .ds-lst-h {
            position: sticky;
            top: 0;
            z-index: 2;
            padding: 10px var(--sp-3);
            background: var(--surface-sunken);
            border-bottom: 1px solid var(--border);
            font-size: var(--txt-xs);
            font-weight: var(--fw-bold);
            text-transform: uppercase;
            letter-spacing: var(--track-caps);
            color: var(--text-3);
            text-align: left;
            white-space: nowrap;
        }

        .ds-lst-h--codigo {
            width: 96px;
        }

        .ds-lst-h--proposta {
            min-width: 120px;
        }

        .ds-lst-h--cliente {
            width: auto;
        }

        .ds-lst-h--marca {
            width: 140px;
        }

        .ds-lst-h--inicio {
            min-width: 112px;
        }

        .ds-lst-h--fim {
            min-width: 120px;
        }

        .ds-lst-h--estado {
            width: 118px;
            text-align: center;
        }

        /* A largura vem de uma variável que o `MOD.listagem` mede a partir dos
           botões que a linha traz. Estava presa em 96px — que dá para dois
           botões e corta o terceiro. Nos Contratos (ver, editar, PDF) o
           conteúdo pedia 135px e perdiam-se 39px: era o ícone do PDF a
           desaparecer. Os 96px ficam como valor de recurso, para o caso de o
           JavaScript não correr. */
        .ds-lst-h--acoes {
            width: var(--ds-lst-acoes-w, 96px);
            text-align: right;
        }

        .ds-lst-linha {
            display: table-row;
            padding: 0;
            border: 0;
            border-radius: 0;
            background: transparent;
            box-shadow: none;
            overflow: visible;
        }

        .ds-lst-linha::before {
            content: none;
        }

        .ds-lst-tab tbody tr.ds-lst-linha:hover {
            background: var(--surface-alt);
            box-shadow: none;
        }

        .ds-lst-c {
            display: table-cell;
            padding: 10px var(--sp-3);
            border-bottom: 1px solid var(--border);
            vertical-align: middle;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .ds-lst-tab tbody tr:last-child .ds-lst-c {
            border-bottom: 0;
        }

        .ds-lst-c[data-rot]::before {
            content: none;
        }

        /* A faixa de estado passa a ser a borda esquerda da 1.ª célula
           (numa `table-row` não há onde pendurar um pseudo absoluto). */
        .ds-lst-c--codigo {
            border-left: 3px solid var(--lst-estado);
            padding-left: calc(var(--sp-3) - 3px);
        }

        .ds-lst-cod {
            font-size: var(--txt-sm);
        }

        .ds-lst-c--estado {
            text-align: center;
        }

        .ds-lst-c--inicio,
        .ds-lst-c--fim {
            text-align: right;
            font-variant-numeric: var(--num-tabular);
        }

        .ds-lst-c--acoes {
            display: table-cell;
            padding-top: 10px;
            margin: 0;
            border-top: 0;
            border-bottom: 1px solid var(--border);
            text-align: right;
            white-space: nowrap;
        }

        .ds-lst-c--cliente,
        .ds-lst-c--marca {
            overflow: hidden;
            text-overflow: ellipsis;
        }

        /* O sinal de alerta cabe numa linha própria dentro da célula. */
        .ds-lst-sinal {
            margin-top: 2px;
            max-width: 100%;
            font-size: var(--txt-2xs);
            padding: 1px 6px;
        }

        .ds-lst-ref,
        .ds-lst-nota {
            font-size: var(--txt-xs);
        }

        /* Ações só no hover/foco — mas SEMPRE visíveis ao toque
           (§4.3). O `pointer:coarse` no fim do ficheiro reverte. */
        .ds-lst-acoes-linha {
            display: inline-flex;
            gap: 2px;
            opacity: 0;
            transition: opacity .14s ease;
        }

        .ds-lst-linha:hover .ds-lst-acoes-linha,
        .ds-lst-linha:focus-within .ds-lst-acoes-linha {
            opacity: 1;
        }
    }

    /* ===============================================================
       7. ESTADOS VAZIOS (§4.6) — três, nunca o mesmo texto
       "não há nada" ≠ "os filtros não devolvem nada" ≠ "ainda não foi
       migrado". O terceiro é obrigatório: mostrar 0 onde a verdade é
       "ainda não sabemos" destrói a confiança no sistema.
       =============================================================== */

    .ds-lst-vazio {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: var(--sp-2);
        padding: var(--sp-10) var(--sp-4);
        border: 1px dashed var(--border-strong);
        border-radius: var(--r-xl);
        background: var(--surface-alt);
        text-align: center;
    }

    .ds-lst-vazio-ico {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 48px;
        height: 48px;
        border-radius: var(--r-full);
        background: var(--surface);
        border: 1px solid var(--border);
        color: var(--text-3);
    }

    .ds-lst-vazio-ico .ds-lst-ico {
        width: 22px;
        height: 22px;
    }

    .ds-lst-vazio-tit {
        margin: 0;
        font-size: var(--txt-lg);
        font-weight: var(--fw-bold);
        color: var(--text-1);
    }

    .ds-lst-vazio-txt {
        margin: 0;
        max-width: 46ch;
        font-size: var(--txt-sm);
        color: var(--text-3);
    }

    .ds-lst-vazio-acoes {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        gap: var(--sp-2);
        margin-top: var(--sp-2);
    }

    /* Vazio "por migrar": informa, não convida a agir. */
    .ds-lst-vazio--migracao {
        border-style: solid;
        border-color: var(--border);
        background: var(--surface);
    }

    /* ===============================================================
       8. RODAPÉ DA LISTAGEM — espaço de respiro no fim
       Não há CTA fixo nesta moldura, de propósito: uma barra colada ao
       fundo tapa permanentemente o cartão que está por baixo (a
       auditoria responsiva marca-o como sobreposição crítica). A ação
       principal vive no cabeçalho, sempre alcançável, e repete-se no
       estado vazio, que é onde faz mesmo falta.
       =============================================================== */

    .ds-lst-fim {
        height: var(--sp-6);
    }

    /* ===============================================================
       9. TOQUE, MOVIMENTO E IMPRESSÃO
       =============================================================== */

    @media (pointer: coarse) {

        /* Sem hover não há revelação: as ações da linha têm de estar
           sempre lá (§4.3). */
        .ds-lst-acoes-linha {
            opacity: 1;
        }

        .ds-lst-kpi,
        .ds-lst-chip-x {
            min-height: var(--lst-ctrl);
        }
    }

    @media (prefers-reduced-motion: reduce) {

        .ds-lst-kpi,
        .ds-lst-linha,
        .ds-lst-acoes-linha {
            transition: none;
        }
    }

    @media print {

        .ds-lst-kpis,
        .ds-lst-cab-acoes,
        .ds-lst-c--acoes,
        .ds-lst-chips {
            display: none;
        }

        .ds-lst-tabwrap {
            overflow: visible;
            border: 0;
            box-shadow: none;
        }

        .ds-lst-linha {
            break-inside: avoid;
        }
    }
}


/* ===================================================================
   PONTE DE MIGRAÇÃO — FORA de camada, de propósito.
   ===================================================================
   Mesma mecânica (e mesma data de validade) da ponte do ds-ficha.css:
   apaga-se INTEIRA na Fase 6, quando o legado passar a ser servido
   dentro de `@layer legado{}`.

   O reset do style.css vive sem camada e, por isso, ganha a QUALQUER
   camada — incluindo a `listagem`. Sem estas linhas, tudo o que esta
   folha escreve em `padding`, `margin`, `background`, `border` e
   `list-style` computa a zero. `revert-layer` numa regra sem camada
   recua para a ÚLTIMA camada, ou seja, para o que ficou acima; a
   ponte ganha ao reset por especificidade (0-1-0 > 0-0-0) e devolve o
   valor à camada. Zero `!important`, zero duplicação de valores.

   Restrita a `ds-lst*`/`ds-analise*` de propósito: se apanhasse
   `.ds-btn` ou `.ds-table` — que vivem sem camada no design-system.css
   — o `revert-layer` deitaria fora o estilo deles.
   =================================================================== */

[class*="ds-lst"],
[class*="ds-analise"] {
    /* contra  *, *::before, *::after { margin: 0; padding: 0 } */
    margin: revert-layer;
    padding: revert-layer;
    /* contra  button { border: none; background: none } */
    background: revert-layer;
    border: revert-layer;
    /* contra  ul, ol { list-style: none } */
    list-style: revert-layer;
}
