/* Grupo Dls/ - índice de cases
 *
 * A página que o "Ver todos os cases" da home promete. Ela tem três
 * trabalhos, nesta ordem de importância:
 *
 *   1. Mostrar o que existe. É um índice, não uma landing: quem chega
 *      aqui já quer ver trabalho, e a página não precisa convencer
 *      ninguém a rolar.
 *   2. Deixar filtrar. Oito cases hoje, quarenta depois - a grade e o
 *      filtro nasceram para a segunda quantidade.
 *   3. Ter um lugar para o destaque editorial. É o banner do topo, e
 *      quem escolhe o que entra nele é uma pessoa, não uma regra: o
 *      cartão ganha `data-destaque` e sobe.
 *
 * O QUE ESTA FOLHA NÃO REFAZ
 * O cartão de case já existe, em scenes.css, e é o mesmo objeto que a
 * faixa da home usa: moldura, capa, botão de hover que segue o cursor,
 * corpo com frente e cliente. Reimplementá-lo aqui daria dois cartões
 * que precisam ser mantidos juntos e vão divergir na terceira alteração.
 * O que muda entre a faixa e a grade é o TAMANHO e o RAIO, e é só isso
 * que está escrito aqui.
 */

/* ---------- os tokens da folha ----------
   O raio é 16px, e não o squircle. O squircle proporcional (20,8% do
   lado menor) é desenho de OBJETO - o núcleo das frentes, o loader, a
   marca. Numa grade de nove capas ele vira nove buracos arredondados
   demais na mesma tela, e come justamente o canto da foto. Na faixa da
   home o cartão é uma peça por vez, passando; aqui são todos ao mesmo
   tempo, e a diferença de contexto decide. */
:root {
  --r-cartao: 16px;
}

/* A página é clara e continua clara até o fechamento. O corte para o
   preto no fim é o mesmo da home e das páginas de case: é o ponto final
   do site, e acontece uma vez. */
.cases-page {
  background: var(--bg);
}

/* Mesmo raciocínio da página de case: sobre chão claro o header se
   resolve por subtração, sem coreografia. */
.cases-page .header {
  background: none;
  mix-blend-mode: difference;
}

/* O anel de foco amarelo do sistema mede 1.07:1 sobre claro. Aqui ele é
   preto com um segundo anel branco por fora, para sobreviver também
   quando o alvo estiver sobre a capa. */
.cases-page :focus-visible {
  outline: 2px solid var(--c-black);
  outline-offset: 3px;
  box-shadow: 0 0 0 5px var(--c-white);
}

/* ============================================================
   ci-destaque
   O banner rotativo. Divisão em duas colunas, e não texto por
   cima da foto: sobre imagem, texto branco precisa de um véu
   para ser lido, e o véu apaga a foto que o banner existe para
   mostrar. Com as duas colunas separadas, a foto fica inteira e
   o texto fica em 18:1 sobre papel. Ninguém cede.
   ============================================================ */
.ci-destaque {
  padding-block: clamp(var(--sp-9), 15vh, var(--sp-10)) clamp(var(--sp-9), 10vh, var(--sp-10));
}

.ci-banner {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(var(--sp-6), 4vw, var(--sp-8));
  align-items: stretch;
}

/* ---------- o palco ----------
   Os slides ocupam a mesma célula da grade e se sobrepõem, senão a
   troca empurraria a página para baixo a cada seis segundos. A altura é
   a do slide mais alto, e ela é reservada aqui: sem isto o palco teria
   altura zero, porque todo filho é posicionado. */
.ci-banner__palco {
  position: relative;
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
  min-height: clamp(420px, 58vh, 620px);
}

.ci-slide {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(var(--sp-6), 4vw, var(--sp-8));
  align-items: center;
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
}

.ci-slide.is-ativo {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
}

/* Sem JS a transição é do CSS. Com JS quem manda é o GSAP, e a transição
   sai de cena: dois motores escrevendo em `opacity` fazem a peça piscar
   duas vezes na mesma troca. */
.ci-banner:not(.is-viva) .ci-slide {
  transition:
    opacity var(--dur-scene) var(--ease-out),
    visibility 0s linear var(--dur-scene);
}

.ci-banner:not(.is-viva) .ci-slide.is-ativo {
  transition:
    opacity var(--dur-scene) var(--ease-out),
    visibility 0s;
}

.ci-slide__texto {
  display: grid;
  align-content: center;
  justify-items: start;
  gap: var(--sp-4);
}

.ci-slide__frentes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--fg-muted);
}

/* A marca da frente. Não é enfeite: é a cor da unidade que assinou o
   trabalho, o mesmo par cor-frente que o menu principal usa. Quadrado
   pequeno, e não texto colorido - o amarelo do Dls/ mede 1.35:1 sobre
   papel e não sustenta uma letra. */
.ci-marca {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 0.6em;
  border-radius: 2px;
  background: var(--unit, var(--c-black));
  vertical-align: 0.02em;
}

.ci-slide__titulo {
  font-weight: 300;
  font-size: var(--fs-display-m);
  line-height: 1.06;
  letter-spacing: var(--tr-display);
  max-width: 16ch;
}

.ci-slide__cliente {
  font-size: var(--fs-body-l);
  color: var(--fg-muted);
}

/* O número só aparece onde ele existe. Case sem resultado documentado
   não ganha uma linha vazia nem um número de enfeite. */
.ci-slide__resultado {
  font-size: var(--fs-body);
  font-variant-numeric: tabular-nums;
}

.ci-slide__moldura {
  position: relative;
  height: 100%;
  border-radius: var(--r-cartao);
  overflow: hidden;
  background: #0d0d0d;
}

.ci-slide__moldura img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-scene) var(--ease-out);
}

.ci-slide:hover .ci-slide__moldura img,
.ci-slide:focus-visible .ci-slide__moldura img {
  transform: scale(1.04);
}

/* O link cobre o slide inteiro. Um `<a>` em volta de tudo, com um
   `role` de carrossel por cima, destruiria a semântica de link; e dois
   links para o mesmo destino - um na foto, outro no botão - fazem o
   leitor de tela anunciar o mesmo case duas vezes. Um botão de verdade,
   com a área estendida por pseudo-elemento, resolve os dois. */
.ci-slide__link {
  margin-top: var(--sp-3);
}

/* O `::after` resolve contra o ancestral posicionado mais próximo, e o
   único posicionado no caminho é `.ci-slide`. Por isso o botão NÃO leva
   `position: relative`: ele o tornaria o próprio ancestral, e a área
   estendida cobriria só o botão. A régua de progresso continua
   clicável porque ela é irmã do palco e tem `z-index` próprio - o
   clique no passo troca de slide, não abre o case. */
.ci-slide__link::after {
  content: "";
  position: absolute;
  inset: 0;
  /* Acima da moldura da foto. Sem isto o `::after` continua atrás dela:
     a moldura é posicionada e vem DEPOIS no HTML, então pinta por cima
     de um pseudo-elemento sem camada própria - e o clique na foto, que é
     metade do banner, não abria o case. Um a menos que o `z-index: 2`
     dos controles, que precisam continuar recebendo o próprio clique. */
  z-index: 1;
}

/* ---------- os controles ----------
   Uma régua por slide, e a régua é o próprio relógio: ela preenche
   durante o intervalo e o preenchimento é a única indicação de que a
   troca vai acontecer. Ponto, número ou seta seriam um segundo desenho
   dizendo o que a régua já diz.

   São botões de verdade, com rótulo: quem navega por teclado precisa
   poder pular para o terceiro sem esperar doze segundos. */
.ci-banner__controles {
  position: absolute;
  bottom: 0;
  left: 0;
  z-index: 2;
  display: flex;
  gap: var(--sp-3);
  width: min(100%, 320px);
}

.ci-passo {
  flex: 1;
  position: relative;
  height: 2px;
  padding: 0;
  border: 0;
  background: var(--line);
  cursor: pointer;
}

/* Alvo de toque de 44px sem engordar a régua: a área invisível é do
   pseudo-elemento, o desenho continua com 2px. */
.ci-passo::before {
  content: "";
  position: absolute;
  inset: -21px 0;
}

.ci-passo i {
  position: absolute;
  inset: 0 auto 0 0;
  display: block;
  width: 0;
  background: var(--fg);
}

.ci-passo[aria-current="true"] i {
  width: 100%;
}

/* ============================================================
   ci-filtros
   Uma barra de uma linha, entre dois filetes: botão de filtros
   à esquerda, contagem de resultado à direita. O painel abre
   por baixo dela.

   Painel, e não pílulas soltas na barra: são vinte e três
   serviços - os mesmos dos submenus do header -, e vinte e três
   pílulas em linha viram um muro que empurra a grade para fora
   da primeira tela. Fechado, o número no botão diz quantos
   filtros estão ligados.
   ============================================================ */
.ci-filtros {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.ci-barra {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
  min-height: 64px;
}

.ci-abrir {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 0;
  border: 0;
  background: none;
  color: var(--fg);
  font-size: var(--fs-body);
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
}

/* O contador de filtros ativos. Zero é um estado, e ele fica escrito:
   um botão que só mostra o número quando há filtro faz a barra mudar de
   largura toda vez que alguém clica numa pílula. */
.ci-abrir__n {
  display: inline-grid;
  place-items: center;
  min-width: 22px;
  height: 22px;
  padding-inline: 0.4em;
  border-radius: var(--r-pill);
  background: var(--line);
  font-size: var(--fs-label);
  font-variant-numeric: tabular-nums;
}

.ci-abrir[aria-expanded="true"] .ci-abrir__n,
.ci-abrir__n.tem-filtro {
  background: var(--fg);
  color: var(--bg);
}

.ci-abrir__seta {
  width: 12px;
  height: 8px;
  transition: rotate var(--dur-base) var(--ease-out);
}

.ci-abrir[aria-expanded="true"] .ci-abrir__seta {
  rotate: 180deg;
}

.ci-conta {
  font-size: var(--fs-body);
  color: var(--fg-muted);
  font-variant-numeric: tabular-nums;
}

/* ---------- o painel ----------
   Abre e fecha com a linha `0fr → 1fr` da grade, que é a única forma de
   animar altura automática sem medir nada em JS. Fechado ele sai do
   documento por `inert` e por `visibility`: só a altura zero deixaria
   vinte e três botões alcançáveis por tabulação atrás de uma barra
   fechada. */
.ci-painel {
  display: grid;
  grid-template-rows: 0fr;
  visibility: hidden;
  transition:
    grid-template-rows var(--dur-base) var(--ease-out),
    visibility 0s linear var(--dur-base);
}

.ci-painel.is-aberto {
  grid-template-rows: 1fr;
  visibility: visible;
  transition:
    grid-template-rows var(--dur-base) var(--ease-out),
    visibility 0s;
}

.ci-painel__dentro {
  overflow: hidden;
}

.ci-painel__grupos {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-7);
  padding-block: var(--sp-6) var(--sp-5);
  border-top: 1px solid var(--line);
}

.ci-grupo__nome {
  display: flex;
  align-items: center;
  margin-bottom: var(--sp-4);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--fg-muted);
}

.ci-grupo__itens {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
}

.ci-pilula {
  display: inline-flex;
  align-items: center;
  padding: 0.62em 1.1em;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--fg);
  font-size: var(--fs-small);
  line-height: 1.15;
  text-align: left;
  cursor: pointer;
  transition:
    background-color var(--dur-base) var(--ease-out),
    color var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out);
}

.ci-pilula:hover {
  border-color: var(--fg);
}

/* Selecionada é preenchida, e não só contornada. Contorno mais grosso
   ou cor de texto diferente são diferenças que somem em tela de celular
   ao sol; preenchimento inverte a pílula inteira. */
.ci-pilula[aria-pressed="true"] {
  background: var(--fg);
  border-color: var(--fg);
  color: var(--bg);
}

.ci-painel__pe {
  padding-bottom: var(--sp-6);
}

/* O "Limpar filtros" E' PRETO CHEIO, e o que estava aqui antes era uma
   segunda copia do `.btn--ghost` - transparente, texto escuro, filete
   claro. Saiu junto com a classe na marcacao: com as duas em pe, tirar
   so' uma nao mudaria nada na tela, e a que ficasse ainda venceria por
   especificidade.

   PRETO E PILULA E' TAMBEM O DESENHO DA PILULA SELECIONADA logo acima,
   e e' o X que separa os dois. Sem ele, um botao cheio no pe do painel
   se leria como mais uma categoria - ligada. O icone diz que este
   desfaz, e nao que esta marcado. */

/* ============================================================
   ci-grade
   Os cartões. O objeto vem de scenes.css; daqui saem só a
   grade, o tamanho da moldura e o raio.
   ============================================================ */
.ci-grade-secao {
  padding-block: clamp(var(--sp-8), 8vh, var(--sp-9)) clamp(var(--sp-9), 11vh, var(--sp-10));
}

.ci-grade {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(var(--sp-6), 3.4vw, var(--sp-8)) clamp(var(--sp-5), 2.4vw, var(--sp-6));
  align-items: start;
}

/* Sem degrau na coluna do meio. Ele existia para dar desequilíbrio à
   grade, e o preço era alto demais: com o cartão de alturas variáveis
   (duas frentes ocupam duas linhas de olho, um cliente de nome longo
   quebra), o degrau somava-se à variação natural e a grade passava a
   ter quatro linhas de base diferentes na mesma fileira. Alinhada, a
   fileira é uma fileira, e a variação que sobra é só a do conteúdo.

   Quem dá o ritmo agora é `align-items: start` com a entrada em cascata:
   a linha inteira sobe junta, e não em degrau desenhado. */

/* A moldura da grade é mais alta que a da faixa e tem raio de janela, e
   não de objeto. O resto do cartão - capa, botão de hover, corpo - é o
   de scenes.css, sem uma linha reescrita. */
.ci-grade .case__frame {
  height: auto;
  aspect-ratio: 4 / 5;
  border-radius: var(--r-cartao);
}

/* O corpo do cartão foi escrito para a faixa da home, que corre sobre
   preto: ele fixa `--c-gray-on-dark` e `--c-line-dark` direto, sem
   passar por `--fg-muted` e `--line`. Sobre papel, o cinza dá 3.04:1 e
   a régua vira uma linha que não se vê. A correção é do índice, e não
   da faixa: quem mudou de chão foi o índice. */
.ci-grade .case__eyebrow {
  color: var(--fg-muted);
}

.ci-grade .case__eyebrow > span:not(:first-child) {
  border-left-color: var(--line);
}

/* As tags também foram escritas para a faixa escura: contorno e texto
   em `--c-line-dark` e `--c-gray-on-dark`, e o hover clareando para
   branco. Sobre papel, os três viram invisível, 3.04:1 e invisível de
   novo. */
.ci-grade .case__tags {
  border-top-color: var(--line);
}

.ci-grade .case__tag {
  border-color: var(--line);
  color: var(--fg-muted);
}

.ci-grade .case:hover .case__tag {
  border-color: var(--fg);
  color: var(--fg);
}

/* O resumo do resto. Ele não nomeia serviço nenhum, então não finge
   ser uma tag clicável: sem contorno, e no cinza do que acompanha. */
.ci-grade .case__tag--mais {
  border-color: transparent;
}

/* O cartão filtrado para fora sai da grade, e não fica transparente no
   lugar: um buraco no meio da grade é pior que a grade menor. */
.case[hidden] {
  display: none;
}

/* ---------- nada encontrado ----------
   Estado vazio com saída. Uma frase que diz o que aconteceu e um botão
   que desfaz - beco sem saída é o que transforma filtro em armadilha. */
.ci-vazio {
  display: none;
  justify-items: start;
  gap: var(--sp-5);
  padding-block: clamp(var(--sp-8), 10vh, var(--sp-9));
}

.ci-vazio.is-visivel {
  display: grid;
}

.ci-vazio p {
  font-size: var(--fs-body-l);
  line-height: 1.5;
  max-width: 42ch;
  color: var(--fg-muted);
}

/* ============================================================
   ci-fim
   O fechamento. Mesma peça das páginas de case: o preto entra,
   o convite fica sozinho, e o rodapé emenda sem costura.
   ============================================================ */
.ci-fim {
  padding-block: clamp(var(--sp-9), 11vh, var(--sp-10));
  background: var(--c-black);
  color: var(--c-white);
  --fg: var(--c-white);
  --fg-muted: var(--c-gray-on-dark);
  --line: var(--c-line-dark);
}

/* `.ci-fim__caixa` E `.ci-fim__frase` SAIRAM (25/08). Elas eram uma
   terceira versao do convite de fechamento - a pagina de case e a materia
   ja usavam `.cs__cta`/`.cs__cta-frase` -, e a versao daqui era a unica em
   corpo de texto e em cinza. O bloco passou a usar a peca compartilhada,
   que subiu para `layout.css`. Fica o nome registrado para quem
   reencontrar as classes num rascunho.

   `.ci-fim` FICA: ela e' a secao preta, e o que ela declara e' o tema
   (os quatro tokens) mais a inversao do botao. Isso e' desta pagina. */

.ci-fim .btn {
  --btn-bg: var(--c-white);
  --btn-fg: var(--c-black);
}

.ci-fim .btn:hover {
  --btn-bg: var(--c-yellow);
  --btn-fg: var(--c-black);
}

/* A REGRA DO RODAPÉ ESCURO SUBIU PARA `layout.css` (25/08), junto com as
   das outras três páginas de chão claro. Eram quatro cópias da mesma
   decisão e duas estavam incompletas - o porquê está lá. */

/* ============================================================
   estado inicial das entradas
   Declarado no CSS e desfeito pelo JS. Ao contrário, o conteúdo
   pisca visível antes de sumir para entrar.
   ============================================================ */
.js .ci-grade > .case {
  opacity: 0;
  transform: translateY(28px);
}

/* ============================================================
   telas menores
   Toda grade multi-coluna declara aqui como colapsa. Nenhuma
   confia em "o navegador resolve".
   ============================================================ */
@media (max-width: 1024px) {
  .ci-grade {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 900px) {
  .ci-painel__grupos {
    grid-template-columns: 1fr;
    gap: var(--sp-6);
  }

  /* Alvo de toque de 44px. Em 35px a pílula era confortável no mouse e
     apertada no dedo, e é no dedo que vinte e três delas vão ser
     usadas. */
  .ci-pilula {
    min-height: 44px;
  }

  /* O banner empilha: foto em cima, texto embaixo. A foto primeiro
     porque é ela que faz parar - e porque, empilhada, ela deixa de
     disputar largura com o texto e passa a ter a tela inteira. */
  .ci-banner,
  .ci-banner__palco,
  .ci-slide {
    grid-template-columns: 1fr;
  }

  .ci-banner__palco {
    display: block;
    min-height: 0;
  }

  .ci-slide {
    position: absolute;
    inset: 0;
    grid-auto-rows: min-content;
    align-content: start;
    gap: var(--sp-5);
  }

  /* Empilhado, o palco não tem mais uma altura de coluna para herdar:
     ela passa a ser a do slide mais alto, medida pelo JS. O valor de
     partida vale para o primeiro quadro e para a página sem JS. */
  .ci-banner__palco {
    min-height: var(--altura-palco, 560px);
  }

  /* A foto sobe para o topo. No HTML o texto vem primeiro porque é ele
     que dá sentido à imagem para quem lê por leitor de tela; na tela
     estreita, é a foto que faz parar o dedo. `order` troca só a ordem
     visual, e a de leitura fica onde estava. */
  .ci-slide__moldura {
    order: -1;
    height: clamp(240px, 42vh, 360px);
  }

  .ci-slide__texto {
    padding-bottom: var(--sp-7);
  }

  .ci-banner__controles {
    width: 100%;
  }
}

@media (max-width: 560px) {
  .ci-grade {
    grid-template-columns: 1fr;
  }

  .ci-filtros__linha {
    align-items: flex-start;
  }
}

/* ============================================================
   sem movimento
   Não é atenuação, é desligamento: nada gira sozinho, nada
   desliza, e o carrossel vira um conjunto de botões que troca a
   peça na hora.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .ci-banner:not(.is-viva) .ci-slide,
  .ci-banner:not(.is-viva) .ci-slide.is-ativo {
    transition: none;
  }

  .ci-slide__moldura img,
  .ci-pilula {
    transition: none;
  }

  .js .ci-grade > .case {
    opacity: 1;
    transform: none;
  }
}
