/* =============================================================================
   TAKA DESIGN — 4ª DOBRA: SERVIÇOS
   -----------------------------------------------------------------------------
   Carregue DEPOIS de passage.css e about.css: este arquivo consome
   --narrative-axis e a variante .spectrum-rule--v declaradas em passage.css.

   Tudo aqui vem do Design System PRISMA. Nenhum token novo de cor, tipografia
   ou motion é criado:
     · .spectrum-rule / .spectrum-rule--v  → a costura, o nó e o indicador
     · .badge badge-pill badge-violet      → o cabeçalho numerado do DS
                                             ("0X · Nome da seção"); violeta é
                                             o próximo da sequência que o
                                             próprio DS usa depois do índigo
     · .card / .card-neon / .spotlight     → os três serviços
     · .t-h2 / .t-h3 / .t-h6 / .t-body / .t-body-sm / .t-caption / .t-label
     · .btn btn-neon btn-lg                → o encerramento comercial
     · .aurora                             → a atmosfera que toda dobra carrega
     · --ds-void / --ds-r-* / --ds-ease    → superfície, raios e curva

   O RITMO DA DOBRA
   ----------------
   Hero = impacto · Confiança = precisão · Sobre = humano · Serviços = produto.
   Depois de uma dobra editorial e silenciosa, o nível de interação volta a
   subir — mas em cima de uma sequência FINITA (três produtos), que é
   exatamente o caso em que prender o viewport se justifica.

     costura → cabeçalho editorial → experiência presa (3 estados) → solta →
     adicionais | suporte → CTA

   A COSTURA COM A DOBRA ANTERIOR
   ------------------------------
   O Sobre encerra com a régua espectral abrindo os diferenciais: ali a linha
   partiu DO eixo narrativo para as duas bordas. Aqui o gesto é o inverso — a
   régua se forma nas duas bordas da página e CONVERGE para o mesmo eixo, onde
   um nó acende e deixa cair um fio vertical. Mesmo vocabulário (a linha de
   1px do DS, o nó com halo índigo, o eixo narrativo), gesto invertido: é a
   evolução pedida, não a repetição da transição anterior.

   O fio que desce é a última aparição do eixo narrativo até aqui: ele se
   apaga (máscara do próprio componente) enquanto a composição se recentra
   para a experiência, que é simétrica por natureza. A entrega de um eixo para
   o outro é o que abre o espaço tridimensional dos cartões.

   DOIS ESTADOS DE LAYOUT
   ----------------------
   estático (padrão)  Os três serviços em grade de três colunas, lado a lado,
                      completos e legíveis. É o que o navegador desenha sem JS,
                      sem GSAP, com o CDN fora do ar ou com movimento reduzido.
   ao vivo (.is-live) services.js confirma GSAP + movimento permitido: o trilho
                      ganha altura, o palco gruda no topo e a grade vira um
                      baralho em perspectiva, com um cartão ativo por vez.

   Sticky em vez de `pin: true` do ScrollTrigger — a mesma escolha de
   passage.css, pelos mesmos motivos: nenhum pin-spacer injetado no fluxo,
   nenhum risco de salto no refresh, reversão com uma única classe e, aqui
   especialmente, ZERO interferência na detecção de direção de scroll do
   header (header.js lê `scrollY` e a geometria real do H2 do Sobre — nada
   disso muda com sticky).
   ============================================================================= */

/* -----------------------------------------------------------------------------
   Trilho da seção
   -------------------------------------------------------------------------- */
.services {
  /* Vão que a costura atravessa antes do cabeçalho. */
  --svc-lead: clamp(3rem, 7vh, 5.5rem);
  /* Respiro entre o cabeçalho e a entrada da experiência. Encurtado a partir
     de medição: o baralho agora CHEGA dentro desse vão (o gatilho B dispara
     com o deck acima da dobra, ver services.js), então o vão deixou de ser
     uma espera e passou a ser o espaço em que a experiência se apresenta. */
  --svc-gap: clamp(1.75rem, 4.5vh, 3.5rem);
  --svc-tail: clamp(3rem, 8vh, 5.5rem);

  /* Curso de rolagem consumido pela experiência, além dos 100vh do palco.
     210vh → 150vh depois de medir o percurso quadro a quadro em 1440 × 900: as
     duas TRAVESSIAS ficaram praticamente do mesmo tamanho (605px → 567px, que
     é o que dá a sensação de massa se deslocando), e a economia inteira saiu
     dos platôs, que somavam 681px de scroll em que nada mudava. Ver a nota
     sobre a repartição do curso em services.js. */
  --svc-travel: 150vh;

  /* Largura do cartão. É ela que define o alcance do baralho: os laterais são
     deslocados em PORCENTAGEM da própria largura (ver services.js), então a
     composição inteira é responsiva sem nenhuma medida em JS.

     Medido em 1440 × 900, o cartão ativo tinha 432 × 325 num palco de 900px:
     30% da largura e 36% da altura da janela. 34vw leva a 490 × ~365 (+13%),
     dentro da faixa pedida, e o afastamento dos laterais cresce junto por ser
     percentual da própria largura — o baralho ganha presença SEM perder a
     folga das bordas (medido: 112px livres de cada lado em 1440).

     O teto de 38rem só entra de ~1790px para cima, onde 34vw satura; abaixo
     disso quem manda é o vw, então notebook e tablet acompanham sozinhos. */
  --svc-card-w: clamp(19rem, 34vw, 38rem);

  position: relative;
  isolation: isolate;
  overflow: clip;                    /* contém o sangramento da .aurora e do 3D */
  background: var(--ds-void);
  padding-bottom: var(--svc-tail);
  scroll-margin-top: var(--header-h);
}

/* --- Profundidade da dobra inteira ------------------------------------------
   A CAUSA, medida — não suposta: o brilho que dá profundidade ao palco
   (.services__ambient, a seguir) e o número monumental (.services__ghost)
   vivem os dois dentro de .services__stage, que só existe durante o pin e tem
   overflow:hidden. Capturado em 1440 × 900: no y exato em que .services__head
   termina e .services__stage começa (431px), o brilho e o "01" nascem com uma
   ARESTA RETA — CSS puro, não ilusão de ótica. Acima da aresta, .services__head
   não carrega nenhuma atmosfera própria, só esta camada de base, que no ponto
   de corte contribuía com fração de alfa irrelevante. É exatamente o que os
   itens 1 e 2 do briefing descreveram, e o mesmo corte se repete na saída,
   entre o fim do palco e "Adicionais disponíveis".

   Esta camada é a ÚNICA da dobra que cobre a seção inteira sem clip nenhum —
   por isso é ela, e não outro elemento por cima, que precisa carregar a
   continuidade de verdade.

   REGRESSÃO MEDIDA E REVERTIDA — o gradiente "topo" que este comentário
   descrevia (centrado em 50% 3%, bem em cima da costura) resolvia o corte,
   mas introduziu outro defeito: o Chromium aplica dither anti-banding em
   gradientes radiais grandes e sutis, mais forte perto do PRÓPRIO centro do
   gradiente (onde a cor muda mais rápido por pixel). Centrar um gradiente
   exatamente atrás do fio vertical (.services__seam-drop, um traço de 1px,
   semitransparente, animado) expôs esse ruído através dele — visível como um
   tremor de ±2-4/255 a cada linha, medido pixel a pixel.

   Isolado por eliminação: a versão SEM o gradiente "topo" mede no piso de
   ruído do próprio navegador (~0.85, idêntico a não ter gradiente nenhum); o
   "topo" sozinho já explica a maior parte do salto (~1.36); os quatro
   gradientes somados chegavam a ~1.82 — mais que o dobro do piso. Por isso
   ele não volta: quem carrega a continuidade "logo após a costura" agora é
   só a CAUDA distante do campo do meio (abaixo), cujo centro nunca esteve
   perto o bastante do fio para expor esse ruído — confirmado pela mesma
   medição na versão anterior a esta dobra inteira ter sido criada.

   O que resta:
     1. o campo grande do meio, um pouco mais alto e um pouco mais forte que
        antes (22% em vez de 24%, .062 em vez de .058) para compensar a perda
        do "topo" sem reintroduzir o problema — ponte entre cabeçalho e
        início do pin, e a única fonte de presença logo após a costura;
     2. dois campos colados no CTA, na paleta do próprio .btn-neon
        (índigo-profundo → violeta → rosa) e enviesados para a direita — onde
        o botão mora no desktop —, fazendo o glow do botão "contaminar" a
        atmosfera ao redor sem nenhum elemento novo — item 6.

   Nenhum token novo: índigo, violeta, rosa e ciano são os mesmos quatro do
   --ds-spectrum e do próprio --ds-indigo-deep/--ds-violet/--ds-pink que o
   .btn-neon já usa. Cada parada final é `rgba(cor, 0)` e não `transparent`,
   pelo motivo documentado em passage.css — nenhum navegador passa por um
   cinza no meio da interpolação. */
.services::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    /* O campo grande, ponte entre cabeçalho e início do pin — e agora também
       a única fonte de presença logo após a costura (ver a nota acima). */
    radial-gradient(125% 60% at 50% 22%,
      rgba(99, 102, 241, .062), rgba(99, 102, 241, 0) 68%),
    radial-gradient(95% 46% at 10% 72%,
      rgba(168, 85, 247, .04), rgba(168, 85, 247, 0) 70%),
    /* CTA — a paleta do próprio botão, enviesada para a direita (item 6). */
    radial-gradient(85% 42% at 88% 97%,
      rgba(168, 85, 247, .05), rgba(168, 85, 247, 0) 70%),
    radial-gradient(58% 30% at 92% 99%,
      rgba(236, 72, 153, .042), rgba(236, 72, 153, 0) 68%);
}

/* -----------------------------------------------------------------------------
   A costura — a régua que converge para o eixo narrativo
   -----------------------------------------------------------------------------
   Duas metades da mesma .spectrum-rule, cada uma crescendo da sua borda em
   direção ao eixo. A máscara do componente é substituída em cada metade para
   que a ponta EXTERNA se dissipe (nasce do nada, na margem da página) e a
   ponta INTERNA fique sólida — é ali que as duas se encontram.
   -------------------------------------------------------------------------- */
.services__seam {
  position: relative;
  z-index: 1;
  height: 1px;
  pointer-events: none;
}

.services__seam-half {
  position: absolute;
  top: 0;
  height: 1px;
}
/* `display: block` não é cosmético: .spectrum-rule declara height/width mas não
   display, e aqui o componente está num <span>. Inline, largura e altura são
   ignoradas e a régua simplesmente não é pintada — medido, o que aparecia era
   só o halo do nó (que mora num elemento absoluto, portanto blocado). Vale
   para todas as instâncias em <span> desta dobra; nas variantes verticais o
   próprio .spectrum-rule--v já resolve isso. */
.services__seam-half > .spectrum-rule {
  display: block;
  height: 1px;
}

.services__seam-half--l {
  left: 0;
  width: var(--narrative-axis);
  transform-origin: 0% 50%;
}
.services__seam-half--l > .spectrum-rule {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 16%, #000 100%);
          mask-image: linear-gradient(90deg, transparent, #000 16%, #000 100%);
}

.services__seam-half--r {
  left: var(--narrative-axis);
  right: 0;
  transform-origin: 100% 50%;
}
.services__seam-half--r > .spectrum-rule {
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 84%, transparent);
          mask-image: linear-gradient(90deg, #000 0%, #000 84%, transparent);
}

/* --- O nó: o ponto onde as duas metades se encontram ------------------------
   Mesma construção de .trust__node e .about__node — duas camadas, porque a
   máscara de .spectrum-rule recortaria o halo se ele morasse no mesmo
   elemento. Nenhuma cor nova: o halo índigo é o mesmo dos badges do DS. */
.services__seam-node {
  --svc-node-w: clamp(2.5rem, 4vw, 4.5rem);
  position: absolute;
  top: 0;
  left: var(--narrative-axis);
  z-index: 2;
  width: var(--svc-node-w);
  height: 1px;
  margin-left: calc(var(--svc-node-w) / -2);
}
.services__seam-node > .spectrum-rule {
  display: block;
  height: 1px;
  opacity: 1;
  box-shadow: 0 0 18px -4px rgba(99, 102, 241, .85);
}
.services__seam-node::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 320%;
  height: 1.5rem;
  translate: -50% -50%;
  background: radial-gradient(closest-side, rgba(99, 102, 241, .3), transparent 100%);
}

/* --- O fio que cai do nó ----------------------------------------------------
   Atravessa o vão do cabeçalho e se apaga: a máscara própria (de sólido para
   transparente) é o gesto de entrega — o eixo narrativo, que conduziu as três
   primeiras dobras, cede lugar ao eixo central e simétrico da experiência.
   Não some por opacidade: se dissipa, que é diferente. */
.services__seam-drop {
  position: absolute;
  top: 0;
  left: var(--narrative-axis);
  width: 1px;
  height: calc(var(--svc-lead) + var(--svc-gap) * .55);
  translate: -50% 0;
  transform-origin: 50% 0%;
}
.services__seam-drop > .spectrum-rule--v {
  height: 100%;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 34%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 0%, #000 34%, transparent 100%);
}

/* -----------------------------------------------------------------------------
   Cabeçalho editorial
   -----------------------------------------------------------------------------
   Primeiro o usuário entende ONDE chegou; só depois a experiência começa. Por
   isso o cabeçalho tem o vão inteiro para si — nada de H2 e carrossel
   disputando a mesma tela.
   -------------------------------------------------------------------------- */
.services__head {
  position: relative;
  z-index: 2;
  padding-top: var(--svc-lead);
  padding-bottom: var(--svc-gap);
}

.services__eyebrow { margin-bottom: clamp(1rem, 2.1vh, 1.5rem); }

.services__headline {
  margin: 0;
  color: #fff;
  max-width: 22ch;
}

/* Revelação por linha, mesmo princípio de .split-line do DS (invólucro com
   overflow, filho em bloco). Classe própria porque .split-line > span carrega
   `animation … both`, que venceria o estilo inline do GSAP. O padding
   compensa as descendentes que o overflow cortaria; a margem negativa
   devolve o espaço ao fluxo. */
.services__line {
  display: block;
  overflow: hidden;
  padding-bottom: .18em;
  margin-bottom: -.18em;
}
.services__line > span {
  display: block;
  text-wrap: balance;
}

/* -----------------------------------------------------------------------------
   A experiência — trilho e palco
   -------------------------------------------------------------------------- */
.services__experience { position: relative; }

.services.is-live .services__experience {
  min-height: calc(100vh + var(--svc-travel));
  min-height: calc(100svh + var(--svc-travel));
}

.services__stage {
  position: relative;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: clamp(1.75rem, 4vh, 3rem);
}

.services.is-live .services__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  /* O palco é a moldura da experiência: o que passar da borda em perspectiva
     não deve empurrar a página nem aparecer sobre as sub-seções. */
  overflow: hidden;
}

/* -----------------------------------------------------------------------------
   Atmosfera do palco
   -----------------------------------------------------------------------------
   "Toda dobra segue o mesmo esqueleto: régua espectral, atmosfera animada ao
   fundo, cabeçalho e conteúdo" — design_system.html.

   Aqui a atmosfera tem uma função a mais: acompanhar o cartão ativo. São três
   campos radiais, um por serviço, e services.js escreve --svc-a1/2/3 com a
   proximidade de cada cartão do centro. O alfa máximo é .05 — o mesmo teto de
   .trust__ambient e .about__ambient. Não é holofote: no pico somado o fundo
   sai de #020205 para algo em torno de #0A0A14, um passo de profundidade e
   não de cor.

   Cada gradiente termina em `rgba(cor, 0)` e não em `transparent`, pelo mesmo
   motivo documentado em passage.css: nenhum navegador passa por um cinza no
   meio da interpolação.
   -------------------------------------------------------------------------- */
.services__ambient {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  /* A CAUSA do corte, corrigida na origem. .services__stage tem
     overflow:hidden (precisa ter: é o que contém o sangramento do 3D do
     baralho), e este elemento cobre o palco inteiro — sem a máscara, o topo e
     a base do brilho terminam exatamente na borda do palco, com o alfa que
     tinham naquele ponto, e não em zero. Medido: em 1440 × 900, a aresta
     nasce com uma linha reta visível bem no y em que .services__head termina.

     A máscara resolve onde o problema realmente mora — dentro do elemento
     clipado — em vez de tentar disfarçar por cima com mais um gradiente na
     camada de baixo (isso .services::before também ganhou, mas como
     PONTE, não como remendo). Fade simétrico nos dois extremos: entrada e
     saída do pin recebem o mesmo tratamento. */
  -webkit-mask-image: linear-gradient(180deg,
      transparent 0%, #000 16%, #000 84%, transparent 100%);
          mask-image: linear-gradient(180deg,
      transparent 0%, #000 16%, #000 84%, transparent 100%);
}

/* O campo em que o cartão ativo existe. Uma única elipse muito maior que o
   baralho (76% × 84% do palco, contra 38% × 46% dos campos de acento), de alfa
   único e baixo. Grande e difusa a esse ponto ela não tem borda perceptível:
   não se lê como um círculo de luz, se lê como o fundo tendo profundidade
   naquela região. É ela que separa os cartões do vazio.

   --svc-cx é o único parâmetro que o serviço ativo move: services.js desloca o
   centro entre 46% e 54% conforme o baralho avança. Oito por cento de curso
   num gradiente sem borda visível é deslocamento subliminar por construção —
   não há como ler como "o fundo mudou de cor". */
.services__ambient::before {
  content: '';
  position: absolute;
  inset: -12% -8%;
  background: radial-gradient(76% 84% at var(--svc-cx, 50%) 47%,
      rgba(99, 102, 241, .075), rgba(99, 102, 241, 0) 72%);
}

/* Os campos de acento, um por serviço, modulados pela proximidade do centro
   (--svc-a1/2/3). Mantêm o teto de .05 de alfa de .trust__ambient e
   .about__ambient; o que mudou foi só o ALCANCE — 38% × 46% deixava o campo
   menor que o próprio baralho depois do aumento de escala, e um campo menor
   que o objeto que ele ilumina vira mancha. */
.services__ambient::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(62% 58% at var(--svc-cx, 50%) 50%,
      rgba(99, 102, 241, calc(.05 * var(--svc-a1, 1))), rgba(99, 102, 241, 0) 72%),
    radial-gradient(62% 58% at var(--svc-cx, 50%) 50%,
      rgba(168, 85, 247, calc(.05 * var(--svc-a2, 0))), rgba(168, 85, 247, 0) 72%),
    radial-gradient(62% 58% at var(--svc-cx, 50%) 50%,
      rgba(34, 211, 238, calc(.042 * var(--svc-a3, 0))), rgba(34, 211, 238, 0) 72%);
}

.services__aurora {
  inset: auto -12% -14% -12%;
  height: clamp(18rem, 42vh, 30rem);
  opacity: .14;
  filter: blur(100px);
}

/* -----------------------------------------------------------------------------
   Textura tipográfica
   -----------------------------------------------------------------------------
   O palco preso tem 100vh e o baralho ocupa o miolo dele — medido, sobravam
   cerca de 290px vazios acima e abaixo. Esta camada dá matéria a esse vazio
   sem acrescentar UMA palavra de conteúdo: é o mesmo índice que já está no
   cartão, em escala de textura.

   Sem componente novo no DS: .t-display é a escala máxima que ele define, e o
   número herda exatamente a mesma família, peso e tracking dela — só o
   `font-size` sai da escala, porque aqui a função não é tipográfica, é de
   fundo. O branco a .026 fica abaixo do primeiro degrau de superfície do
   próprio DS (rgba(255,255,255,.025) do .card), o que garante que ele nunca
   compete com a leitura.

   Os três números ficam sobrepostos na mesma célula e services.js cruza a
   opacidade deles: a troca acompanha o scrub em vez de piscar num limiar.
   Cortado pela base — `overflow: hidden` do palco faz o recorte — para ler
   como marca-d'água contínua e não como um número centralizado.
   -------------------------------------------------------------------------- */
.services__ghost {
  position: absolute;
  z-index: 0;
  left: 0;
  right: 0;
  /* Mais alto que antes (22% → 15%): uma fatia do número agora interage com
     a base do cabeçalho — item 8 —, mas quem garante que isso não vira outra
     aresta reta é a máscara logo abaixo, não a posição. */
  top: 15%;
  margin: 0;
  /* Só existe ao vivo: no estado estático os três serviços estão na tela ao
     mesmo tempo e um "02" gigante ao fundo não descreveria nada. */
  display: none;
  justify-items: center;
  pointer-events: none;
  font-family: 'Inter', system-ui, sans-serif;
  font-weight: 600;
  /* Monumental, mas um degrau abaixo: reduzido de 46rem/78vh para 40rem/70vh
     e a cor de .021 para .015. Hierarquia do item 8 — H2, depois a
     experiência, só depois o número — e medido, a 46rem/78vh ele competia
     com o baralho em vez de servir de textura atrás dele. */
  font-size: clamp(13rem, 70vh, 40rem);
  line-height: .72;
  letter-spacing: -0.06em;
  color: rgba(255, 255, 255, .015);
  translate: 0 -50%;
  /* BUG MEDIDO — a aresta reta sobreviveu à primeira correção. A máscara
     dissipava o topo em PORCENTAGEM da própria altura deste elemento (uma
     caixa cuja altura depende do font-size, que depende de vh), mas quem
     corta é a borda de .services__stage — uma referência geométrica
     TOTALMENTE INDEPENDENTE (top:15% da altura do PALCO). As duas só
     coincidiam por acidente no viewport em que a correção anterior foi
     testada; capturado num viewport mais baixo (1440 × 539): a caixa deste
     elemento nasce 55px acima do palco, e a rampa de dissipação (20% de
     ~272px ≈ 54px) TERMINAVA A 0.6PX do corte — ou seja, chegava perto do
     palco já quase 100% opaca. Resultado: a mesma aresta reta de antes, só
     que 1px mais abaixo.

     A correção usa uma distância FIXA em pixel, não percentual — porque só
     um valor absoluto pode ficar desacoplado da altura variável desta caixa
     E ainda cobrir o "sangramento" acima do palco em qualquer viewport.
     Medido o sangramento em quatro alturas (539 a 1080px): 55 a 92px. 240px
     de rampa cobre esse intervalo com folga em qualquer tela razoável — o
     número está praticamente transparente bem antes de chegar à borda que
     o corta, então não sobra aresta nenhuma para cortar.

     A base continua em porcentagem: o rodapé desta caixa nunca chega perto
     do fim do palco (sobra >300px de margem no pior caso testado), então a
     dissipação ali pode continuar servida pela própria altura do elemento,
     entregando o espaço ao indicador de progressão como já fazia. */
  -webkit-mask-image: linear-gradient(180deg,
      transparent 0, #000 240px, #000 52%, transparent 96%);
          mask-image: linear-gradient(180deg,
      transparent 0, #000 240px, #000 52%, transparent 96%);
}
.services.is-live .services__ghost { display: grid; }

.services__ghost > span {
  grid-area: 1 / 1;
  opacity: var(--svc-g, 0);
}

/* -----------------------------------------------------------------------------
   O baralho
   -----------------------------------------------------------------------------
   ESTÁTICO — três colunas, lado a lado. Nenhuma perspectiva, nenhum
   empilhamento: sem JS os três serviços simplesmente existem, completos.

   O deck repete a geometria de .container (max-width + gutter) em vez de ser
   embrulhado por um: ao vivo ele precisa poder centralizar UMA coluna do
   tamanho do cartão, e um container em volta seria uma caixa a mais entre a
   perspectiva e os slots.
   -------------------------------------------------------------------------- */
.services__deck {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--app-container-max);
  margin-inline: auto;
  padding-inline: var(--app-gutter);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1rem, 1.6vw, 1.5rem);
}

.services__slot { display: flex; }

/* AO VIVO — os três ocupam a MESMA célula da grade. Empilhamento por
   `grid-area`, e não por `position: absolute`: assim a altura da célula
   continua sendo a do cartão mais alto (os três ficam iguais, sem altura
   fixa em lugar nenhum) e nada precisa ser medido em JS. */
.services.is-live .services__deck {
  grid-template-columns: var(--svc-card-w);
  justify-content: center;
  gap: 0;
  padding-inline: 0;
  perspective: 1500px;
  perspective-origin: 50% 50%;
}
.services.is-live .services__slot {
  grid-area: 1 / 1;
  /* Sem transição: quem escreve a matriz é o GSAP, quadro a quadro, a partir
     do progresso do scroll. Uma transição aqui somaria um segundo atraso ao
     scrub e o movimento deixaria de acompanhar o dedo. */
  transition: none;
}

/* -----------------------------------------------------------------------------
   Cartão de serviço
   -----------------------------------------------------------------------------
   .card do DS. Cartões EDITORIAIS de serviço, não cartões de pricing: sem
   tabela, sem checklist, sem ícone, sem preço, sem botão em cada um. A
   hierarquia é a mesma numerada que o eyebrow e o Sobre já usam.

   O GSAP transforma o SLOT, nunca o cartão: assim o `transform` de :hover que
   o .card do DS declara continua funcionando, sem disputar matriz com nada.
   -------------------------------------------------------------------------- */
.services__card {
  flex: 1;
  display: grid;
  align-content: start;
  /* O respiro interno sobe junto com a largura, e não é detalhe: alargar o
     cartão sozinho reduz a quebra de linha, então ele fica mais largo E mais
     baixo — medido, a área caía. Crescer nos dois eixos é o que produz a
     presença pedida. Em 1440 o conjunto vai de 432 × 325 para 490 × 323:
     +13% de largura com a altura preservada. */
  padding: clamp(1.5rem, 3.2vw, 3rem);

  /* SUPERFÍCIE OPACA — não é preferência estética, é requisito da composição.
     O .card do DS descansa em rgba(255,255,255,.025), pensado para uma grade
     em que os cartões nunca se sobrepõem. Aqui eles se sobrepõem o tempo
     todo, e um cartão translúcido deixa o texto do cartão de trás atravessar
     o da frente — medido em 1440 e em 390: as três descrições liam
     simultaneamente por cima umas das outras, ilegíveis.

     A composição usada é a do .glass-panel do próprio DS (o gradiente branco
     a 165° de components.css) sobre --ds-surface, que é justamente o token que
     o DS documenta como "neutro · cartões". Nenhuma cor nova: o que muda é
     que a base deixa de ser transparente.

     `background-color` + `background-image` separados, e não a abreviação:
     .card já declara transição em background-color, e mantê-los separados
     preserva essa transição de hover do DS intacta. */
  background-color: var(--ds-surface);
  background-image: linear-gradient(165deg,
      rgba(255, 255, 255, .075) 0%,
      rgba(255, 255, 255, .03) 45%,
      rgba(255, 255, 255, .012) 100%);
  /* Bordas na mesma gramática do .glass-panel: topo e esquerda um degrau mais
     claros, que é o que dá a leitura de vidro iluminado de cima. */
  border-color: rgba(255, 255, 255, .08);
  border-top-color: rgba(255, 255, 255, .16);
  border-left-color: rgba(255, 255, 255, .12);
}

/* Presença vertical em janelas altas. A largura satura no teto do clamp (o
   comprimento de linha tem limite editorial), mas a ALTURA do cartão é sempre
   ditada pelo texto — então numa janela de 1440px de altura o baralho voltava
   a ocupar 22% do palco e a se perder no vazio, exatamente o problema que o
   refinamento veio corrigir.

   `min-height`, e não `height`: é um piso, não uma medida. Onde o conteúdo já
   é mais alto que ele, nada muda — medido, 1440 × 900 (323px naturais contra
   um piso de 306px) e 1280 × 800 ficam intocados, e só janelas altas entram
   na conta. O respiro extra assenta abaixo do texto por causa do
   `align-content: start`, que é o mesmo lugar onde o cartão já respira.

   Só a partir de 900px: no compacto o cartão ocupa 84vw e já é o objeto
   dominante da tela — um piso de altura ali só criaria vão interno.

   O teto de 23rem DENTRO do piso não é arbitrário: acima dele o cartão passa
   a crescer mais rápido que o próprio texto e o respiro interno vira vão. Foi
   medido em 2560 × 1440 — com o piso solto em 34vh o cartão ia a 480px para
   um conteúdo de 317px, e os 163px sobrando abaixo do texto eram a mesma área
   morta de antes, agora dentro do cartão. Com o teto, a sobra fica em ~50px
   em 1920 e em 2560: respiro, não vazio. */
@media (min-width: 900px) {
  .services.is-live .services__card { min-height: min(34vh, 23rem); }
}

/* O :hover do .card troca `background` inteiro por uma cor translúcida, o que
   devolveria a transparência justamente no cartão ativo. Aqui ele passa a
   trocar só a intensidade, sobre a superfície opaca — --ds-surface-2 é o
   passo acima que o próprio DS define. */
.services__card:hover {
  background-color: var(--ds-surface-2);
  background-image: linear-gradient(165deg,
      rgba(255, 255, 255, .11) 0%,
      rgba(255, 255, 255, .05) 45%,
      rgba(255, 255, 255, .02) 100%);
}
.services__card > :not(.services__card-glow):not(.services__card-veil) {
  position: relative;
  z-index: 2;
}

/* Véu de profundidade. Reduz o CONTRASTE do cartão inativo sem desfoque —
   blur em três cartões grandes custaria caro e prejudicaria justamente a
   legibilidade que o briefing pede para preservar. services.js escreve
   --svc-veil com a distância do centro.

   z-index ACIMA do conteúdo (3 contra 2), e não abaixo: um véu sob o texto
   escureceria só a superfície e deixaria a tipografia dos cartões laterais no
   mesmo branco do cartão ativo — medido, era exatamente o que acontecia. É o
   cartão inteiro que recua, não o fundo dele.

   O véu é a ÚNICA ferramenta de escurecimento dos laterais que fica dentro do
   cartão. A alternativa óbvia — baixar a opacidade do slot — foi medida e
   descartada: com o slot a 88%, o cartão de trás atravessava o da frente
   (título e descrição do Institucional liam por cima do Premium). Um cartão
   que se sobrepõe a outro precisa ser opaco; ver a nota em services.js. */
.services__card-veil {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: var(--ds-void);
  opacity: var(--svc-veil, 0);
}

/* Glow espectral do cartão. Mesmo blob de acento que o DS documenta para a
   variante .card-neon (`-top-6 -right-6 w-32 h-32 bg-indigo-500/25
   blur-[60px]`), aqui modulado pela posição: só o cartão ativo o carrega
   inteiro. Elemento real e não pseudo porque .spotlight já ocupa o ::before
   do cartão e .card-neon o ::after. */
.services__card-glow {
  position: absolute;
  z-index: 0;
  top: -1.5rem;
  right: -1.5rem;
  width: 9rem;
  height: 9rem;
  border-radius: 50%;
  background: rgba(99, 102, 241, .22);
  filter: blur(60px);
  pointer-events: none;
  opacity: var(--svc-glow, 1);
}
/* O serviço intermediário é o principal comercialmente: o acento dele é
   violeta e um passo mais presente. Discreto — em repouso .card-neon é
   idêntico a .card, a linha espectral do topo só acende no hover. */
.services__card--lead .services__card-glow {
  background: rgba(168, 85, 247, .26);
}

.services__card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: clamp(1.25rem, 3vh, 2rem);
}

.services__card-index {
  margin: 0;
  color: rgba(255, 255, 255, .3);
}

.services__card-title {
  margin: 0 0 .875rem;
  color: #fff;
  text-wrap: balance;
}

/* Prazo em .t-h6 — Space Mono 700, caixa-alta, tracking .18em: o tratamento
   técnico que o DS reserva para dados e rótulos, o mesmo da Barra de
   Confiança. O traço espectral curto no lugar do bullet é o mesmo recurso de
   .about__caption: a linha da dobra, em escala mínima. */
.services__card-term {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin: 0 0 clamp(1.125rem, 2.6vh, 1.625rem);
  color: rgba(255, 255, 255, .55);
}
.services__card-term::before {
  content: '';
  flex: none;
  width: 1.5rem;
  height: 1px;
  background: var(--ds-spectrum);
  background-size: 300% 100%;
  animation: spectrum-slide 11s linear infinite;
  opacity: .85;
}

.services__card-desc {
  margin: 0 0 clamp(.75rem, 1.8vh, 1.125rem);
  color: rgba(255, 255, 255, .62);
  text-wrap: pretty;
}

.services__card-note {
  margin: 0;
  color: rgba(255, 255, 255, .38);
  text-wrap: pretty;
}

/* -----------------------------------------------------------------------------
   Indicador de progressão
   -----------------------------------------------------------------------------
   Existe só no estado ao vivo: parado, "01 / 03" não descreveria nada — os
   três serviços estão na tela ao mesmo tempo.

   Nada de pagination dots: o indicador é a própria .spectrum-rule avançando
   sobre um trilho, que é a linguagem que o site usa desde a primeira dobra, e
   o contador em Space Mono, que é o tratamento técnico do DS.
   -------------------------------------------------------------------------- */
.services__progress {
  display: none;
  position: relative;
  z-index: 1;
  align-items: center;
  gap: clamp(.875rem, 2vw, 1.5rem);
}
.services.is-live .services__progress { display: flex; }

.services__counter {
  margin: 0;
  color: rgba(255, 255, 255, .55);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.services__counter-total,
.services__counter-sep { color: rgba(255, 255, 255, .26); }

.services__rail {
  position: relative;
  width: clamp(5rem, 14vw, 11rem);
  height: 1px;
  background: rgba(255, 255, 255, .12);
  overflow: hidden;
}
/* Sem a máscara do componente: num trilho de progresso, uma ponta esmaecida
   diria "não chegou" onde ele de fato chegou. */
.services__fill {
  position: absolute;
  inset: 0;
  transform-origin: 0% 50%;
  opacity: 1;
  -webkit-mask-image: none;
          mask-image: none;
}

.services__progress-label {
  margin: 0;
  color: rgba(255, 255, 255, .26);
  white-space: nowrap;
}

/* -----------------------------------------------------------------------------
   Sub-blocos — adicionais e suporte
   -----------------------------------------------------------------------------
   Informação complementar, não dois cartões novos: sem superfície, sem borda,
   sem raio. O que os separa é a mesma régua vertical que separa os dados da
   Barra de Confiança.
   -------------------------------------------------------------------------- */
.services__notes {
  /* Nomeada porque .services__note-sep precisa dela para se autocorrigir de
     volta ao eixo central — ver a nota lá embaixo. */
  --svc-notes-gap: clamp(2.5rem, 6vw, 5rem);

  position: relative;
  z-index: 2;
  padding-top: clamp(1.75rem, 4vh, 2.75rem);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: var(--svc-notes-gap);
  row-gap: clamp(2rem, 5vh, 3rem);
}

/* Ao vivo, a faixa sobe para dentro da metade inferior do palco — que é
   comprovadamente vazia: o baralho termina cerca de 290px acima da base do
   palco de 100vh. Sem isto, o usuário atravessa quase meia tela de nada entre
   "03 / 03" e "Adicionais disponíveis"; com isto, a faixa já está encostando
   na base da janela quando o palco solta, e a leitura é contínua.

   O valor é conservador de propósito: o topo da faixa nunca alcança a base do
   baralho, então nada se sobrepõe a nenhum cartão em nenhum quadro do curso.
   O respiro HORIZONTAL não muda — o que sai é só o excesso vertical. */
.services.is-live .services__notes {
  margin-top: clamp(-7rem, -8vh, -3rem);
}

/* Gêmea de .services__cta-rule: mesma construção, mesma origem de transform,
   grudada no topo do bloco. As duas delimitam a faixa informativa. */
.services__notes-rule {
  position: absolute;
  top: 0;
  left: var(--app-gutter);
  right: var(--app-gutter);
  margin: 0;
  border: 0;
  transform-origin: 50% 50%;
}

.services__note {
  position: relative;
  display: grid;
  align-content: start;
  gap: .75rem;
}
.services__note + .services__note { padding-left: var(--svc-notes-gap); }

/* Divisor = .spectrum-rule na variante vertical. Centragem VERTICAL por
   margem negativa e não por translate, pela mesma razão de .trust__sep: a
   centragem permanece do CSS e a altura pode mudar por breakpoint sem deixar
   resíduo de alinhamento.

   AJUSTE PEDIDO — o divisor saiu do eixo central da composição.
   `left: 0` posiciona o traço na borda da SEGUNDA coluna da grade — ou seja,
   logo depois do vão entre as colunas, não no meio dele. Com duas colunas de
   largura igual (1fr cada) e um vão de `--svc-notes-gap` entre elas, essa
   borda fica `--svc-notes-gap / 2` à DIREITA do centro verdadeiro da faixa —
   medido em 2560px: 40px de distância (a metade do vão de 80px naquela
   largura). Esse centro verdadeiro é o MESMO eixo em que a régua do CTA, o
   nó da ponte e o fio de Processo (services__cta-node/-drop, process__seam)
   já vivem — pedido explícito: o divisor devia se alinhar a ELES, não o
   contrário.

   `left: calc(var(--svc-notes-gap) / -2)` desloca o traço exatamente meio
   vão para a esquerda, cancelando o deslocamento e devolvendo-o ao centro. */
.services__note-sep {
  --svc-sep-h: 5.5rem;
  position: absolute;
  top: 50%;
  left: calc(var(--svc-notes-gap) / -2);
  height: var(--svc-sep-h);
  margin-top: calc(var(--svc-sep-h) / -2);
}

.services__note-flag {
  margin: 0;
  color: rgba(255, 255, 255, .3);
}

.services__note-title {
  margin: 0;
  color: rgba(255, 255, 255, .82);
}

.services__note-text {
  margin: 0;
  max-width: 46ch;
  color: rgba(255, 255, 255, .45);
  text-wrap: pretty;
}

/* -----------------------------------------------------------------------------
   Encerramento comercial
   -------------------------------------------------------------------------- */
.services__cta {
  position: relative;
  z-index: 2;
  /* 144px de vão somado (margem + padding) entre a faixa e o CTA, medido em
     1440 × 900 — mais do que a própria altura do bloco de CTA. O fechamento
     precisa de uma respiração que o separe da faixa, não de uma dobra nova. */
  margin-top: clamp(2rem, 5vh, 3.25rem);
  padding-top: clamp(1.75rem, 4.5vh, 3rem);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: clamp(1.5rem, 4vw, 3rem);
}

/* A régua fecha a dobra do mesmo jeito que abriu o capítulo dos diferenciais
   no Sobre: a linha de 1px do DS, aberta a partir do centro.

   BUG MEDIDO — o centro real não era o centro visual.
   .spectrum-rule (o componente base) declara `width: 100%`. Combinado com
   `left` E `right` aqui, os três ficam sobredeterminados — a caixa não tem
   como satisfazer os dois insets E ocupar 100% do bloco de contenção ao
   mesmo tempo. A regra do CSS 2.1 para esse caso descarta `right` e resolve
   a largura a partir de `left` + `width`, então a régua nascia com 1700px de
   largura (a largura CHEIA de .services__cta) começando em `left: 64px` —
   ou seja, transbordando 64px além da borda direita do próprio CTA.
   Capturado em 2560px de largura: centro real em x=1336.5, quando o centro
   de .services__cta (e de todo o resto da composição — o nó novo, o eixo
   central de Processo) está em x=1272.5. A régua nunca esteve exatamente
   onde o resto da dobra pensa que ela está.

   Inofensivo enquanto nada dependia do centro exato — mas o nó de
   convergência da ponte para Processo (services__cta-node, mais abaixo)
   precisa estar EXATAMENTE sobre ela. `width: auto` devolve à régua o
   comportamento padrão de "left + right definem a caixa, sem terceiro
   competidor": ela volta a preencher exatamente o vão entre os dois insets,
   e seu centro passa a coincidir com o de .services__cta. */
.services__cta-rule {
  position: absolute;
  top: 0;
  left: var(--app-gutter);
  right: var(--app-gutter);
  width: auto;
  margin: 0;
  border: 0;
  transform-origin: 50% 50%;
}

.services__cta-copy {
  display: grid;
  gap: .625rem;
  max-width: 34rem;
}
.services__cta-title { margin: 0; color: #fff; text-wrap: balance; }
.services__cta-sub   { margin: 0; color: rgba(255, 255, 255, .5); text-wrap: pretty; }

/* -----------------------------------------------------------------------------
   A ponte para a 5ª dobra — Spectrum converge e muda de direção
   -----------------------------------------------------------------------------
   O problema que isto resolve: Processo terminava com uma linha vertical
   nascendo sozinha, sem relação visível com a régua que já fecha Serviços —
   duas seções que liam como sistemas independentes ligados por espaço morto.

   A correção reaproveita a MESMA construção de .services__seam-node/-drop —
   a costura que já abre esta dobra na entrada (convergindo das bordas para o
   eixo, acendendo um nó, deixando cair um fio) — só que espelhada na saída:
   o nó nasce no CENTRO da régua que já fecha a dobra (mesmo eixo de
   .services__cta-rule, já que os dois têm o mesmo `transform-origin: 50%`
   dentro do mesmo .container), e o fio desce a partir dele. Nenhum vocabulário
   novo: é a mesma linha de 1px do DS, o mesmo halo índigo dos nós, o mesmo
   gesto de queda com dissipação da régua vertical.

   A animação dos dois vive em process.js — não em services.js — porque a
   MESMA timeline que os revela também governa a entrada de Processo (o fio
   que .process__seam continua e a ativação do node 01). Uma única sequência
   contínua, sem dois gatilhos de scroll disputando a mesma transição. Ver o
   comentário de process.js na seção "A PONTE + A ENTRADA".

   Sem JS/GSAP, os dois nascem já visíveis e o fio já desenhado por inteiro —
   mesma política do resto do site: a conexão nunca depende da animação, só é
   refinada por ela. */
.services__cta-copy,
.services__cta > .btn {
  /* Eleva a cópia e o botão acima de .services__cta-drop, que passa por trás
     deles no mesmo eixo — a mesma solução que .services__card já usa para os
     decorativos absolutos não roubarem a leitura do conteúdo real. */
  position: relative;
  z-index: 1;
}

.services__cta-node {
  --cta-node-w: clamp(2.25rem, 3.5vw, 4rem);
  position: absolute;
  top: 0;
  left: 50%;
  z-index: 0;
  width: var(--cta-node-w);
  height: 1px;
  margin-left: calc(var(--cta-node-w) / -2);
  pointer-events: none;
}
.services__cta-node > .spectrum-rule {
  display: block;
  height: 1px;
  opacity: 1;
  box-shadow: 0 0 16px -4px rgba(99, 102, 241, .8);
}
/* O halo — a única forma de "brilho" pedida: nenhuma esfera, nenhum ícone,
   só um aumento de luminosidade Spectrum num raio pequeno, exatamente como
   .services__seam-node::after já faz na costura de entrada. */
.services__cta-node::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 280%;
  height: 1.25rem;
  translate: -50% -50%;
  background: radial-gradient(closest-side, rgba(99, 102, 241, .26), transparent 100%);
}

/* O fio que desce a partir do nó. A altura chega exatamente à base da seção:
   100% cobre o restante da caixa de .services__cta (que termina na base do
   botão/copy, já que o bloco não tem padding-bottom próprio) e
   var(--svc-tail) cobre o respiro final da dobra — herdado por cascata, sem
   precisar redeclarar o valor aqui. Mesma lógica de .services__seam-drop
   (altura composta a partir de variáveis de espaçamento já existentes, nunca
   medida à mão). */
.services__cta-drop {
  position: absolute;
  top: 0;
  left: 50%;
  z-index: 0;
  width: 1px;
  height: calc(100% + var(--svc-tail));
  translate: -50% 0;
  transform-origin: 50% 0%;
  pointer-events: none;
}
/* BUG MEDIDO — a linha "apagava" bem na costura com Processo.
   A primeira versão dissipava o fio nos últimos 32% da própria altura,
   apostando que a entrada de .process__seam (que também fadeava nos
   primeiros 14% da SUA altura) cobriria a transição por continuidade de
   gesto. Medido em 2560×1261: as duas caixas se tocam exatas (0px de vão —
   height: calc(100% + var(--svc-tail)) entrega o que promete), mas as duas
   MÁSCARAS são fades ADJACENTES, não sobrepostos — no ponto exato da costura
   (y = 878px) as duas chegavam a zero de opacidade ao mesmo tempo, e a
   vizinhança inteira (811px a 921px, ~110px) ficava visivelmente esmaecida.
   Capturado em screenshot: um trecho real de linha apagada entre a régua do
   CTA e a headline de Processo — o oposto do traço contínuo que a ponte
   inteira existe para construir.

   A correção: já que as duas pontas se ENCONTRAM de verdade (geometria
   exata, não aproximada), elas não precisam mais dissipar uma na outra —
   podem ficar sólidas as duas, e a costura vira invisível por não ter mais
   nada para esconder. Ver o mesmo ajuste em .process__seam. */
.services__cta-drop > .spectrum-rule--v {
  height: 100%;
  -webkit-mask-image: none;
          mask-image: none;
}

/* -----------------------------------------------------------------------------
   Responsivo
   -------------------------------------------------------------------------- */

/* Notebook / tablet — mesmo conceito, curso menor e cartão mais compacto. */
@media (max-width: 1179px) {
  .services {
    --svc-travel: 135vh;
    --svc-card-w: clamp(18rem, 44vw, 25rem);
  }
  .services__deck { gap: clamp(.875rem, 1.4vw, 1.25rem); }
}

@media (max-width: 899px) {
  .services {
    /* O cartão NÃO cresce aqui. Ocupando 84vw ele já é o objeto dominante da
       tela; o aumento de escala do desktop resolvia um problema — baralho
       pequeno numa janela larga — que simplesmente não existe no compacto. */
    --svc-travel: 125vh;
    --svc-card-w: min(84vw, 24rem);
  }

  /* A folga inferior do palco é menor aqui (o cartão empilhado é mais alto),
     então a faixa sobe menos. */
  .services.is-live .services__notes { margin-top: clamp(-4rem, -5vh, -2rem); }

  /* Medido: aqui a caixa (130-182px) nasce ABAIXO da borda do palco em
     qualquer altura de tela comum (sangramento negativo) — o bug do fixed
     240px do desktop não existe neste breakpoint, porque o número já é bem
     menor. Usar os mesmos 240px aqui faria a rampa de entrada nunca terminar
     antes do fade de saída começar (52% de uma caixa de ~150px são só 78px),
     e o número praticamente sumiria. Uma rampa proporcional e mais curta
     resolve, já que não há aresta nenhuma pra dissipar aqui. */
  .services__ghost {
    font-size: clamp(11rem, 30vh, 18rem);
    -webkit-mask-image: linear-gradient(180deg,
        transparent 0%, #000 20%, #000 52%, transparent 96%);
            mask-image: linear-gradient(180deg,
        transparent 0%, #000 20%, #000 52%, transparent 96%);
  }

  /* Empilhado no estado estático: um serviço por vez também sem JS. */
  .services__deck { grid-template-columns: minmax(0, 1fr); }

  .services__headline { max-width: none; }

  /* A costura passa a convergir para o centro: empilhado, o eixo narrativo do
     Sobre não organiza mais nada (lá ele também deixa de correr pela calha) e
     a experiência já é simétrica. */
  .services__seam-half--l { width: 50%; }
  .services__seam-half--r { left: 50%; }
  .services__seam-node,
  .services__seam-drop { left: 50%; }

  .services__notes { grid-template-columns: minmax(0, 1fr); }
  .services__note + .services__note { padding-left: 0; padding-top: clamp(2rem, 5vh, 3rem); }

  /* Empilhados, o divisor deita: separa uma linha da outra, não uma coluna da
     outra. É a mesma régua, na orientação que a composição pede. */
  .services__note-sep {
    top: 0;
    left: 0;
    right: 0;
    width: auto;
    height: 1px;
    margin-top: 0;
    -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 72%, transparent);
            mask-image: linear-gradient(90deg, #000 0%, #000 72%, transparent);
  }

  .services__cta { flex-direction: column; align-items: flex-start; }

  /* No modo linear, Processo transfere seu eixo para a coluna esquerda dos
     nodes. A ponte central do CTA pertence à composição orbital: mantê-la
     aqui criava um fio vertical sem destino atrás do botão. O seam e o rail
     de Processo continuam o percurso mobile no eixo correto. */
  .services__cta-node,
  .services__cta-drop { display: none; }
}

@media (max-width: 599px) {
  .services { --svc-travel: 115vh; }
  .services__card { padding: 1.375rem; }
  .services__progress { gap: .75rem; }
  .services__progress-label { display: none; }
  .services__cta .btn { width: 100%; }
}

/* Viewports baixos — o cartão precisa caber no palco preso junto com o
   indicador. Só o respiro interno cede; a escala tipográfica do DS fica
   intacta. */
@media (max-height: 780px) and (min-width: 900px) {
  .services__card { padding: 1.375rem 1.5rem; }
  .services__card-head { margin-bottom: 1rem; }
  .services__card-term { margin-bottom: 1rem; }
  .services__stage { gap: 1.25rem; }
}

/* -----------------------------------------------------------------------------
   Movimento reduzido
   -----------------------------------------------------------------------------
   services.js já não monta timeline nenhuma neste modo (gsap.matchMedia trata
   a condição), então .is-live não chega a existir e a dobra fica no estado
   estático: três serviços em grade, completos, sem palco preso e sem
   perspectiva. As regras abaixo são a rede de segurança, caso a classe sobre
   por qualquer caminho.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .services.is-live .services__experience { min-height: 0; }
  .services.is-live .services__stage {
    position: static;
    height: auto;
    overflow: visible;
  }
  .services.is-live .services__deck {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: clamp(1rem, 1.6vw, 1.5rem);
    padding-inline: var(--app-gutter);
    perspective: none;
  }
  .services.is-live .services__slot { grid-area: auto; }
  .services.is-live .services__progress { display: none; }
  /* Sem palco preso não há folga inferior para a faixa ocupar, e a textura
     tipográfica não teria a que se referir. */
  .services.is-live .services__notes { margin-top: 0; }
  .services.is-live .services__ghost { display: none; }

  .services__card-term::before,
  .services__seam-half > .spectrum-rule,
  .services__seam-node > .spectrum-rule,
  .services__seam-drop > .spectrum-rule,
  .services__notes-rule,
  .services__cta-rule,
  .services__cta-node > .spectrum-rule,
  .services__cta-drop > .spectrum-rule,
  .services__fill { animation: none; }
}

@media (prefers-reduced-motion: reduce) and (max-width: 899px) {
  .services.is-live .services__deck { grid-template-columns: minmax(0, 1fr); }
}

/* -----------------------------------------------------------------------------
   Sinalização de camada
   -----------------------------------------------------------------------------
   Mesma política de passage.css e about.css: `will-change` só enquanto a
   experiência está de fato em curso (services.js liga e desliga
   .services-active no <html> pelo onToggle do ScrollTrigger). Promover três
   cartões grandes para camada própria pela vida inteira da página custaria
   memória de GPU por causa de uma sequência de poucos segundos.
   -------------------------------------------------------------------------- */
.services-active .services__slot { will-change: transform, opacity; }
.services-active .services__fill { will-change: transform; }
