/* =========================================================================
   Jaime Luiz Hansen Filho — sistema visual
   Ordem: fontes › tokens › reset › tipografia › layout › componentes › seções
   ========================================================================= */

/* -------------------------------------------------------------- 01 FONTES */

@font-face {
  font-family: 'Archivo Black';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/archivo-black-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Archivo Black';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/archivo-black-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Barlow';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/barlow-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Barlow';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/barlow-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Barlow';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/barlow-500-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Barlow';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/barlow-500-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Barlow';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/barlow-600-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Barlow';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/barlow-600-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Barlow';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/barlow-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Barlow';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/barlow-700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/space-mono-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/space-mono-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/space-mono-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/space-mono-700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* -------------------------------------------------------------- 02 TOKENS */

:root {
  /* cores do material impresso — não alterar */
  --ink: #12161c;
  --near: #0e1217;
  --paper: #f7f5f1;
  --accent: #c8553d;
  --line: #dcd8d1;
  --muted: #6b6f76;

  /* variantes derivadas, criadas só para atingir contraste AA.
     --accent puro dá 4.00:1 sobre --paper (reprova em texto pequeno),
     por isso texto e botões usam --accent-ink (5.6:1 sobre --paper)
     e rótulos em fundo escuro usam --accent-soft (6.4:1 sobre --near). */
  --accent-ink: #a8402c;
  --accent-soft: #e07a5f;
  --muted-inv: #a8adb5;
  --line-inv: #2a3038;

  --font-display: 'Archivo Black', 'Arial Black', system-ui, sans-serif;
  --font-text: 'Barlow', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'Space Mono', ui-monospace, 'Courier New', monospace;

  --wrap: 1180px;
  --gutter: clamp(20px, 5vw, 64px);
  /* respiro em cima e embaixo de cada seção. O teto é baixo de propósito: em
     tela larga o vw dispara e o site vira um corredor de espaço vazio. */
  --sec-y: clamp(52px, 6vw, 88px);
  --measure: 44ch;

  --t: 220ms cubic-bezier(0.2, 0.6, 0.2, 1);
}

/* --------------------------------------------------------------- 03 RESET */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-text);
  font-size: 17px;
  line-height: 1.6;
  font-weight: 400;
  /* `clip` e não `hidden`: os dois cortam o que passa da largura, mas o
     `hidden` transforma o body em área de rolagem própria e isso quebra o
     `position: sticky` do cabeçalho. O `clip` corta sem criar rolagem. */
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
}

/* âncoras (#processo, #projetos…) param abaixo do cabeçalho grudado, e não
   atrás dele */
[id] {
  scroll-margin-top: 92px;
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}

a {
  color: inherit;
}

ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

p {
  margin: 0 0 1.1em;
}

p:last-child {
  margin-bottom: 0;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: 400;
}

:focus-visible {
  outline: 3px solid var(--accent-ink);
  outline-offset: 3px;
  border-radius: 2px;
}

.on-dark :focus-visible {
  outline-color: var(--accent-soft);
}

::selection {
  background: var(--accent);
  color: var(--paper);
}

/* ---------------------------------------------------------- 04 TIPOGRAFIA */

.h-display,
h1,
h2 {
  font-family: var(--font-display);
  letter-spacing: -0.025em;
  line-height: 1.05;
}

h1 {
  font-size: clamp(2.5rem, 7.2vw, 4.75rem);
}

h2 {
  font-size: clamp(1.9rem, 4.6vw, 3.15rem);
}

h3 {
  font-family: var(--font-text);
  font-weight: 700;
  font-size: 1.24rem;
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.mono {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.mono--lg {
  font-size: 12px;
}

.lede {
  font-size: clamp(1.06rem, 2.1vw, 1.28rem);
  line-height: 1.5;
  max-width: var(--measure);
}

.measure {
  max-width: var(--measure);
}

/* frase que tem de caber numa linha só. Solta a largura de leitura e proíbe a
   quebra — mas só da tela grande para cima: no celular nenhuma frase dessas
   caberia, e forçar a linha jogaria o texto para fora da margem.

   Quem usa isto são os subtítulos de seção (`.sec-head__title > p`), na regra
   mais abaixo. A classe fica aqui para servir a qualquer outro texto. */
.one-line {
  max-width: none;
}

@media (min-width: 1000px) {
  .one-line {
    white-space: nowrap;
  }
}

.muted {
  color: var(--muted);
}

.on-dark .muted {
  color: var(--muted-inv);
}

/* ------------------------------------------------------------- 05 LAYOUT */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  padding-block: var(--sec-y);
}

.on-dark {
  background: var(--near);
  color: var(--paper);
}

.on-dark h1,
.on-dark h2,
.on-dark h3 {
  color: var(--paper);
}

/* visível só para leitor de tela e para a busca */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--accent-ink);
  color: var(--paper);
  padding: 12px 18px;
  font-weight: 600;
}

.skip:focus {
  left: 0;
}

/* barra de progresso da rolagem: nasce em escala zero e quem estica é o
   main.js. Sem JS ela existe mas fica com largura nenhuma, invisível. */
.progress {
  position: fixed;
  inset: 0 0 auto 0;
  height: 3px;
  z-index: 60;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: 0 50%;
  pointer-events: none;
}

/* cabeçalho de seção: o rótulo mono fica em cima do título, como etiqueta.
   Já foi em duas colunas (rótulo à esquerda, título à direita) — a versão
   empilhada dá ao título a largura inteira e lê melhor em qualquer tela. */
.sec-head {
  display: grid;
  gap: 12px;
  grid-template-columns: 1fr;
  margin-bottom: clamp(28px, 3.4vw, 44px);
}

.sec-head__label {
  color: var(--accent-ink);
}

.on-dark .sec-head__label {
  color: var(--accent-soft);
}

.sec-head__title {
  min-width: 0;
}

/* O subtítulo de seção fica numa linha só nas telas grandes: com o título
   enorme em cima, uma frase quebrada em duas cria um degrau que puxa o olho
   para o canto errado. No celular ele volta a quebrar normal. */
.sec-head__title > p {
  margin-top: 18px;
  max-width: none;
}

@media (min-width: 1000px) {
  .sec-head__title > p {
    white-space: nowrap;
  }
}

/* --------------------------------------------------------- 06 COMPONENTES */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 52px;
  padding: 14px 26px;
  border: 1px solid transparent;
  border-radius: 3px;
  font-family: var(--font-text);
  font-weight: 600;
  font-size: 1.02rem;
  letter-spacing: 0.005em;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--t), color var(--t), border-color var(--t),
    transform var(--t);
}

.btn--primary {
  background: var(--accent-ink);
  color: var(--paper);
}

.btn--primary:hover {
  background: var(--accent);
  transform: translateY(-1px);
}

.btn--ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--line);
}

.btn--ghost:hover {
  border-color: var(--ink);
}

.on-dark .btn--ghost {
  color: var(--paper);
  border-color: var(--line-inv);
}

.on-dark .btn--ghost:hover {
  border-color: var(--paper);
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 30px;
}

/* no celular os botões ocupam a linha inteira. Empilhados com larguras
   diferentes — um do tamanho do texto, outro maior — a coluna fica torta. */
@media (max-width: 620px) {
  .btn-row {
    gap: 12px;
  }

  .btn-row .btn {
    width: 100%;
  }
}

.link-out {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-weight: 600;
  color: var(--accent-ink);
  text-decoration: none;
  border-bottom: 1px solid var(--line);
  padding-bottom: 2px;
  transition: border-color var(--t), color var(--t);
}

.link-out:hover {
  border-color: var(--accent-ink);
}

.on-dark .link-out {
  color: var(--accent-soft);
  border-bottom-color: var(--line-inv);
}

.on-dark .link-out:hover {
  border-color: var(--accent-soft);
}

/* Alvo de toque. No dedo, um link de 30px de altura erra com facilidade — o
   mínimo recomendado é 44px, e é só o que estas regras fazem: engordam a área
   clicável por cima e por baixo, sem mexer no desenho do texto. */
@media (max-width: 700px) {
  .link-out,
  .contact-item dd > a,
  .site-footer a {
    padding-top: 11px;
    padding-bottom: 11px;
  }

  .nav a {
    padding-block: 12px;
  }

  /* o telefone no fim do aviso do formulário é um link dentro de frase: o
     padding não muda a linha, só engorda a área do dedo */
  .orcamento__aviso a {
    padding-block: 10px;
  }
}

/* moldura de navegador, feita em CSS */
.browser {
  border: 1px solid var(--line);
  border-radius: 4px;
  background: #fff;
  overflow: hidden;
}

.on-dark .browser {
  border-color: var(--line-inv);
  background: #171c23;
}

.browser__bar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 9px 12px;
  border-bottom: 1px solid var(--line);
  background: var(--paper);
}

.on-dark .browser__bar {
  border-bottom-color: var(--line-inv);
  background: #12171e;
}

.browser__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--line);
  flex: none;
}

.on-dark .browser__dot {
  background: var(--line-inv);
}

.browser__url {
  margin-left: 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.on-dark .browser__url {
  color: var(--muted-inv);
}

/* área do print: placeholder e imagem final compartilham a mesma proporção */
.shot {
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--line);
  display: grid;
  place-items: center;
  overflow: hidden;
}

.on-dark .shot {
  background: #1c222a;
}

.shot > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
}

.shot__ph {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: center;
  padding: 16px;
}

.on-dark .shot__ph {
  color: var(--muted-inv);
}

.rule {
  border: 0;
  border-top: 1px solid var(--line);
  margin: 0;
}

.on-dark .rule {
  border-top-color: var(--line-inv);
}

/* ------------------------------------------------------- 07 CABEÇALHO/NAV */

/* gruda no topo e acompanha a página inteira */
.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--near);
  color: var(--paper);
  border-bottom: 1px solid var(--line-inv);
  transition: box-shadow var(--t), border-color var(--t);
}

/* enquanto está no topo da página o cabeçalho encosta no conteúdo e não
   precisa de moldura; assim que a página desce, o main.js marca `is-stuck`
   e ele ganha uma linha e uma sombra para descolar do que passa por baixo */
.site-header.is-stuck {
  box-shadow: 0 10px 26px -20px rgba(18, 22, 28, 0.55);
}

.site-header__in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  min-height: 72px;
}

.brand {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-decoration: none;
  color: var(--paper);
}

.brand__name {
  font-family: var(--font-display);
  font-size: 0.98rem;
  letter-spacing: -0.02em;
  line-height: 1;
  /* sem isto o nome quebra em duas linhas no celular e desalinha o topo */
  white-space: nowrap;
}

.brand__role {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted-inv);
}

.nav {
  display: flex;
  align-items: center;
  gap: clamp(14px, 3vw, 30px);
}

.nav a {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--paper);
  padding: 8px 0;
  border-bottom: 1px solid transparent;
  transition: border-color var(--t), color var(--t);
}

.nav a:hover {
  border-bottom-color: var(--accent-soft);
}

.nav__cta {
  color: var(--accent-soft) !important;
}

.nav__hide-sm {
  display: none;
}

@media (min-width: 640px) {
  .nav__hide-sm {
    display: inline-block;
  }
}

/* cabeçalho claro: ele encosta no banner claro e a emenda precisa sumir. A
   versão escura (`.site-header` puro) segue no arquivo para quem criar uma
   página de fundo escuro. */
.site-header--light {
  background: var(--paper);
  color: var(--ink);
  border-bottom-color: transparent;
}

.site-header--light.is-stuck {
  border-bottom-color: var(--line);
}

.site-header--light .brand {
  color: var(--ink);
}

.site-header--light .brand__role,
.site-header--light .nav a {
  color: var(--muted);
}

.site-header--light .nav a:hover {
  color: var(--ink);
  border-bottom-color: var(--accent-ink);
}

/* o "Orçamento" vira pastilha: é o único botão do topo e precisa ser óbvio */
.site-header--light .nav__cta {
  color: var(--paper) !important;
  background: var(--accent-ink);
  border-radius: 999px;
  padding: 9px 16px;
  border-bottom: 0;
  transition: background var(--t);
}

.site-header--light .nav__cta:hover {
  background: var(--accent);
  border-bottom-color: transparent;
}

/* ------------------------------------------------------------- 08 HERÓI */

.hero {
  background: var(--near);
  color: var(--paper);
  padding-block: clamp(56px, 8vw, 104px) clamp(60px, 9vw, 116px);
  position: relative;
  overflow: hidden;
}

.hero__grid {
  display: grid;
  gap: clamp(40px, 6vw, 64px);
  grid-template-columns: 1fr;
  align-items: center;
}

.hero h1 {
  margin-bottom: 24px;
}

.hero__lede {
  color: var(--muted-inv);
  max-width: 46ch;
}

.hero__art {
  min-width: 0;
}

/* No celular o desenho do site sai da abertura. Ele é enfeite (`aria-hidden`),
   e numa tela estreita empilhava selo, etiqueta, janela e celular em cima da
   mesma dobra — o que a pessoa via primeiro era bagunça, não a proposta.
   Sem ele a abertura termina no botão, que é onde ela deve terminar. */
@media (max-width: 700px) {
  .hero__art {
    display: none;
  }
}

@media (min-width: 940px) {
  .hero__grid {
    grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
  }
}

/* o conteúdo precisa ficar acima da textura decorativa do fundo */
.hero > .wrap {
  position: relative;
  z-index: 1;
}

/* -------------------------------------------------- 08b ABERTURA DA HOME */
/* A home abre claro, com fundo animado e duas telas de site. O `.hero` puro,
   escuro, continua existindo e nada daqui vaza para ele.

   Três camadas de fundo, todas em CSS, nenhuma imagem baixada:
     ::before  malha quadriculada + brilhos terracota, parada
     ::after   três campos de pontinhos, que se deslocam devagar
     .deco     os quatro contornos grandes, que flutuam e giram
   Quem liga "reduzir movimento" no sistema vê tudo parado: a regra global
   de prefers-reduced-motion, no fim deste arquivo, congela as animações. */

.hero--home {
  background: linear-gradient(
    168deg,
    var(--paper) 0%,
    #f4f1ec 42%,
    #f2ece5 100%
  );
  color: var(--ink);
}

.hero--home h1 {
  color: var(--ink);
  /* menor que o h1 padrão do site: com o desenho do site ao lado, o título
     gigante empurrava tudo para baixo e a abertura não cabia mais numa tela */
  font-size: clamp(2rem, 4.4vw, 3.3rem);
  /* distribui o título em linhas de tamanho parecido, para não sobrar
     uma palavra sozinha na última linha */
  text-wrap: balance;
}

.hero--home .hero__lede {
  color: var(--muted);
}

/* camada 1: malha + brilhos */
.hero--home::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    radial-gradient(
      circle at 84% 12%,
      rgba(200, 85, 61, 0.1) 0,
      transparent 52%
    ),
    radial-gradient(
      circle at 6% 92%,
      rgba(200, 85, 61, 0.07) 0,
      transparent 46%
    ),
    repeating-linear-gradient(
      to right,
      rgba(18, 22, 28, 0.032) 0 1px,
      transparent 1px 68px
    ),
    repeating-linear-gradient(
      to bottom,
      rgba(18, 22, 28, 0.032) 0 1px,
      transparent 1px 68px
    );
}

/* camada 2: pontinhos. Os três campos têm tamanhos que não se encaixam,
   então o olho lê como aleatório, e não como grade. Cada um caminha para
   um lado — é essa diferença que dá sensação de profundidade. */
.hero--home::after {
  content: '';
  position: absolute;
  inset: -80px;
  pointer-events: none;
  background-image:
    radial-gradient(circle, rgba(18, 22, 28, 0.2) 1.4px, transparent 1.6px),
    radial-gradient(circle, rgba(200, 85, 61, 0.28) 1.1px, transparent 1.3px),
    radial-gradient(circle, rgba(18, 22, 28, 0.12) 1.8px, transparent 2px);
  background-size: 137px 119px, 211px 173px, 313px 257px;
  background-position: 0 0, 40px 70px, 130px 30px;
  animation: dot-drift 46s linear infinite alternate;
}

@keyframes dot-drift {
  to {
    background-position: 84px -52px, -66px 128px, 96px -74px;
  }
}

/* camada 3: os contornos grandes */
.deco {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}

.deco__ring,
.deco__square {
  position: absolute;
  border: 1px solid rgba(200, 85, 61, 0.3);
  will-change: transform;
}

.deco__ring {
  border-radius: 50%;
  border-color: rgba(18, 22, 28, 0.09);
}

.deco__square {
  border-radius: 18px;
}

.deco__ring--a {
  width: clamp(200px, 26vw, 340px);
  aspect-ratio: 1;
  right: -4%;
  bottom: -14%;
  animation: float-slow 19s ease-in-out infinite;
}

.deco__ring--b {
  width: clamp(90px, 11vw, 148px);
  aspect-ratio: 1;
  left: 4%;
  top: 12%;
  border-color: rgba(200, 85, 61, 0.22);
  animation: float-slow 15s ease-in-out infinite reverse;
}

.deco__square--a {
  width: clamp(96px, 12vw, 156px);
  aspect-ratio: 1;
  left: 2%;
  bottom: 6%;
  animation: spin-slow 34s linear infinite;
}

.deco__square--b {
  width: clamp(80px, 9vw, 120px);
  aspect-ratio: 1;
  right: 22%;
  top: 8%;
  border-color: rgba(18, 22, 28, 0.1);
  animation: spin-slow 27s linear infinite reverse;
}

@keyframes float-slow {
  50% {
    transform: translateY(-26px);
  }
}

@keyframes spin-slow {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

/* ------------------------------------------------- 08b2 SELOS DA ABERTURA */
/* Fileira de pastilhas com um ✓ na frente. O ✓ é um SVG desenhado dentro do
   próprio CSS (data URI): não é fonte, não é ícone baixado e não depende do
   emoji do sistema, então sai igual em qualquer computador. Nenhuma
   requisição sai para fora por causa dele. */

.badges {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  margin-top: 28px;
}

/* no celular os quatro selos viram duas colunas iguais: em linha livre eles
   quebravam 1 + 2 + 1, e a borda irregular parecia erro de alinhamento */
@media (max-width: 700px) {
  .badges {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* alinhados à esquerda, e não centrados: com textos de tamanhos diferentes,
     o ✓ centrado deixa cada selo começando num ponto diferente */
  .badge {
    justify-content: flex-start;
    padding-inline: 12px;
  }
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 14px 7px 11px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.6);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--ink);
}

.badge::before {
  content: '';
  flex: none;
  width: 13px;
  height: 13px;
  background: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Cpath%20d='M2.5%208.4l3.6%203.6L13.5%204'%20fill='none'%20stroke='%23a8402c'%20stroke-width='2.3'%20stroke-linecap='round'%20stroke-linejoin='round'/%3E%3C/svg%3E")
    center / contain no-repeat;
}

/* ------------------------------------------------ 08c DESENHO DA ABERTURA */
/* Um site genérico desenhado só com formas: barra, bloco e retângulo. Zero
   imagem, zero texto — nada aqui é print de cliente. O computador é a peça
   principal, o celular encosta na quina de baixo sobrando um pouco para fora
   (é o que faz o conjunto parecer objeto e não figura recortada), e as duas
   etiquetas flutuam por cima, uma em cada canto oposto.

   Tons: --mock-ink é o bloco cheio (título, botão), --mock-soft é a linha de
   texto, --mock-box é a área de imagem. Todos derivam do --ink, então mudar a
   cor da marca não quebra o desenho. */

.mock {
  --mock-ink: rgba(18, 22, 28, 0.82);
  --mock-soft: rgba(18, 22, 28, 0.13);
  --mock-box: rgba(18, 22, 28, 0.09);
  position: relative;
  padding-bottom: 11%;
}

.mock__win {
  box-shadow: 0 26px 60px -28px rgba(18, 22, 28, 0.42);
  animation: float-slow 13s ease-in-out infinite;
}

/* as três marquinhas do canto direito da barra, como num navegador */
.mock__ctrls {
  display: flex;
  gap: 5px;
  margin-left: auto;
  padding-left: 12px;
  flex: none;
}

.mock__ctrls i {
  width: 13px;
  height: 3px;
  border-radius: 2px;
  background: var(--line);
}

/* a "página" dentro da janela */
.mock__screen {
  display: flex;
  flex-direction: column;
  gap: 12px;
  aspect-ratio: 16 / 10;
  padding: clamp(14px, 2.4vw, 26px);
  background: linear-gradient(150deg, #fdfcfa 0%, #f3efe9 100%);
  position: relative;
  overflow: hidden;
}

/* brilho que atravessa a página de vez em quando, como um bloco que ainda
   está carregando. É o único movimento dentro da janela. */
.mock__screen::after {
  content: '';
  position: absolute;
  inset: 0 auto 0 -40%;
  width: 40%;
  pointer-events: none;
  background: linear-gradient(
    100deg,
    transparent,
    rgba(255, 255, 255, 0.7),
    transparent
  );
  animation: mock-shine 5.6s ease-in-out infinite;
}

@keyframes mock-shine {
  0%,
  62% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(350%);
  }
}

.mock__kicker {
  display: block;
  width: 34%;
  height: 6px;
  border-radius: 3px;
  background: var(--mock-soft);
  margin-bottom: 2px;
}

.mock__cols {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  gap: clamp(12px, 2vw, 22px);
  flex: 1;
  min-height: 0;
}

.mock__col {
  display: flex;
  flex-direction: column;
  gap: 9px;
  min-width: 0;
}

.mock__col--media {
  display: grid;
  grid-template-rows: 1.35fr 1fr;
  gap: 9px;
}

/* linha de texto; com --h vira bloco de título, cheio e mais alto */
.mock__line {
  display: block;
  height: 5px;
  border-radius: 3px;
  background: var(--mock-soft);
  width: 100%;
  flex: none;
}

.mock__line--h {
  height: 15px;
  border-radius: 4px;
  background: var(--mock-ink);
}

.mock__line--sm {
  width: 78%;
}

.mock__line--xs {
  width: 58%;
}

.mock__btns {
  display: flex;
  gap: 8px;
  margin-top: auto;
}

.mock__btn {
  display: block;
  width: 76px;
  height: 20px;
  border-radius: 999px;
  border: 1px solid var(--mock-soft);
  flex: none;
}

.mock__btn--solid {
  background: var(--mock-ink);
  border-color: var(--mock-ink);
}

.mock__btn--full {
  width: 100%;
  margin-top: auto;
}

.mock__box {
  display: block;
  border-radius: 6px;
  background: var(--mock-box);
  width: 100%;
  height: 100%;
}

.mock__box--light {
  background: rgba(18, 22, 28, 0.045);
}

.mock__box--wide {
  height: 34%;
  flex: none;
}

.mock__pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 9px;
  min-height: 0;
}

/* etiquetas flutuantes */
.mock__tag {
  position: absolute;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 9px 14px;
  border-radius: 999px;
  background: #fff;
  border: 1px solid var(--line);
  box-shadow: 0 12px 26px -14px rgba(18, 22, 28, 0.4);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
  animation: float-slow 11s ease-in-out infinite;
}

.mock__tag em {
  font-style: normal;
  color: var(--muted);
}

.mock__tag--a {
  top: -4%;
  left: -2%;
  animation-delay: -3s;
}

.mock__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  flex: none;
}

/* o celular */
.phone {
  border: 1px solid var(--line);
  border-radius: 22px;
  background: #fff;
  padding: 6px;
  box-shadow: 0 18px 38px -18px rgba(18, 22, 28, 0.45);
}

.mock__phone {
  position: absolute;
  right: -3%;
  bottom: 0;
  z-index: 2;
  width: clamp(92px, 26%, 168px);
  animation: float-slow 13s ease-in-out infinite;
  /* meio ciclo atrás do computador: os dois nunca sobem juntos */
  animation-delay: -6.5s;
}

.mock__screen--phone {
  aspect-ratio: 9 / 19.5;
  border-radius: 16px;
  gap: 8px;
  padding: 14px 11px;
}

.mock__screen--phone .mock__line--h {
  height: 11px;
}

/* nas telas pequenas o desenho inteiro encolhe: a etiqueta acompanha */
@media (max-width: 620px) {
  .mock__tag {
    font-size: 9px;
    padding: 7px 11px;
  }
}

/* -------------------------------------------- 08d FAIXA DE TECNOLOGIAS */
/* Duas listas idênticas correndo lado a lado. A animação anda exatamente
   metade da largura da esteira, então no fim do ciclo a segunda lista está
   onde a primeira começou e a volta não tem emenda. Encostou o mouse, para. */

.marquee {
  --marquee-gap: clamp(28px, 4vw, 52px);
  overflow: hidden;
  border-block: 1px solid var(--line);
  padding-block: 16px;
  background: var(--paper);
  /* apaga as pontas, para os itens não nascerem e morrerem no corte seco */
  mask-image: linear-gradient(
    to right,
    transparent,
    #000 7%,
    #000 93%,
    transparent
  );
}

.marquee__track {
  display: flex;
  gap: var(--marquee-gap);
  width: max-content;
  animation: marquee-run 42s linear infinite;
}

.marquee:hover .marquee__track,
.marquee:focus-within .marquee__track {
  animation-play-state: paused;
}

.marquee__list {
  display: flex;
  gap: var(--marquee-gap);
  flex: none;
}

.marquee__list li {
  display: flex;
  align-items: center;
  gap: var(--marquee-gap);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

/* o ponto separador nasce depois de cada item, nunca no começo da fila */
.marquee__list li::after {
  content: '';
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--accent);
  opacity: 0.55;
}

@keyframes marquee-run {
  to {
    transform: translateX(calc(-50% - var(--marquee-gap) / 2));
  }
}

/* ---------------------------------------------------------- 09 SERVIÇOS */
/* três cartões. O antigo bloco "O que eu faço" era uma lista de uma linha
   por item; agora cada frente tem descrição própria e o que está incluso. */

.cards {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(20px, 3vw, 28px);
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: #fff;
  padding: clamp(24px, 3vw, 32px);
  overflow: hidden;
  transition: border-color var(--t), transform var(--t), box-shadow var(--t);
}

.card:hover {
  border-color: var(--accent);
  transform: translateY(-3px);
  box-shadow: 0 18px 34px -22px rgba(18, 22, 28, 0.4);
}

/* holofote que segue o mouse. A posição vem das variáveis --mx/--my, que o
   main.js escreve neste elemento; sem JS ficam no centro e nada acontece,
   porque a camada só aparece no hover. */
.card::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  opacity: 0;
  pointer-events: none;
  transition: opacity 260ms ease;
  background: radial-gradient(
    260px circle at var(--mx, 50%) var(--my, 50%),
    rgba(200, 85, 61, 0.13),
    transparent 68%
  );
}

.card:hover::before {
  opacity: 1;
}

/* o conteúdo precisa entrar na mesma camada do holofote, senão some atrás */
.card > * {
  position: relative;
  z-index: 1;
}

.card__k {
  color: var(--accent-ink);
  display: block;
  margin-bottom: 16px;
}

.card__title {
  margin-bottom: 12px;
}

.card__desc {
  color: var(--muted);
  font-size: 1rem;
  margin-bottom: 20px;
}

.card__list {
  margin-top: auto;
  border-top: 1px solid var(--line);
}

.card__list li {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 11px 0;
  border-bottom: 1px solid var(--line);
  font-size: 0.98rem;
}

.card__list li:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.card__list li::before {
  content: '';
  flex: none;
  width: 14px;
  height: 1px;
  background: var(--accent);
  transform: translateY(-5px);
}

@media (min-width: 900px) {
  .cards {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* ---------------------------------------------------------- 10 PROJETOS */

/* Fundo da seção de projetos. A de cima, Serviços, é papel liso: aqui o papel
   é um tom mais fundo, com a mesma malha quadriculada da abertura e um brilho
   terracota em cada canto. É desenho de CSS, sem imagem e sem animação — a
   seção é longa, e fundo que se mexe atrás de sete cards cansa a leitura.

   O `isolation: isolate` é o que segura os cards por cima: sem ele, qualquer
   z-index de dentro dos cards passaria a brigar com as camadas do fundo. */
.section--papel {
  position: relative;
  isolation: isolate;
  background: linear-gradient(180deg, #f2eee7 0%, #efe9e1 58%, #f4f0ea 100%);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.section--papel::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(
      circle at 88% 6%,
      rgba(200, 85, 61, 0.12) 0,
      transparent 46%
    ),
    radial-gradient(
      circle at 4% 88%,
      rgba(200, 85, 61, 0.08) 0,
      transparent 42%
    ),
    repeating-linear-gradient(
      to right,
      rgba(18, 22, 28, 0.035) 0 1px,
      transparent 1px 68px
    ),
    repeating-linear-gradient(
      to bottom,
      rgba(18, 22, 28, 0.035) 0 1px,
      transparent 1px 68px
    );
}

/* os pontinhos, na versão parada */
.section--papel::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(circle, rgba(18, 22, 28, 0.12) 1.4px, transparent 1.6px),
    radial-gradient(circle, rgba(200, 85, 61, 0.16) 1.1px, transparent 1.3px);
  background-size: 137px 119px, 211px 173px;
  background-position: 0 0, 40px 70px;
}

/* dentro dele a janelinha de navegador precisa continuar destacada do fundo,
   por isso ela ganha um branco cheio e uma sombra de base */
.section--papel .project__shot {
  box-shadow: 0 14px 30px -22px rgba(18, 22, 28, 0.4);
}

.projects {
  display: grid;
  gap: clamp(38px, 5vw, 56px);
  grid-template-columns: 1fr;
}

@media (min-width: 880px) {
  .projects {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: clamp(48px, 5vw, 72px) clamp(32px, 4vw, 48px);
  }
}

.project {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Dentro da seção de fundo texturizado cada projeto vira um cartão de papel
   liso. Sem isto o texto fica em cima da malha e dos pontinhos, e o olho
   precisa trabalhar para ler — o fundo tem de ficar em volta do conteúdo,
   nunca atrás dele. */
.section--papel .project {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: clamp(18px, 2.2vw, 26px);
  box-shadow: 0 18px 40px -34px rgba(18, 22, 28, 0.5);
}

.project__head {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 20px;
}

.project__num {
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.12em;
  color: var(--accent-ink);
  flex: none;
}

.project__name {
  flex: 1;
  min-width: 0;
}

/* o nome do projeto é h2 por hierarquia (a home não tem título visível
   antes dele), mas segue com o corpo tipográfico de subtítulo */
.project__title {
  font-family: var(--font-text);
  font-weight: 700;
  font-size: 1.24rem;
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.project__meta {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: 6px;
  display: block;
}

/* A moldura segura duas coisas empilhadas: o print de desktop dentro da
   janelinha de navegador e, na frente, o celular no canto de baixo. O celular
   passa da borda de propósito — é o que dá a sensação de estar por cima. Por
   isso a margem de baixo é maior aqui: ela reserva o espaço dessa sobra. */
.project__frame {
  position: relative;
  margin-bottom: 44px;
  transition: transform var(--t);
}

.project__shot {
  transition: box-shadow var(--t), border-color var(--t);
}

/* ---- a lupa ---- */
/* O print aproxima com o mouse em cima, e o ponto de aproximação é onde o
   cursor está: quem escreve --zx/--zy é o main.js, a cada movimento.

   Sem JavaScript as variáveis não existem e o zoom cai no ponto padrão, um
   pouco acima do centro — continua funcionando, só não segue o cursor.

   `@media (hover: hover)` porque em tela de toque não existe "passar por
   cima": o dedo já é o clique, e o zoom ficaria preso depois de tocar. */
@media (hover: hover) {
  .shot > img {
    transform-origin: var(--zx, 50%) var(--zy, 34%);
    /* o zoom é lento e a origem é rápida: assim a lente parece acompanhar o
       cursor, em vez de escorregar atrás dele */
    transition: transform 620ms cubic-bezier(0.2, 0.6, 0.2, 1),
      transform-origin 180ms linear;
    will-change: transform;
  }

  .project__frame:hover .shot > img {
    transform: scale(1.16);
  }

  /* o celular na frente aproxima junto, mas bem menos: no mesmo tamanho do
     outro ele cresce demais e cobre o print inteiro */
  .mini-phone__screen img {
    transition: transform 620ms cubic-bezier(0.2, 0.6, 0.2, 1);
  }

  .project__frame:hover .mini-phone__screen img {
    transform: scale(1.06);
  }
}

/* quem pediu "reduzir movimento" no sistema não recebe nenhuma aproximação */
@media (prefers-reduced-motion: reduce) {
  .project__frame:hover .shot > img,
  .project__frame:hover .mini-phone__screen img {
    transform: none;
  }
}

/* passar o mouse em qualquer parte do bloco levanta a moldura e acende a
   barra de endereço — o card inteiro reage, não só a imagem */
.project:hover .project__frame {
  transform: translateY(-4px);
}

.project:hover .project__shot {
  border-color: var(--accent);
  box-shadow: 0 20px 38px -24px rgba(18, 22, 28, 0.45);
}

/* ---- o celular na frente ---- */

.mini-phone {
  position: absolute;
  right: 5%;
  bottom: -26px;
  width: 21%;
  min-width: 84px;
  max-width: 132px;
  aspect-ratio: 9 / 19;
  padding: 5px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: #0e1319;
  box-shadow: -10px 18px 34px -16px rgba(18, 22, 28, 0.6);
  transition: transform var(--t);
}

.project:hover .mini-phone {
  transform: translateY(-6px);
}

/* numa tela estreita o print de desktop já é pequeno, e o celular por cima
   dele come metade do que dá para ver. Aqui ele encolhe junto. */
@media (max-width: 620px) {
  .mini-phone {
    width: 24%;
    min-width: 68px;
    right: 4%;
    bottom: -18px;
  }

  .project__frame {
    margin-bottom: 34px;
  }
}

/* a tarja preta em cima, que faz o retângulo virar celular no olho */
.mini-phone__notch {
  position: absolute;
  top: 9px;
  left: 50%;
  transform: translateX(-50%);
  width: 30%;
  height: 4px;
  border-radius: 3px;
  background: #2a323c;
  z-index: 1;
}

.mini-phone__screen {
  position: relative;
  height: 100%;
  border-radius: 12px;
  overflow: hidden;
  background: #1c222a;
  display: grid;
  place-items: center;
}

.mini-phone__screen > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
}

.mini-phone__screen .shot__ph {
  font-size: 9px;
  letter-spacing: 0.1em;
  padding: 8px;
  color: var(--muted-inv);
}

/* ---- o botão que abre a demonstração ---- */

/* Quem cria este botão é o main.js. Ele cobre a moldura inteira, fica
   transparente até o mouse chegar, e é um <button> de verdade — então
   funciona no teclado e aparece para o leitor de tela como ação. */
.frame__abrir {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 4px;
  background: rgba(18, 22, 28, 0);
  color: transparent;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background var(--t), color var(--t);
}

.frame__abrir span {
  border: 1px solid currentColor;
  border-radius: 2px;
  padding: 10px 18px;
  background: rgba(18, 22, 28, 0);
  transition: background var(--t);
}

.project__frame:hover .frame__abrir,
.frame__abrir:focus-visible {
  background: rgba(18, 22, 28, 0.42);
  color: var(--paper);
}

.project__frame:hover .frame__abrir span,
.frame__abrir:focus-visible span {
  background: rgba(18, 22, 28, 0.55);
}

.project__shot .browser__url {
  transition: color var(--t);
}

.project:hover .browser__url {
  color: var(--accent-ink);
}

.project:hover .project__num {
  color: var(--accent);
}

.project__num {
  transition: color var(--t);
}

/* a seta do "Ver o site" desliza para fora quando o bloco está sob o mouse.
   Nos cards de projeto a seta vem daqui, do CSS, e não do texto do HTML —
   por isso os links ali terminam em "Ver o site", sem o ↗ escrito. */
.project__foot .link-out::after {
  content: '↗';
  display: inline-block;
  transition: transform var(--t);
}

.project:hover .project__foot .link-out::after {
  transform: translate(3px, -3px);
}

.project__desc {
  font-size: 1rem;
  color: var(--ink);
  max-width: var(--measure);
  margin-bottom: 16px;
}

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 18px;
}

.tag {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 5px 9px;
}

.project__foot {
  margin-top: auto;
  padding-top: 4px;
}

.badge-soon {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-ink);
  border: 1px solid var(--accent);
  border-radius: 2px;
  padding: 6px 10px;
}

/* ---------------------------------------------------- 11b PROCESSO NO SCROLL */
/* Duas colunas: o texto das etapas rola normalmente à esquerda, e à direita
   um painel gruda na tela e troca de desenho a cada etapa. Quem manda é o
   main.js: ele marca `is-active` na etapa e na tela correspondente, e escreve
   `--i` (0 a 4) no painel, que é o que enche a barrinha de progresso.

   Sem JS nada recebe classe: as cinco etapas ficam legíveis uma embaixo da
   outra e o painel mostra a primeira tela, parado.

   Todas as telas são desenho em CSS. Os prefixos `sk-` (de *skeleton*) são as
   peças soltas: barra, bloco, pastilha, amostra de cor. */

.flow__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(28px, 5vw, 48px);
}

/* ---- o fundo da seção ---- */
/* Três camadas, as mesmas da abertura, na versão escura: brilhos e degradê no
   próprio elemento, malha no ::before, pontinhos que caminham no ::after, e os
   contornos grandes no `.deco`.

   `overflow: clip` e não `hidden`: o `hidden` transformaria a seção em área de
   rolagem própria e o painel de etapas, que é `sticky`, pararia de grudar. */

.flow.on-dark {
  position: relative;
  overflow: clip;
  background:
    radial-gradient(
      circle at 10% 6%,
      rgba(200, 85, 61, 0.16) 0,
      transparent 44%
    ),
    radial-gradient(
      circle at 92% 74%,
      rgba(200, 85, 61, 0.11) 0,
      transparent 40%
    ),
    linear-gradient(172deg, #0d1116 0%, #141b24 52%, #0d1116 100%);
}

.flow > .wrap {
  position: relative;
  z-index: 1;
}

/* malha quadriculada, parada */
.flow::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(
      to right,
      rgba(247, 245, 241, 0.028) 0 1px,
      transparent 1px 72px
    ),
    repeating-linear-gradient(
      to bottom,
      rgba(247, 245, 241, 0.028) 0 1px,
      transparent 1px 72px
    );
}

/* pontinhos que caminham devagar, cada campo para um lado */
.flow::after {
  content: '';
  position: absolute;
  inset: -80px;
  pointer-events: none;
  background-image:
    radial-gradient(circle, rgba(247, 245, 241, 0.16) 1.3px, transparent 1.5px),
    radial-gradient(circle, rgba(224, 122, 95, 0.3) 1.1px, transparent 1.3px),
    radial-gradient(circle, rgba(247, 245, 241, 0.08) 1.9px, transparent 2.1px);
  background-size: 149px 127px, 197px 181px, 331px 269px;
  background-position: 0 0, 60px 40px, 150px 90px;
  animation: dot-drift 54s linear infinite alternate;
}

/* os contornos grandes em fundo escuro: o traço claro do desenho original
   sumiria, então aqui eles herdam tons próprios */
.deco--dark .deco__ring,
.deco--dark .deco__square {
  border-color: rgba(247, 245, 241, 0.07);
}

.deco__ring--c {
  width: clamp(260px, 32vw, 460px);
  aspect-ratio: 1;
  right: -8%;
  top: 6%;
  border-color: rgba(200, 85, 61, 0.16);
  animation: float-slow 21s ease-in-out infinite;
}

.deco__ring--d {
  width: clamp(120px, 14vw, 200px);
  aspect-ratio: 1;
  left: 6%;
  bottom: 10%;
  animation: float-slow 17s ease-in-out infinite reverse;
}

.deco__square--c {
  width: clamp(120px, 15vw, 200px);
  aspect-ratio: 1;
  right: 14%;
  bottom: -6%;
  border-color: rgba(200, 85, 61, 0.14);
  animation: spin-slow 38s linear infinite;
}

.deco__square--d {
  width: clamp(80px, 10vw, 132px);
  aspect-ratio: 1;
  left: 26%;
  top: -4%;
  animation: spin-slow 30s linear infinite reverse;
}

/* ---- a linha com as bolinhas ---- */
/* A coluna inteira é medida pelo main.js: ele guarda em `--l0` onde fica o
   centro da primeira bolinha, em `--lh` a distância até a última, e em `--p`
   (0 a 1) o quanto da linha já foi percorrido. A linha, o preenchimento e o
   marcador leem essas três variáveis — nenhum deles tem posição fixa no CSS.

   Sem JS as variáveis não existem: a linha fica com a altura do fallback, o
   preenchimento em zero e o marcador some. Os tópicos continuam legíveis. */

.flow__col {
  /* --rail é a largura da calha (o quanto o texto anda para a direita);
     --mark é o diâmetro da bolinha. A linha se posiciona a partir de --mark,
     e não de --rail, senão ela passa fora do centro dos círculos. */
  --rail: 62px;
  --mark: 42px;
  position: relative;
  padding-left: var(--rail);
}

.flow__line {
  position: absolute;
  left: calc(var(--mark) / 2 - 1px);
  top: var(--l0, 0);
  height: var(--lh, 100%);
  width: 2px;
  background: var(--line-inv);
  border-radius: 2px;
}

/* o pedaço da linha que já foi percorrido */
.flow__line-fill {
  position: absolute;
  inset: 0 0 auto 0;
  width: 2px;
  height: calc(var(--p, 0) * 100%);
  background: var(--accent);
  border-radius: 2px;
}

/* o "você está aqui": anda pela linha junto com a rolagem */
.flow__cursor {
  position: absolute;
  left: 50%;
  top: calc(var(--p, 0) * 100%);
  width: 15px;
  height: 15px;
  border-radius: 50%;
  border: 3px solid var(--accent);
  background: var(--near);
  transform: translate(-50%, -50%);
  box-shadow: 0 0 0 5px rgba(200, 85, 61, 0.14);
  opacity: 0;
  transition: opacity var(--t);
}

/* só aparece depois que o JS mediu a coluna */
.flow__col.is-live .flow__cursor {
  opacity: 1;
}

.flow__steps {
  border-top: 0;
}

.flow__step {
  position: relative;
  padding: 22px 0;
}

/* a bolinha de cada tópico */
.flow__mark {
  position: absolute;
  left: calc(var(--rail) * -1);
  top: 26px;
  width: var(--mark);
  height: var(--mark);
  border-radius: 50%;
  border: 2px solid var(--line-inv);
  background: var(--near);
  transition: border-color 320ms ease, background 320ms ease;
}

/* o ✓ nasce transparente e aparece quando o marcador passa por cima */
.flow__mark::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Cpath%20d='M2.5%208.4l3.6%203.6L13.5%204'%20fill='none'%20stroke='%23e07a5f'%20stroke-width='2.4'%20stroke-linecap='round'%20stroke-linejoin='round'/%3E%3C/svg%3E")
    center / 19px 19px no-repeat;
  opacity: 0;
  transform: scale(0.7);
  transition: opacity 320ms ease, transform 380ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.flow__mark.is-reached {
  border-color: var(--accent);
}

.flow__mark.is-reached::before {
  opacity: 1;
  transform: none;
}

/* o instante em que o marcador encosta: um anel que abre e some */
.flow__mark.is-hit {
  animation: mark-ring 900ms ease-out, mark-pop 560ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

@keyframes mark-ring {
  from {
    box-shadow: 0 0 0 0 rgba(200, 85, 61, 0.5);
  }
  to {
    box-shadow: 0 0 0 22px rgba(200, 85, 61, 0);
  }
}

@keyframes mark-pop {
  45% {
    transform: scale(1.16);
  }
}

.flow__num {
  display: block;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.12em;
  color: var(--accent-soft);
  margin-bottom: 10px;
}

.flow__title {
  margin-bottom: 8px;
}

.flow__desc {
  color: var(--muted-inv);
  max-width: 52ch;
}

/* ---- o painel ---- */

/* O painel começa bem de lado, deitado e afastado, e vai se endireitando
   conforme a seção atravessa a tela. Na última etapa ele chega em zero: de
   frente, reto, sem nenhuma inclinação sobrando.

   Como funciona: `.flow__stage` cria a perspectiva (a "distância do olho") e
   `.stage` é o que gira dentro dela. Girar o filho, e não o pai, é o que faz
   a rotação parecer profundidade de verdade e não uma figura achatada torta —
   juntar as duas coisas no mesmo elemento mata o efeito.

   Quem move é o main.js, escrevendo `--sy` (0 a 1) na seção. Todos os ângulos
   são escritos como "valor inicial menos o mesmo valor vezes --sy", então em
   --sy = 1 sobra exatamente zero. Sem JS a variável cai no 0 do fallback e o
   painel fica parado na inclinação inicial — continua bonito, só não se vira. */

.flow__stage {
  position: sticky;
  /* abaixo do cabeçalho grudado */
  top: 96px;
  z-index: 1;
  /* quanto menor, mais forte a profundidade */
  perspective: 1100px;
  perspective-origin: 62% 50%;
}

.stage {
  border: 1px solid var(--line-inv);
  border-radius: 6px;
  background: #12171e;
  overflow: hidden;
  transform-origin: 50% 50%;
  /* o translateZ negativo empurra o painel para longe no começo: é ele que
     segura o tamanho na tela, já que o giro forte aproxima a borda esquerda */
  transform: translateZ(calc(-260px + var(--sy, 0) * 260px))
    rotateY(calc(-31deg + var(--sy, 0) * 31deg))
    rotateX(calc(14deg - var(--sy, 0) * 14deg))
    rotateZ(calc(3deg - var(--sy, 0) * 3deg));
  /* a sombra cai para o lado oposto da inclinação, senão o painel parece
     colado num vidro em vez de flutuando. Ela encolhe junto com o giro. */
  box-shadow: calc(-46px + var(--sy, 0) * 46px) calc(54px - var(--sy, 0) * 34px)
    100px -40px rgba(0, 0, 0, 0.95);
  will-change: transform;
}

/* no celular a inclinação é bem menor: numa tela estreita o mesmo ângulo
   corta a borda do painel e parece defeito, não profundidade */
@media (max-width: 999px) {
  .flow__stage {
    perspective: 900px;
    perspective-origin: 50% 50%;
  }

  .stage {
    transform: translateZ(calc(-120px + var(--sy, 0) * 120px))
      rotateY(calc(-13deg + var(--sy, 0) * 13deg))
      rotateX(calc(7deg - var(--sy, 0) * 7deg));
    box-shadow: -18px 26px 56px -30px rgba(0, 0, 0, 0.95);
  }
}

.stage__bar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--line-inv);
  background: #0e1319;
}

.stage__bar .browser__dot {
  background: var(--line-inv);
}

.stage__count {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted-inv);
}

.stage__count b {
  color: var(--accent-soft);
}

/* as cinco telas ocupam o mesmo lugar; só a ativa aparece */
.stage__screens {
  position: relative;
  aspect-ratio: 4 / 3;
  margin: 18px;
  border: 1px solid var(--line-inv);
  border-radius: 4px;
  background: #0e1319;
  overflow: hidden;
}

.stage__screen {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  /* centralizado: os desenhos têm alturas diferentes e sem isto os menores
     ficariam grudados no topo, com um vazio embaixo */
  justify-content: center;
  gap: 12px;
  padding: clamp(16px, 2.4vw, 26px);
  opacity: 0;
  /* a tela que entra vem de baixo e um pouco menor, como se viesse de trás */
  transform: translateY(14px) scale(0.965);
  transition: opacity 380ms ease, transform 420ms cubic-bezier(0.2, 0.6, 0.2, 1);
}

.stage__screen.is-active {
  opacity: 1;
  transform: none;
}

/* sem JS ninguém recebe is-active, então a primeira tela vale como padrão */
html:not(.js) .stage__screen:first-child {
  opacity: 1;
  transform: none;
}

.stage__tag {
  align-self: flex-start;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-soft);
  border: 1px solid var(--line-inv);
  border-radius: 999px;
  padding: 5px 11px;
}

/* ---- peças dos desenhos ---- */

.sk-bar {
  display: block;
  height: 6px;
  border-radius: 3px;
  background: rgba(247, 245, 241, 0.14);
}

.sk-bar--head {
  height: 13px;
  border-radius: 4px;
  background: rgba(247, 245, 241, 0.82);
}

.sk-pill {
  display: block;
  width: 84px;
  height: 22px;
  border-radius: 999px;
  background: var(--accent);
  margin-top: 4px;
}

/* 01 briefing */
.sk-list {
  display: flex;
  flex-direction: column;
  gap: 13px;
  margin-top: 4px;
}

.sk-list__item {
  display: flex;
  align-items: center;
  gap: 12px;
}

.sk-list__item i {
  width: 14px;
  height: 14px;
  flex: none;
  border-radius: 3px;
  border: 1px solid var(--line-inv);
}

.sk-list__item.is-on i {
  border-color: var(--accent);
  background: var(--accent)
    url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Cpath%20d='M2.5%208.4l3.6%203.6L13.5%204'%20fill='none'%20stroke='%23f7f5f1'%20stroke-width='2.6'%20stroke-linecap='round'%20stroke-linejoin='round'/%3E%3C/svg%3E")
    center / 9px 9px no-repeat;
}

/* 02 estrutura */
.sk-tree {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  margin-top: 8px;
}

.sk-node {
  display: block;
  width: 74px;
  height: 30px;
  border-radius: 4px;
  border: 1px solid var(--line-inv);
  background: rgba(247, 245, 241, 0.06);
}

.sk-node--root {
  width: 112px;
  border-color: var(--accent);
  background: rgba(200, 85, 61, 0.18);
}

.sk-node--sm {
  width: 48px;
  height: 20px;
}

.sk-branch {
  width: 1px;
  height: 16px;
  background: var(--line-inv);
}

.sk-row {
  display: flex;
  gap: 12px;
  position: relative;
  padding-top: 10px;
}

/* a linha que liga a página de cima com as de baixo */
.sk-row::before {
  content: '';
  position: absolute;
  left: 20%;
  right: 20%;
  top: 0;
  height: 1px;
  background: var(--line-inv);
}

.sk-row--deep {
  gap: 9px;
}

/* 03 design */
.sk-art {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 40px;
  gap: 18px;
  margin-top: 6px;
}

.sk-art__main {
  display: flex;
  flex-direction: column;
  gap: 11px;
}

.sk-art__side {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.sk-swatch {
  display: block;
  height: 34px;
  border-radius: 4px;
}

.sk-swatch--a {
  background: var(--accent);
}

.sk-swatch--b {
  background: var(--accent-soft);
}

.sk-swatch--c {
  background: var(--paper);
}

/* 04 código */
.sk-code {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 6px;
}

.sk-code li {
  display: flex;
  gap: 9px;
  align-items: center;
}

.sk-code--in {
  padding-left: 22px;
}

.sk-code--in2 {
  padding-left: 44px;
}

.tk {
  display: block;
  height: 7px;
  border-radius: 2px;
  background: rgba(247, 245, 241, 0.16);
  width: 18%;
}

.tk--key {
  background: var(--accent-soft);
  width: 14%;
}

.tk--str {
  background: rgba(247, 245, 241, 0.5);
}

/* 05 no ar */
.sk-live {
  position: relative;
  margin-top: 6px;
  flex: 1;
  min-height: 0;
}

.sk-live__win {
  display: flex;
  flex-direction: column;
  gap: 11px;
  height: 100%;
  padding: 16px;
  border: 1px solid var(--line-inv);
  border-radius: 4px;
  background: rgba(247, 245, 241, 0.04);
}

.sk-live__bar {
  display: block;
  height: 8px;
  border-radius: 2px;
  background: var(--line-inv);
  margin-bottom: 4px;
}

/* ---- a tela 05 é a da entrega, e comemora ---- */
/* Três coisas acontecem juntas quando ela vira a ativa: um brilho abre atrás
   da janela, o selo "publicado" dá um pulso, e o confete cai.

   Tudo está preso à classe `is-active`. Isso é de propósito: uma animação só
   recomeça quando a regra passa a valer, então voltar para a etapa 05 refaz a
   festa em vez de mostrar o fim dela parado. */

.stage__screen--festa::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(
    circle at 50% 52%,
    rgba(200, 85, 61, 0.32) 0,
    transparent 62%
  );
  opacity: 0;
}

.stage__screen--festa.is-active::before {
  animation: festa-brilho 1600ms ease-out both;
}

@keyframes festa-brilho {
  0% {
    opacity: 0;
    transform: scale(0.7);
  }
  35% {
    opacity: 1;
  }
  100% {
    opacity: 0.45;
    transform: scale(1);
  }
}

.sk-confete {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}

/* Os tempos ficam aqui, e o `animation-name` fica na regra do `is-active`.
   Isso não é estilo: o atalho `animation: nome 3s curva forwards` reescreve
   TODAS as propriedades de animação, inclusive o `animation-delay` que cada
   pedaço define no seu próprio nth-child. Como a regra do `is-active` tem
   mais peso, o atalho zerava os atrasos e os 24 pedaços caíam juntos, em
   fila. Separando em propriedades soltas, cada atraso sobrevive. */
.sk-confete i {
  position: absolute;
  top: -14%;
  width: 7px;
  height: 11px;
  border-radius: 2px;
  opacity: 0;
  /* a curva acelera, como gravidade. Com uma curva que desacelera, os pedaços
     percorrem quase tudo logo no começo e depois se arrastam */
  animation-duration: 3000ms;
  animation-timing-function: cubic-bezier(0.42, 0.02, 0.72, 0.55);
  animation-fill-mode: forwards;
}

.stage__screen--festa.is-active .sk-confete i {
  animation-name: festa-confete;
}

/* e cada pedaço leva um tempo diferente para chegar embaixo */
.sk-confete i:nth-child(2n) {
  animation-duration: 3500ms;
}

.sk-confete i:nth-child(3n) {
  animation-duration: 2500ms;
}

/* cada pedaço cai de um lugar, numa hora e num tom diferente — se todos
   caíssem juntos pareceria uma cortina, não confete */
.sk-confete i:nth-child(1 ) { left:  4%; --dx:  -30px; animation-delay:    0ms; background: var(--accent); }
.sk-confete i:nth-child(2 ) { left: 10%; --dx:   22px; animation-delay:  520ms; background: var(--paper); }
.sk-confete i:nth-child(3 ) { left: 15%; --dx:  -16px; animation-delay:  180ms; background: var(--accent-soft); }
.sk-confete i:nth-child(4 ) { left: 20%; --dx:   34px; animation-delay:  980ms; background: var(--accent); }
.sk-confete i:nth-child(5 ) { left: 25%; --dx:  -24px; animation-delay:   60ms; background: var(--paper); }
.sk-confete i:nth-child(6 ) { left: 29%; --dx:   18px; animation-delay: 1420ms; background: var(--accent-soft); }
.sk-confete i:nth-child(7 ) { left: 34%; --dx:  -34px; animation-delay:  340ms; background: var(--accent); }
.sk-confete i:nth-child(8 ) { left: 38%; --dx:   14px; animation-delay:  760ms; background: var(--paper); }
.sk-confete i:nth-child(9 ) { left: 43%; --dx:  -20px; animation-delay:  120ms; background: var(--accent-soft); }
.sk-confete i:nth-child(10) { left: 47%; --dx:   30px; animation-delay: 1240ms; background: var(--accent); }
.sk-confete i:nth-child(11) { left: 51%; --dx:  -26px; animation-delay:  640ms; background: var(--paper); }
.sk-confete i:nth-child(12) { left: 55%; --dx:   20px; animation-delay: 1700ms; background: var(--accent-soft); }
.sk-confete i:nth-child(13) { left: 59%; --dx:  -12px; animation-delay:  260ms; background: var(--accent); }
.sk-confete i:nth-child(14) { left: 63%; --dx:   28px; animation-delay:  900ms; background: var(--paper); }
.sk-confete i:nth-child(15) { left: 67%; --dx:  -32px; animation-delay: 1080ms; background: var(--accent-soft); }
.sk-confete i:nth-child(16) { left: 71%; --dx:   16px; animation-delay:  420ms; background: var(--accent); }
.sk-confete i:nth-child(17) { left: 75%; --dx:  -22px; animation-delay: 1560ms; background: var(--paper); }
.sk-confete i:nth-child(18) { left: 79%; --dx:   36px; animation-delay:  700ms; background: var(--accent-soft); }
.sk-confete i:nth-child(19) { left: 83%; --dx:  -18px; animation-delay:  160ms; background: var(--accent); }
.sk-confete i:nth-child(20) { left: 87%; --dx:   24px; animation-delay: 1320ms; background: var(--paper); }
.sk-confete i:nth-child(21) { left: 90%; --dx:  -28px; animation-delay:  860ms; background: var(--accent-soft); }
.sk-confete i:nth-child(22) { left: 93%; --dx:   12px; animation-delay: 1160ms; background: var(--accent); }
.sk-confete i:nth-child(23) { left: 96%; --dx:  -36px; animation-delay:  480ms; background: var(--paper); }
.sk-confete i:nth-child(24) { left: 98%; --dx:   26px; animation-delay: 1620ms; background: var(--accent-soft); }

.sk-confete i:nth-child(3n) {
  width: 9px;
  height: 9px;
  border-radius: 50%;
}

.sk-confete i:nth-child(4n) {
  width: 5px;
  height: 14px;
}

/* o --dx é o quanto cada pedaço desliza para o lado enquanto cai: sem ele
   todos descem em linha reta e parece chuva, não confete */
@keyframes festa-confete {
  0% {
    transform: translate(0, 0) rotate(0deg);
    opacity: 0;
  }
  10% {
    opacity: 1;
  }
  85% {
    opacity: 1;
  }
  100% {
    transform: translate(var(--dx, 0), 540px) rotate(560deg);
    opacity: 0;
  }
}

.sk-live__flag {
  position: absolute;
  right: -6px;
  bottom: -10px;
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 8px 13px;
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  box-shadow: 0 14px 30px -16px rgba(0, 0, 0, 0.9);
}

/* o selo chega junto com o confete e dá um pulso, como quem diz "entregue" */
.stage__screen--festa.is-active .sk-live__flag {
  animation: festa-selo 900ms cubic-bezier(0.2, 0.8, 0.2, 1) 520ms both,
    mark-ring 1400ms ease-out 900ms;
}

@keyframes festa-selo {
  0% {
    opacity: 0;
    transform: translateY(14px) scale(0.82);
  }
  60% {
    transform: translateY(0) scale(1.08);
  }
  100% {
    opacity: 1;
    transform: none;
  }
}

/* No celular o painel não gruda. Em uma coluna só, um painel grudado no topo
   vira uma tampa: o texto das etapas passa por baixo e sai cortado no meio da
   linha. Aqui ele aparece uma vez, no começo da seção, e vai embora com a
   rolagem — o desenho ainda troca a cada etapa, só não fica na tela. */
@media (max-width: 999px) {
  .flow__stage {
    position: static;
    margin-bottom: 6px;
  }
}

/* ---- duas colunas a partir do desktop ---- */

@media (min-width: 1000px) {
  .flow__grid {
    /* a coluna do painel é maior que a do texto: ele é a peça que carrega a
       seção, e no tamanho anterior ficava miúdo perto do título */
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
    gap: clamp(40px, 5vw, 72px);
    align-items: start;
  }

  /* o painel vem primeiro no HTML para aparecer em cima no celular;
     no desktop ele volta para a coluna da direita */
  .flow__stage {
    grid-column: 2;
    grid-row: 1;
    /* centralizado na tela, na mesma altura em que o JS troca a etapa */
    top: calc(50vh - 230px);
    /* avança um pouco por fora da margem do site. A seção tem overflow:
       clip, então isso não cria rolagem lateral */
    margin-right: -6%;
  }

  .flow__steps {
    grid-column: 1;
    grid-row: 1;
    border-top: 0;
  }

  /* cada etapa ocupa quase uma tela: é esse espaço que dá tempo do painel
     trocar um desenho de cada vez */
  .flow__col {
    --rail: 88px;
    --mark: 54px;
  }

  .flow__step {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 56vh;
    padding: 0;
    opacity: 0.3;
    transition: opacity 420ms ease;
  }

  /* com a etapa ocupando meia tela, a bolinha vai para o meio dela, na mesma
     altura do título */
  .flow__mark {
    top: 50%;
    margin-top: calc(var(--mark) / -2);
  }

  .flow__mark::before {
    background-size: 24px 24px;
  }

  .js .flow__step.is-active {
    opacity: 1;
  }

  html:not(.js) .flow__step {
    opacity: 1;
    min-height: 0;
    padding: 26px 0;
  }

  html:not(.js) .flow__mark {
    top: 30px;
    margin-top: 0;
  }

  .flow__title {
    font-family: var(--font-display);
    font-weight: 400;
    letter-spacing: -0.02em;
    font-size: clamp(1.6rem, 2.6vw, 2.2rem);
    line-height: 1.1;
    margin-bottom: 16px;
  }

  .flow__desc {
    font-size: clamp(1.02rem, 1.5vw, 1.14rem);
  }
}

/* ------------------------------------------------------- 11c DEPOIMENTOS */
/* Duas ou três frases de cliente, lado a lado, logo depois dos projetos. O
   bloco está comentado no HTML até existir depoimento de verdade: frase
   inventada aqui vira propaganda falsa, não prova. */

.quotes {
  display: grid;
  gap: clamp(20px, 3vw, 30px);
  grid-template-columns: 1fr;
}

@media (min-width: 820px) {
  .quotes {
    grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  }
}

.quote {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: clamp(20px, 2.6vw, 30px);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 5px;
  border-left: 2px solid var(--accent);
}

.quote blockquote {
  font-size: 1.06rem;
  line-height: 1.55;
  color: var(--ink);
}

.quote figcaption {
  margin-top: auto;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

.quote figcaption b {
  display: block;
  color: var(--accent-ink);
  margin-bottom: 4px;
}

/* -------------------------------------------------------- 12 ORÇAMENTO */
/* Formulário que vira mensagem de WhatsApp. Duas colunas no desktop: o texto
   à esquerda, os campos à direita; no celular vira uma coluna só. */

.orcamento__grid {
  display: grid;
  gap: clamp(30px, 5vw, 56px);
  grid-template-columns: 1fr;
  align-items: start;
}

@media (min-width: 900px) {
  .orcamento__grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: clamp(48px, 6vw, 88px);
  }
}

.orcamento__texto h2 {
  margin-top: 12px;
}

.orcamento__texto > .measure {
  margin-top: 18px;
}

.orcamento__notas {
  margin-top: 28px;
  border-top: 1px solid var(--line-inv);
}

.orcamento__notas li {
  padding: 15px 0 15px 22px;
  border-bottom: 1px solid var(--line-inv);
  color: var(--muted-inv);
  font-size: 0.98rem;
  position: relative;
}

/* o tracinho terracota no lugar do marcador redondo padrão */
.orcamento__notas li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 26px;
  width: 12px;
  height: 1px;
  background: var(--accent);
}

.orcamento__form {
  display: grid;
  gap: 16px;
  padding: clamp(20px, 3vw, 30px);
  border: 1px solid var(--line-inv);
  border-radius: 6px;
  background: #12171e;
}

.campo {
  display: grid;
  gap: 7px;
}

.campo__rotulo {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted-inv);
}

.campo__caixa {
  width: 100%;
  font-family: var(--font-text);
  font-size: 1rem;
  color: var(--paper);
  background: #0e1319;
  border: 1px solid var(--line-inv);
  border-radius: 3px;
  padding: 13px 14px;
  transition: border-color var(--t), background var(--t);
}

/* a seta do select desenhada em CSS: sem isto o campo herda o visual do
   sistema operacional e destoa do resto no Windows */
.orcamento__form select.campo__caixa {
  appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--muted-inv) 50%),
    linear-gradient(135deg, var(--muted-inv) 50%, transparent 50%);
  background-position: calc(100% - 19px) 50%, calc(100% - 13px) 50%;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: 38px;
}

.campo__caixa--alta {
  resize: vertical;
  min-height: 92px;
  line-height: 1.5;
}

.campo__caixa::placeholder {
  color: #6e757e;
}

.campo__caixa:hover {
  border-color: #3a424c;
}

.campo__caixa:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}

.orcamento__enviar {
  margin-top: 4px;
  width: 100%;
}

.orcamento__aviso {
  font-size: 0.88rem;
  color: var(--muted-inv);
}

.orcamento__aviso a {
  color: var(--accent-soft);
}

/* ---------------------------------------------------------- 13 DÚVIDAS */
/* <details>/<summary> nativo: abre e fecha sem JavaScript nenhum. */

.faq {
  border-top: 1px solid var(--line);
}

.faq__item {
  border-bottom: 1px solid var(--line);
}

.faq__item summary {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  padding: 20px 0;
  cursor: pointer;
  font-weight: 700;
  font-size: 1.08rem;
  line-height: 1.3;
  transition: color var(--t);
  /* tira o triangulinho padrão do navegador, nos dois motores */
  list-style: none;
}

.faq__item summary::-webkit-details-marker {
  display: none;
}

.faq__item summary:hover {
  color: var(--accent-ink);
}

.faq__item summary::after {
  content: '+';
  flex: none;
  font-family: var(--font-mono);
  font-size: 1.1rem;
  line-height: 1;
  color: var(--accent-ink);
}

.faq__item[open] summary::after {
  content: '−';
}

.faq__a {
  padding-bottom: 24px;
  color: var(--muted);
  max-width: 62ch;
}

.js .faq__item[open] .faq__a {
  animation: rise-in 320ms cubic-bezier(0.2, 0.6, 0.2, 1) both;
}

/* ------------------------------------------------- 14 CHAMADA E CONTATO */

.cta__head {
  max-width: 34ch;
}

.cta__lede {
  color: var(--muted-inv);
  max-width: 48ch;
  margin-top: 20px;
}

.cta .contact-list {
  margin-top: clamp(48px, 6vw, 72px);
}

/* em fundo claro a lista funciona igual: as divisórias e o rótulo só trocam
   de cor dentro de .on-dark */
.on-dark .contact-list,
.on-dark .contact-item {
  border-color: var(--line-inv);
}

.on-dark .contact-item dt {
  color: var(--muted-inv);
}

.on-dark .contato-link {
  color: var(--paper);
}

/* em fundo escuro o terracota cheio some; quem aparece é a variante clara */
.on-dark .contato-link .ico {
  stroke: var(--accent-soft);
}

.on-dark .contato-link span {
  border-bottom-color: var(--line-inv);
}

@media (min-width: 940px) {
  .cta__head {
    max-width: none;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: clamp(40px, 6vw, 80px);
  }

  .cta__head h2 {
    grid-row: span 2;
  }

  .cta__lede {
    margin-top: 0;
  }

  .cta__head .btn-row {
    margin-top: 26px;
  }
}

/* ---------------------------------------------------------- 14 CONTATO */

.contact-list {
  display: grid;
  grid-template-columns: 1fr;
  border-top: 1px solid var(--line);
}

.contact-item {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 20px 0;
  border-bottom: 1px solid var(--line);
}

.contact-item dt {
  color: var(--muted);
}

.contact-item dd {
  margin: 0;
  font-size: 1.06rem;
}

/* O link de contato com ícone: mesmo desenho da apresentação em PDF. O SVG
   está escrito no HTML, então não existe fonte de ícone nem arquivo para
   baixar — a página segue sem nenhuma requisição para fora.

   O sublinhado fica no <span>, e não no <a>: passando o traço por baixo do
   ícone também, ele encosta no desenho e parece defeito de renderização. */
.contato-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--ink);
  text-decoration: none;
}

.contato-link .ico {
  flex: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: var(--accent-ink);
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.contato-link span {
  border-bottom: 1px solid var(--line);
  padding-bottom: 2px;
  transition: border-color var(--t);
}

.contato-link:hover span {
  border-bottom-color: currentColor;
}

@media (min-width: 820px) {
  .contact-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: clamp(28px, 4vw, 56px);
  }

  .contact-item {
    border-bottom: 0;
    padding: 24px 0 0;
  }
}

/* os quatro só cabem lado a lado quando há largura para o e-mail inteiro */
@media (min-width: 1120px) {
  .contact-list {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* ----------------------------------------------------------- 15 RODAPÉ */

.site-footer {
  background: var(--near);
  color: var(--paper);
  border-top: 1px solid var(--line-inv);
  padding-block: 34px 40px;
}

.site-footer__in {
  display: flex;
  flex-wrap: wrap;
  gap: 16px 32px;
  justify-content: space-between;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted-inv);
}

.site-footer a {
  color: var(--muted-inv);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}

.site-footer a:hover {
  color: var(--paper);
  border-bottom-color: var(--line-inv);
}

/* ------------------------------------------------- 17 REVELAÇÃO NO SCROLL */
/* o conteúdo nasce visível; a classe .js só é adicionada pelo inline do
   <head>, e só quando o navegador tem suporte e o movimento não está
   reduzido. Se este bloco inteiro sumir, o site continua legível. */

.js .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 520ms ease, transform 520ms cubic-bezier(0.2, 0.6, 0.2, 1);
}

.js .reveal.is-in {
  opacity: 1;
  transform: none;
}

/* cascata: os filhos entram um atrás do outro, e não em bloco. O container
   continua sendo o .reveal — quem ganha atraso são as crianças. */
.js .reveal--stagger {
  opacity: 1;
  transform: none;
}

.js .reveal--stagger > * {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 560ms ease, transform 560ms cubic-bezier(0.2, 0.6, 0.2, 1);
}

.js .reveal--stagger.is-in > * {
  opacity: 1;
  transform: none;
}

.js .reveal--stagger > *:nth-child(1) { transition-delay: 0ms; }
.js .reveal--stagger > *:nth-child(2) { transition-delay: 70ms; }
.js .reveal--stagger > *:nth-child(3) { transition-delay: 140ms; }
.js .reveal--stagger > *:nth-child(4) { transition-delay: 210ms; }
.js .reveal--stagger > *:nth-child(5) { transition-delay: 280ms; }
.js .reveal--stagger > *:nth-child(6) { transition-delay: 350ms; }
.js .reveal--stagger > *:nth-child(7) { transition-delay: 420ms; }
.js .reveal--stagger > *:nth-child(n + 8) { transition-delay: 490ms; }

/* ---- entrada dos cards de projeto ---- */

/* Antes a lista inteira era um `.reveal--stagger` só: os sete entravam
   quando o topo da lista aparecia, então do terceiro em diante a animação
   acontecia fora da tela e a pessoa nunca via. Agora cada card é um `.reveal`
   por conta própria, e anima quando chega a vez dele.

   As peças de dentro usam as propriedades `scale` e `translate` separadas, e
   não `transform`: assim o efeito de entrada não briga com o `transform` que
   o mouse aplica na mesma peça. */

.js .project.reveal .project__shot {
  scale: 0.98;
  transition: scale 640ms cubic-bezier(0.2, 0.6, 0.2, 1),
    box-shadow var(--t), border-color var(--t);
}

.js .project.reveal.is-in .project__shot {
  scale: 1;
}

/* o celular chega depois da janelinha, vindo da direita e de baixo */
.js .project.reveal .mini-phone {
  opacity: 0;
  translate: 22px 14px;
  transition: opacity 520ms ease 170ms,
    translate 660ms cubic-bezier(0.2, 0.6, 0.2, 1) 170ms;
}

.js .project.reveal.is-in .mini-phone {
  opacity: 1;
  translate: none;
}

/* ------------------------------------------------ 18 ENTRADA DA ABERTURA */
/* A abertura não espera rolagem: ela entra sozinha assim que a página
   carrega, em cascata de cima para baixo, terminando nas telas. */

@keyframes rise-in {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
}

.js .hero--home .hero__text > *,
.js .hero--home .hero__art {
  animation: rise-in 720ms cubic-bezier(0.2, 0.6, 0.2, 1) both;
}

.js .hero--home .hero__text > *:nth-child(1) { animation-delay: 60ms; }
.js .hero--home .hero__text > *:nth-child(2) { animation-delay: 180ms; }
.js .hero--home .hero__text > *:nth-child(3) { animation-delay: 300ms; }
.js .hero--home .hero__text > *:nth-child(4) { animation-delay: 400ms; }
.js .hero--home .hero__art { animation-delay: 220ms; }

/* os contornos do fundo chegam por último, bem devagar, para não competir
   com o título na primeira olhada */
.js .hero--home .deco {
  animation: fade-in 1400ms ease 420ms both;
}

@keyframes fade-in {
  from {
    opacity: 0;
  }
}

/* --------------------------------------------- 18b DEMONSTRAÇÃO DO PROJETO */

/* A janela que abre por cima da página com o site do cliente rodando dentro.
   O `hidden` do HTML é quem mantém tudo fechado; o main.js tira e põe. */

.modal[hidden] {
  display: none;
}

.modal {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  padding: clamp(10px, 2vw, 28px);
}

.modal__veu {
  position: absolute;
  inset: 0;
  background: rgba(12, 15, 19, 0.78);
  animation: modal-veu 200ms ease-out;
}

.modal__caixa {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(1320px, 100%);
  height: min(880px, 100%);
  border: 1px solid var(--line-inv);
  border-radius: 8px;
  background: #0e1319;
  overflow: hidden;
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.9);
  animation: modal-caixa 220ms cubic-bezier(0.2, 0.6, 0.2, 1);
}

@keyframes modal-veu {
  from {
    opacity: 0;
  }
}

@keyframes modal-caixa {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.99);
  }
}

.modal__barra {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line-inv);
  background: #12171e;
  color: var(--paper);
}

.modal__titulo {
  flex: 1;
  min-width: 0;
  font-family: var(--font-text);
  font-weight: 700;
  font-size: 1.02rem;
  letter-spacing: -0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* o par de botões desktop/celular, colados como um interruptor só */
.modal__telas {
  display: flex;
  border: 1px solid var(--line-inv);
  border-radius: 3px;
  overflow: hidden;
  flex: none;
}

.modal__tela {
  border: 0;
  background: transparent;
  color: var(--muted-inv);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 9px 14px;
  cursor: pointer;
  transition: background var(--t), color var(--t);
}

.modal__tela + .modal__tela {
  border-left: 1px solid var(--line-inv);
}

.modal__tela:hover {
  color: var(--paper);
}

.modal__tela.is-on {
  background: var(--accent);
  color: #fff;
}

.modal__sair {
  flex: none;
  color: var(--accent-soft);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.modal__fechar {
  flex: none;
  width: 34px;
  height: 34px;
  border: 1px solid var(--line-inv);
  border-radius: 3px;
  background: transparent;
  color: var(--paper);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  transition: background var(--t), border-color var(--t);
}

.modal__fechar:hover {
  background: var(--accent);
  border-color: var(--accent);
}

/* o palco é a área onde o print aparece. Ele rola sozinho: assim um print de
   página inteira, bem mais alto que a janela, continua servindo sem precisar
   de outra regra. O xadrez do fundo é o que aparece nas sobras dos lados. */
.modal__palco {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow: auto;
  background:
    repeating-conic-gradient(#151b23 0% 25%, #11161d 0% 50%) 50% / 22px 22px;
  display: grid;
  justify-items: center;
  /* `safe` é o que importa: print curto fica centrado na vertical, print de
     página inteira encosta no topo e rola — sem cortar o começo dele */
  align-items: safe center;
}

.modal__print {
  display: block;
  width: 100%;
  height: auto;
  background: #fff;
}

/* No celular o print de desktop encolhido vira uma tirinha ilegível. Ele
   entra numa largura mínima e o palco rola para o lado — ver de perto e
   arrastar é melhor do que ver tudo e não ler nada. */
@media (max-width: 700px) {
  .modal__palco:not(.is-mobile) .modal__print {
    width: auto;
    min-width: 620px;
  }
}

/* no modo celular o print fica estreito e centrado, com cara de aparelho */
.modal__palco.is-mobile .modal__print {
  width: auto;
  /* o `min()` é o que impede a rolagem lateral numa tela mais estreita que os
     400px do aparelho desenhado */
  max-width: min(400px, 100%);
  margin: 16px 0;
  border-radius: 12px;
  box-shadow: 0 20px 50px -20px rgba(0, 0, 0, 0.8);
}

/* aviso de print que ainda não existe na pasta. Aparece no lugar da imagem
   quebrada, com o caminho para o site de verdade. */
.modal__aviso {
  max-width: 46ch;
  margin: auto;
  padding: 30px;
  text-align: center;
  color: var(--muted-inv);
  font-size: 0.98rem;
}

.modal__aviso strong {
  display: block;
  color: var(--paper);
  font-size: 1.06rem;
  margin-bottom: 10px;
}

.modal__aviso .btn {
  margin-top: 18px;
}

/* fecha a rolagem da página enquanto a janela está aberta, senão o fundo
   corre atrás do site que está sendo mostrado */
html.modal-aberto,
html.modal-aberto body {
  overflow: hidden;
}

@media (max-width: 700px) {
  .modal__barra {
    gap: 10px;
  }

  .modal__titulo {
    flex-basis: 100%;
  }
}

/* ------------------------------------------------------- 19 PARALAXE */
/* O main.js escreve --px e --py na abertura (de -1 a 1, conforme onde o
   mouse está). Só dois elementos leem essas variáveis, e cada um anda para
   um lado: é a diferença entre eles que dá a sensação de profundidade.
   Sem JS as variáveis não existem, o valor cai no 0 do fallback e nada
   se move. Nenhum dos dois tem animação própria — as animações estão nos
   filhos, para os dois efeitos não brigarem pela mesma propriedade. */

.hero--home .deco,
.hero--home .mock {
  transition: transform 420ms cubic-bezier(0.2, 0.6, 0.2, 1);
}

.hero--home .deco {
  transform: translate3d(
    calc(var(--px, 0) * 16px),
    calc(var(--py, 0) * 16px),
    0
  );
}

.hero--home .mock {
  transform: translate3d(
    calc(var(--px, 0) * -12px),
    calc(var(--py, 0) * -12px),
    0
  );
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .js .reveal {
    opacity: 1;
    transform: none;
  }

  /* o painel do Processo é o único elemento que gira acompanhando a rolagem.
     Com movimento reduzido ele já nasce reto e fica parado. */
  .stage {
    transform: none;
  }
}

/* ------------------------------------------------------------ 20 IMPRESSO */

@media print {
  .site-header,
  .btn-row,
  .skip,
  .progress,
  .marquee,
  .deco {
    display: none;
  }

  body {
    background: #fff;
    color: #000;
  }

  .hero--home {
    background: #fff;
  }

  /* no papel não existe abrir e fechar: todas as respostas saem impressas */
  .faq__item .faq__a {
    display: block;
  }
}
