/* ==========================================================================
   Kukii Store: estilo.css
   Uma única folha de estilo para as nove páginas.

   Índice
    1. Tokens: cores, tipografia, espaçamento, raios, movimento
    2. Cor por categoria (--cat)
    3. Base
    4. Utilitários
    5. Botões
    6. Cabeçalho
    7. Rodapé
    8. Blocos partilhados: secções, placeholders, passos, marcas a confirmar
    9. Página inicial
   10. Páginas de categoria: faixa e filtros
   11. Cartões de produto
   12. Gavetas: painel de produto e carrinho
   13. Formulários
   14. Aviso "juntaste ao carrinho"
   15. Movimento reduzido
   ========================================================================== */


/* 1. Tokens ----------------------------------------------------------------
   Regra: no resto do ficheiro não há cores, tamanhos ou espaços escritos à
   mão. Tudo vem daqui. Mudar um valor aqui muda-o no site todo.
   -------------------------------------------------------------------------- */
:root {
  /* Base: fundo claro e neutro, para as peças saltarem */
  --fundo: #FFFFFF;          /* branco limpo: as cores das peças saltam */
  --fundo-alt: #F1F2F4;      /* superfície neutra fria dos blocos: nada de creme nem pêssego */
  --cartao: #FFFFFF;
  --texto: #2B1D17;
  --texto-suave: #6B564A;
  --linha: #E3E5E9;          /* só separadores decorativos, nunca texto */
  --branco: #FFFFFF;

  /* Marca: só onde a marca fala (encomendar, WhatsApp, passos, selo) */
  --marca: #CE2B22;
  --marca-escura: #A61F18;   /* estado hover dos botões da marca (7.4:1 com branco) */

  /* Marcador [A CONFIRMAR]: propositadamente fora da paleta, para saltar à vista */
  --confirmar: #FFE08A;

  /* Cor de cada categoria, tirada das peças reais.
     Todas verificadas: >= 4.5:1 como texto sobre os três fundos claros
     e com texto branco por cima. */
  /* Uma cor por categoria. Todas medidas contra o branco: a mais fraca dá
     5.48:1 e a mais forte 8.22:1, com o mínimo do WCAG AA em 4.5:1. Estão
     também espalhadas pelo círculo das cores, para duas categorias nunca se
     confundirem: a que mais se aproxima de outra é o grafite dos
     articulados, e essa é quase cinzenta, por isso lê-se à parte. */
  --c-natal: #2A5F49;          /* verde escuro */
  --c-articulados: #4A5261;    /* grafite */
  --c-decoracao: #9E4759;      /* vinho */
  --c-escola: #A65128;         /* laranja queimado */
  --c-criancas: #6B4A78;       /* roxo */
  --c-iluminados: #464C99;     /* índigo */
  --c-lembrancas: #A8447F;     /* magenta */
  --c-dia-do-pai: #3A6483;     /* azul */
  --c-dia-da-mae: #B03A4E;     /* carmim */
  --c-porta-chaves: #2D6B69;   /* verde-azulado */
  --c-religiosos: #7D6634;     /* dourado */
  --c-toppers: #52702F;        /* verde-musgo */

  /* Tipografia
     Duas famílias com dois trabalhos: títulos (Bricolage) e texto (Karla). */
  --f-titulo: "Bricolage Grotesque", system-ui, sans-serif;
  --f-texto: "Karla", system-ui, sans-serif;

  /* Escala com saltos grandes: cada nível é visivelmente diferente do seguinte.
     clamp(mínimo, crescimento com o ecrã, máximo) */
  /* QUATRO ESTILOS DE TEXTO, e nada mais. Títulos na Bricolage (o da
     página, o de secção, e o Título dos cartões e cartões de painel), texto
     corrido a --t-base e pequeno a --t-pequeno, na Karla. A cor e o negrito
     dizem o que a coisa é; o tamanho não muda por causa disso. Só os títulos
     podem acompanhar a largura do ecrã. */
  --t-pequeno: 0.875rem;                                   /* 14px: legendas, rodapé */
  --t-base: 1.0625rem;                                     /* 17px: texto corrido */
  --t-medio: 1.3125rem;                                    /* 21px: h3, nomes de produto, intro */
  --t-grande: clamp(1.5rem, 1.25rem + 1.1vw, 2.25rem);     /* 24 -> 36px: h2 */
  --t-enorme: clamp(2rem, 1rem + 2.6vw, 3.25rem);        /* 32 -> 52px: h1, o mesmo em todo o site */

  /* Espaçamento: seis degraus, e só seis. Cada um tem um papel, e a
     pergunta a fazer antes de escolher é "que distância é esta?", não
     "quantos píxeis ficam bem aqui?". Havia nove; os que quase não se
     usavam (32, 64 e 96) juntaram-se ao vizinho mais próximo.
       --e-1   4px  colado: ícone e texto, o rótulo e a ajuda dele
       --e-2   8px  perto: coisas da mesma peça (botões lado a lado, chips)
       --e-3  12px  recuo: entre cartões, do título ao texto, do bloco à
                    borda do ecrã no telemóvel
       --e-4  16px  dentro: o enchimento de cartões, campos e caixas
       --e-5  24px  bloco: entre blocos da mesma secção
       --e-6  48px  secção: entre secções */
  --e-1: 0.25rem;
  --e-2: 0.5rem;
  --e-3: 0.75rem;
  --e-4: 1rem;
  --e-5: 1.5rem;
  --e-6: 3rem;

  /* Os papéis com nome, para as regras dizerem o que querem */
  --e-titulo: var(--e-3);   /* título -> texto logo por baixo */
  --e-bloco: var(--e-5);    /* entre blocos dentro da mesma secção */
  --e-secao: var(--e-6);    /* entre secções */
  --margem: var(--e-4);     /* margem lateral da página */

  /* Três raios, e só três */
  --raio-cartao: 14px;      /* fotos, cartões, campos */
  --raio-bloco: 28px;       /* banners e blocos grandes */
  --raio-botao: 999px;      /* botões e filtros: redondos */

  /* Movimento: curto, só em resposta a uma ação */
  --dur: 180ms;

  /* Outros */
  --alvo: 44px;             /* alvo de toque mínimo */
  /* Largura máxima do conteúdo, e com ela a margem lateral da página.
     A margem de cada lado é metade do que sobra: (ecrã - conteúdo) / 2.
     Para a partir ao meio, o conteúdo tem de crescer até meio caminho
     entre a largura do ecrã e a largura antiga, que era 72rem. A média das
     duas é exactamente isso, e é o que a conta faz.
     Exemplos: num ecrã de 1280 a margem passa de 64px para 32; num de 1440,
     de 144 para 72; num de 1920, de 384 para 192.
     O tecto de 100rem existe para ecrãs muito largos, onde continuar a
     abrir daria linhas e cartões grandes de mais. A partir daí a margem
     volta a crescer. */
  --largura-antiga: 72rem;
  --largura: min(100rem, calc((100vw + var(--largura-antiga)) / 2));
  --altura-topo: 3.75rem;   /* altura da barra do topo (telemóvel) */

  /* Cor da página atual. Na página inicial é a cor da marca. */
  --cat: var(--marca);
}

@media (min-width: 48rem) {
  :root {
    /* A moldura da página no computador. Não é um espaço entre coisas,
       é a margem do ecrã, por isso fica fora da escala. */
    --margem: 2rem;
  }
}


/* 2. Cor por categoria ----------------------------------------------------
   Um único conjunto de regras serve dois usos:
   - <body data-cat="natal"> pinta a página inteira de Natal;
   - <li data-cat="natal"> pinta só aquele cartão na página inicial.
   Como é CSS e não JavaScript, a faixa já nasce com a cor certa.
   -------------------------------------------------------------------------- */
[data-cat="natal"]        { --cat: var(--c-natal); }
[data-cat="articulados"]  { --cat: var(--c-articulados); }
[data-cat="decoracao"]    { --cat: var(--c-decoracao); }
[data-cat="escola"]       { --cat: var(--c-escola); }
[data-cat="criancas"]     { --cat: var(--c-criancas); }
[data-cat="iluminados"]   { --cat: var(--c-iluminados); }
[data-cat="dia-da-mae"]   { --cat: var(--c-dia-da-mae); }
[data-cat="dia-do-pai"]   { --cat: var(--c-dia-do-pai); }
/* Os dois códigos antigos ficam com a cor das Lembranças: um carrinho
   guardado antes da mudança ainda os pode trazer. */
[data-cat="lembrancas"],
[data-cat="aniversarios"],
[data-cat="batizados"]    { --cat: var(--c-lembrancas); }
[data-cat="porta-chaves"] { --cat: var(--c-porta-chaves); }
[data-cat="religiosos"]   { --cat: var(--c-religiosos); }
[data-cat="toppers"]      { --cat: var(--c-toppers); }


/* 3. Base ----------------------------------------------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  /* ao saltar para uma âncora, não esconder o título atrás do topo fixo */
  scroll-padding-top: calc(var(--altura-topo) + var(--e-4));
}

/* Os saltos do menu ("Sobre nós", "Contactos") são instantâneos, de propósito.
   Um scroll suave ao longo de três mil píxeis demora segundos, muito acima
   dos 300ms que este site se impõe, e deixa a pessoa a ver a página a passar
   sem poder fazer nada. O salto seco é também o comportamento que o browser
   tem por omissão, e portanto o que as pessoas esperam. */

body {
  margin: 0;
  /* devolve o espaço do cabeçalho, que passou a fixed e saiu do fluxo.
     O +1px é a linha fina por baixo dele. */
  padding-top: calc(var(--altura-topo) + 1px);
  background: var(--fundo);
  color: var(--texto);
  font-family: var(--f-texto);
  font-size: var(--t-base);
  line-height: 1.55;
}

/* bloqueia o scroll da página por trás quando uma gaveta está aberta */
body:has(dialog[open]) { overflow: hidden; }

h1, h2, h3 {
  margin: 0;
  font-family: var(--f-titulo);
  font-optical-sizing: auto;
  line-height: 1.08;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
h1 { font-size: var(--t-enorme); font-weight: 800; }
h2 { font-size: var(--t-grande); font-weight: 800; }
h3 { font-size: var(--t-medio); font-weight: 700; letter-spacing: -0.01em; }

p { margin: 0; max-width: 65ch; text-wrap: pretty; }
ul, ol { margin: 0; padding: 0; }

a { color: inherit; text-underline-offset: 0.18em; }

img, svg { display: block; max-width: 100%; }

button, input, textarea, select { font: inherit; color: inherit; }

/* Foco desenhado de propósito, na cor da categoria.
   Nunca "outline: none" sem alternativa. */
:focus-visible {
  outline: 3px solid var(--cat);
  outline-offset: 2px;
}


/* 4. Utilitários ---------------------------------------------------------- */

/* Esconde do ecrã mas mantém para leitores de ecrã */
.vh {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.contentor {
  width: min(100% - 2 * var(--margem), var(--largura));
  margin-inline: auto;
}

.saltar {
  position: absolute;
  left: var(--e-4);
  top: var(--e-2);
  z-index: 100;
  padding: var(--e-2) var(--e-4);
  background: var(--texto);
  color: var(--branco);
  border-radius: var(--raio-cartao);
  transform: translateY(-200%);
}
.saltar:focus { transform: none; }


/* 5. Botões ----------------------------------------------------------------
   Redondos (raio-botao). Sem setas nem ícones decorativos no texto.
   Só mudam de cor ao passar o rato: não sobem, não crescem.
   -------------------------------------------------------------------------- */
.botao {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--e-2);
  min-height: 48px;
  padding: var(--e-2) var(--e-5);
  border: 2px solid transparent;
  border-radius: var(--raio-botao);
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur), color var(--dur), border-color var(--dur);
}

/* Encomendar, WhatsApp: a marca fala */
.botao--marca { background: var(--marca); color: var(--branco); }
.botao--marca:hover { background: var(--marca-escura); }

/* Navegação principal: escuro, neutro */
.botao--escuro { background: var(--texto); color: var(--branco); }
.botao--escuro:hover { background: var(--texto-suave); }

/* Secundário: a alternativa ao lado do botão principal, sem competir com
   ele. Só o contorno, na cor do texto. */
.botao--contorno { background: transparent; color: var(--texto); border-color: var(--texto); }
.botao--contorno:hover { background: var(--fundo-alt); }

/* Na cor da categoria a que o botão leva. O data-cat no próprio botão
   define o --cat, por isso funciona em qualquer página. */
.botao--cat { background: var(--cat); color: var(--branco); }
.botao--cat:hover { background: color-mix(in srgb, var(--cat) 82%, black); }

/* Sobre um fundo cheio de cor */
.botao--claro { background: var(--branco); color: var(--cat); }
.botao--claro:hover { background: var(--fundo-alt); }

.botao:disabled,
.botao[aria-disabled="true"] {
  background: var(--linha);
  color: var(--texto-suave);
  border-color: transparent;
  cursor: not-allowed;
}

.botao--largo { width: 100%; }

/* Botão só com texto sublinhado (remover, limpar o carrinho) */
.botao-texto {
  min-height: var(--alvo);
  padding: 0 var(--e-2);
  border: 0;
  background: none;
  color: var(--texto-suave);
  font-size: var(--t-pequeno);
  text-decoration: underline;
  text-underline-offset: 0.18em;
  cursor: pointer;
}
.botao-texto:hover { color: var(--texto); }


/* 6. Cabeçalho -------------------------------------------------------------
   Desenhado pelo site.js. Aqui reserva-se a altura antes de o JavaScript
   correr, para a página não saltar quando o cabeçalho aparece.
   position: sticky comporta-se como fixo, mas sem ser preciso empurrar o
   conteúdo para baixo à mão.
   -------------------------------------------------------------------------- */
/* fixed e não sticky, de propósito.
   Com sticky, o browser continua a achar que o cabeçalho está lá em cima no
   documento, mesmo estando colado ao ecrã. Ao dar foco a qualquer coisa lá
   dentro (o campo de procura, uma tab, o carrinho) ia "buscá-lo", e a página
   saltava para o topo. Com fixed o cabeçalho está fora do fluxo e o browser
   sabe que já está à vista, por isso não scrolla.
   O espaço que ele deixaria de ocupar é devolvido no padding-top do body. */
.topo {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  min-height: var(--altura-topo);
  background: var(--fundo);
  border-bottom: 1px solid var(--linha);
}

.topo__barra {
  display: flex;
  align-items: center;
  flex-wrap: wrap;   /* em telemóvel o menu cai para a linha de baixo */
  gap: var(--e-2);
  min-height: 3.75rem;
}

/* Logo: pequeno, sempre */
.logo {
  display: inline-flex;
  align-items: center;
  min-height: var(--alvo);
  margin-right: auto;
  text-decoration: none;
}

/* O logo tem muito detalhe e muita cor: fica pequeno para não competir com
   as peças. Só se fixa a altura; a largura segue a proporção do ficheiro. */
.logo__img {
  height: var(--alvo);
  width: auto;
}
.rodape .logo__img { height: 3.5rem; }

.topo__menu {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--alvo);
  height: var(--alvo);
  margin-left: calc(-1 * var(--e-2));
  padding: 0;
  border: 0;
  background: none;
  border-radius: var(--raio-cartao);
  cursor: pointer;
}
.topo__menu svg { width: 24px; height: 24px; }
.topo__menu .icone-fechar { display: none; }
.topo--aberto .topo__menu .icone-abrir { display: none; }
.topo--aberto .topo__menu .icone-fechar { display: block; }

/* A lupa tem a mesma forma do botão do menu: um alvo de 44px, sem caixa.
   Só existe no telemóvel (ver a secção do telemóvel, no fim). */
.topo__lupa {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--alvo);
  height: var(--alvo);
  padding: 0;
  border: 0;
  background: none;
  border-radius: var(--raio-cartao);
  cursor: pointer;
}
.topo__lupa svg { width: 22px; height: 22px; }
.topo--procura .topo__lupa { color: var(--cat); }
@media (min-width: 64rem) {
  .topo__lupa { display: none; }
}

/* Botão do carrinho */
.botao-carrinho {
  display: inline-flex;
  align-items: center;
  gap: var(--e-2);
  min-height: var(--alvo);
  padding-inline: var(--e-3) var(--e-2);
  border: 2px solid var(--texto);
  border-radius: var(--raio-botao);
  background: var(--cartao);
  font-weight: 700;
  cursor: pointer;
  transition: background-color var(--dur);
}
.botao-carrinho:hover { background: var(--fundo-alt); }
.botao-carrinho svg { width: 20px; height: 20px; flex: none; }

.botao-carrinho__num {
  display: inline-grid;
  place-items: center;
  min-width: 1.75rem;
  height: 1.75rem;
  padding: 0 var(--e-2);
  border-radius: var(--raio-botao);
  background: var(--marca);
  color: var(--branco);
  font-size: var(--t-pequeno);
}
.botao-carrinho__num.pulsar { animation: pulsar 200ms ease-out; }

@keyframes pulsar {
  50% { transform: scale(1.25); }
}

/* WhatsApp: no telemóvel flutua no canto inferior direito */
.botao-whatsapp {
  position: fixed;
  right: var(--e-4);
  bottom: var(--e-4);
  z-index: 40;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--e-2);
  width: 3.5rem;
  height: 3.5rem;
  border-radius: var(--raio-botao);
  background: var(--marca);
  color: var(--branco);
  font-weight: 700;
  text-decoration: none;
  transition: background-color var(--dur);
}
.botao-whatsapp:hover { background: var(--marca-escura); }
.botao-whatsapp svg {
  width: 21px;
  height: 21px;
  flex: none;
  /* Centrado pelo peso, não pela caixa. O símbolo do WhatsApp tem o bico
     do balão em baixo à esquerda: a caixa está centrada, mas a mancha
     branca não, e é a mancha que o olho centra. Medi o centro do peso
     pintado e fica 0.76 e 0.67 unidades (de 24) para a esquerda e para
     baixo. Este translate devolve-o ao centro do círculo. Em percentagem
     do próprio ícone, para valer a qualquer tamanho a que ele apareça. */
  transform: translate(3.2%, -2.8%);
}
.botao-whatsapp__texto {
  /* no telemóvel só se vê o ícone; o texto fica para leitores de ecrã */
  position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%);
}

/* Menu principal: quatro entradas, e as sete categorias dentro de
   "Os nossos produtos". No telemóvel é uma lista que abre por baixo da
   barra; em ecrã largo é uma linha com um menu suspenso. */
.topo__nav { display: none; }
/* o menu aberto ocupa a linha inteira, por baixo do logo */
.topo--aberto .topo__nav {
  display: block;
  flex-basis: 100%;
  max-height: calc(100dvh - 3.75rem);
  overflow-y: auto;
  border-top: 1px solid var(--linha);
  animation: menu-abrir var(--dur) ease-out;
}
@keyframes menu-abrir {
  from { opacity: 0; transform: translateY(calc(-1 * var(--e-2))); }
}

/* ">" para a regra não cair também na lista de dentro do menu de produtos */
.topo__nav > ul {
  list-style: none;
  padding-block: var(--e-2) var(--e-4);
}
.nav__sub { list-style: none; padding: 0 0 var(--e-2); }

/* Uma só regra para as ligações e para o "Os nossos produtos", que é um
   <summary>: assim têm o mesmo tamanho, o mesmo peso e o mesmo alvo. */
.nav__ligacao {
  display: flex;
  align-items: center;
  min-height: 48px;
  padding: 0 var(--e-4);
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
}
.nav__ligacao:hover { color: var(--cat); }
.nav__ligacao[aria-current="page"] { color: var(--cat); }

/* O <summary> traz um triângulo por omissão. Escondê-lo obriga a pôr outra
   pista de direção no lugar: esta seta, que roda quando o menu abre. */
.nav__resumo { list-style: none; justify-content: space-between; gap: var(--e-3); }
.nav__resumo::-webkit-details-marker { display: none; }
.nav__resumo::after {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--dur);
}
.nav__menu[open] > .nav__resumo::after { transform: translateY(1px) rotate(-135deg); }

/* As sete categorias. A barra na cor de cada uma organiza a lista e diz,
   sem texto, que cada categoria tem a sua cor. */
.nav__sub a {
  display: flex;
  align-items: center;
  min-height: 48px;
  padding: 0 var(--e-4);
  border-left: 4px solid var(--cat);
  margin-left: var(--e-4);
  font-size: var(--t-pequeno);
  font-weight: 700;
  text-decoration: none;
}
.nav__sub a:hover,
.nav__sub a[aria-current="page"] { color: var(--cat); background: var(--cartao); }

@media (min-width: 64rem) {
  .topo__menu { display: none; }

  .topo__barra { gap: var(--e-4); }

  /* No cabeçalho é só o ícone, num círculo, para ocupar o mínimo.
     O nome fica para os leitores de ecrã. */
  .botao-whatsapp {
    position: static;
    width: var(--alvo);
    height: var(--alvo);
    padding: 0;
  }
  .botao-whatsapp svg { width: 22px; height: 22px; }

  .topo__barra { flex-wrap: nowrap; }
  .logo { margin-right: 0; }

  .topo__nav,
  .topo--aberto .topo__nav {
    display: block;
    flex-basis: auto;
    margin-right: auto;   /* empurra WhatsApp e carrinho para a direita */
    max-height: none;
    border-top: 0;
    animation: none;
  }
  .topo__nav > ul {
    display: flex;
    gap: var(--e-2);
    padding: 0;
  }

  .nav__ligacao {
    min-height: 3rem;
    padding: 0 var(--e-3);
    border-bottom: 3px solid transparent;
    white-space: nowrap;
  }
  .nav__ligacao:hover,
  .nav__ligacao[aria-current="page"] { border-bottom-color: var(--cat); }
  /* o menu aberto marca-se como uma entrada ativa */
  .nav__menu[open] > .nav__resumo { color: var(--cat); border-bottom-color: var(--cat); }

  /* O menu de produtos abre por cima da página, ancorado à sua entrada. */
  .nav__menu { position: relative; }
  .nav__sub {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 60;
    min-width: 17rem;
    padding: var(--e-2) 0;
    background: var(--cartao);
    border: 1px solid var(--linha);
    border-radius: 0 0 var(--raio-cartao) var(--raio-cartao);
    animation: menu-abrir var(--dur) ease-out;
  }
  .nav__sub a {
    margin-left: 0;
    min-height: var(--alvo);
  }
}


/* 7. Rodapé --------------------------------------------------------------- */
.rodape {
  padding-block: var(--e-5) calc(2 * var(--e-5));   /* o dobro em baixo, para o WhatsApp flutuante não tapar o fim */
  background: var(--fundo-alt);
  border-top: 1px solid var(--linha);
  font-size: var(--t-pequeno);
  color: var(--texto-suave);
}

.rodape__grelha {
  display: grid;
  gap: var(--e-5);
}

.rodape__titulo {
  margin-bottom: var(--e-2);
  font-size: var(--t-medio);
  color: var(--texto);
}

.rodape__marca p { margin-top: var(--e-3); }

.rodape ul { list-style: none; }
.rodape li a {
  display: inline-flex;
  align-items: center;
  min-height: var(--alvo);
}

/* Redes: ícone e nome na mesma linha. O ícone é decorativo, o nome está
   sempre escrito ao lado, por isso a ligação lê-se bem sem ele. */
.redes a { gap: var(--e-2); }
.redes svg { width: 20px; height: 20px; flex: none; }
.rodape a { color: var(--texto); }

.rodape__fim {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--e-3);
  margin-top: var(--e-6);
  padding-top: var(--e-5);
  border-top: 1px solid var(--linha);
}

/* Crédito Mondra: todo o crédito é um link. "Site criado por" fica igual
   ao resto do texto pequeno; só a palavra Mondra tem traço por baixo.
   border-bottom e não text-decoration, porque text-decoration não desenha
   por baixo de um SVG. */
.rodape .credito {
  color: inherit;
  text-decoration: none;
}
.credito__marca {
  display: inline-block;
  padding-bottom: 2px;
  border-bottom: 1px solid currentColor;
}
.credito:hover { color: var(--texto); }

@media (min-width: 48rem) {
  .rodape { padding-bottom: var(--e-6); }
  .rodape__grelha { grid-template-columns: 2fr 1.2fr 1fr; }
  .rodape__lista-cat { columns: 2; column-gap: var(--e-5); }
}
/* Em ecrã largo, a coluna da marca (logo e uma frase) ficava com quase
   metade da largura e muito vazio por baixo. Encolhe para um quarto, e as
   categorias ficam com o espaço, em três colunas de quatro. Só a partir
   de 64rem: abaixo disso, "Lembranças de aniversário" partia em duas. */
@media (min-width: 64rem) {
  .rodape__grelha { grid-template-columns: 1fr 2fr 1fr; }
  .rodape__lista-cat { columns: 3; }
}


/* 8. Blocos partilhados --------------------------------------------------- */

/* Secções: separadas por mudança de fundo e linhas finas, nunca sombras */
.secao { padding-block: var(--e-secao); }
.secao--alt {
  background: var(--fundo-alt);
  border-block: 1px solid var(--linha);
}

.secao__cabeca { margin-bottom: var(--e-bloco); }
.secao__cabeca p {
  margin-top: var(--e-titulo);
  font-size: var(--t-base);
  color: var(--texto-suave);
}

/* Fotos de produto, e o que aparece quando ainda não há nenhuma.
   As duas ocupam exatamente o mesmo espaço, por isso a grelha não muda de
   forma quando as fotos chegarem. */
/* Todas as fotos do catálogo são 4:5, em retrato: é a forma que uma peça
   pousada numa mesa pede, e é a mesma em todo o lado para a grelha nunca
   ficar desalinhada. A proporção está aqui e nos atributos width e height
   das imagens: o browser reserva o espaço antes de a foto chegar e a
   página não salta. O bloco sem foto usa a mesma proporção, por isso o
   cartão tem exatamente o mesmo tamanho com ou sem foto. */
.foto,
.foto-vazia {
  aspect-ratio: 4 / 5;
  border-radius: var(--raio-cartao);
}

.foto {
  width: 100%;
  height: auto;
  object-fit: cover;              /* corta em vez de deformar a peça */
  background: var(--fundo-alt);   /* fundo enquanto a foto carrega */
}

/* Sem foto: bloco liso na cor da categoria com o nome da peça. Nunca um
   espaço em branco nem um ícone de imagem partida. O texto é branco sobre
   a cor da categoria, combinação já verificada nas oito cores.
   O container-type permite à letra encolher com a largura do bloco, para o
   nome caber tanto num cartão estreito como na foto grande do painel. */
.foto-vazia {
  display: grid;
  place-items: center;
  padding: var(--e-3);
  background: var(--cat);
  color: var(--branco);
  overflow: hidden;
  container-type: inline-size;
}
.foto-vazia span {
  font-family: var(--f-titulo);
  font-size: var(--t-base);   /* o estilo Título, como o nome nos cartões */
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.01em;
  text-align: center;
  text-wrap: balance;
}

/* [A CONFIRMAR COM O CLIENTE: ...] visível na página, de propósito */
.a-confirmar {
  padding: 0 var(--e-1);
  background: var(--confirmar);
  color: var(--texto);
  font-weight: 700;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}
p.a-confirmar,
div.a-confirmar {
  padding: var(--e-3) var(--e-4);
  border: 2px dashed var(--texto);
  border-radius: var(--raio-cartao);
}

/* A nota no lugar vazio da grelha das categorias: estica até à altura dos
   cartões ao lado, para ler como mais um cartão, e não como um aviso solto. */
.categorias__confirmar { display: flex; }
.categorias__confirmar .a-confirmar {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}
/* A duas colunas o buraco tem metade da largura de um telemóvel, e a nota
   partia em nove linhas: esticava a fila, e o cartão dos Toppers ao lado
   esticava junto. Aqui passa a ocupar uma fila sua, logo por baixo. */
@media (max-width: 47.99rem) {
  .categorias__confirmar { grid-column: 1 / -1; }
}

/* Como encomendar: três passos numerados, porque é mesmo uma sequência */
.passos {
  list-style: none;
  display: grid;
  gap: var(--e-5);
  counter-reset: passo;
}
.passos > li {
  counter-increment: passo;
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: var(--e-4);
  padding-top: var(--e-4);
  border-top: 1px solid var(--linha);
}
.passos > li > * { grid-column: 2; }
.passos > li::before {
  content: counter(passo);
  grid-row: span 3;
  font-family: var(--f-titulo);
  font-size: var(--t-grande);
  font-weight: 800;
  line-height: 1;
  color: var(--marca);
}
.passos h3 { margin-bottom: var(--e-2); }
.passos p { color: var(--texto-suave); }
/* Cada passo em tópicos curtos, em vez de um parágrafo. As regras de cima
   usam ".passos > li" para não apanharem os pontos destas listas. */
.passos__lista {
  list-style: disc;          /* dentro de outra lista, o browser punha círculos vazios */
  padding-left: 1.1em;
  color: var(--texto-suave);
}
.passos__lista li + li { margin-top: var(--e-1); }
.passos__lista li::marker { color: var(--marca); }
.passos .a-confirmar { margin-top: var(--e-3); }

/* Quatro passos: dois por dois no tablet, os quatro lado a lado no
   computador. Quatro colunas num tablet davam cerca de 150px a cada uma, e
   o texto do passo 2, o mais comprido, virava uma torre. */
@media (min-width: 48rem) {
  .passos { grid-template-columns: repeat(2, 1fr); gap: var(--e-5); }
  .passos > li { grid-template-columns: 1fr; }
  .passos > li > * { grid-column: 1; }
  .passos > li::before { grid-row: auto; margin-bottom: var(--e-3); font-size: var(--t-enorme); }
}
@media (min-width: 64rem) {
  .passos { grid-template-columns: repeat(4, 1fr); }
}


/* 9. Página inicial -------------------------------------------------------- */

/* Hero: sem imagem. Em telemóvel empilha título, parágrafo e botões, com a
   altura que o conteúdo pedir. */
/* Sem nada por cima, os destaques passam a ser a primeira secção da página
   e ficam com o espaço normal de uma secção. */

/* Em destaque -------------------------------------------------------------
   Carrossel com os cartões de produto normais. O deslizar é do browser:
   overflow-x mais scroll-snap. As setas são um extra para o rato.
   -------------------------------------------------------------------------- */
.destaques__acao { margin-top: var(--e-bloco); }

/* Uma seta de cada lado dos cartões, na mesma linha que eles */
.carrossel {
  display: flex;
  align-items: center;
  gap: var(--e-3);
}

.seta[hidden] { display: none; }

.seta {
  flex: none;
  display: inline-grid;
  place-items: center;
  width: var(--alvo);
  height: var(--alvo);
  padding: 0;
  border: 2px solid var(--texto);
  border-radius: var(--raio-botao);
  background: var(--cartao);
  cursor: pointer;
  transition: background-color var(--dur), border-color var(--dur), color var(--dur);
}
.seta:hover:not(:disabled) { background: var(--fundo-alt); }
.seta:disabled {
  border-color: var(--linha);
  color: var(--texto-suave);
  cursor: not-allowed;
}
.seta svg { width: 20px; height: 20px; }

/* A pista tem o seu próprio scroll horizontal. A página nunca o tem.
   O padding com a margem negativa a compensar existe para o contorno de
   foco de um cartão não ficar cortado pelo limite do scroll. */
.carrossel__pista {
  flex: 1;
  min-width: 0;      /* deixa a pista encolher para as setas caberem */
  list-style: none;
  display: flex;
  gap: var(--e-3);
  overflow-x: auto;
  overscroll-behavior-x: contain;   /* não arrasta a página ao chegar ao fim */
  scroll-snap-type: x mandatory;
  padding: var(--e-2);
  margin: calc(-1 * var(--e-2));
  /* Sem isto, o primeiro cartão encostava ao limite do padding e a pista
     ficava parada em scrollLeft 8 em vez de 0, o que dava a entender que
     já havia sido deslizada. O scroll-padding diz ao snap que o início é
     depois do espaço, e a pista volta a assentar no zero. */
  scroll-padding-inline: var(--e-2);
  /* a barra nativa fica escondida: as setas e o próprio corte dos cartões
     já dizem que há mais, e a barra por baixo dos cartões suja a secção */
  scrollbar-width: none;
}
.carrossel__pista::-webkit-scrollbar { display: none; }

/* Os cartões do destaque têm a mesma largura que os da grelha das
   categorias (ver "Tamanho dos cartões de produto", na secção 11). */
.carrossel__pista { gap: var(--produto-espaco); }
.carrossel__pista > .produto {
  flex: 0 0 var(--produto-largura);
  /* sem isto, uma linha que não se pode partir ("Gadgets para crianças"
     ao lado do preço) alargava o cartão para lá da largura certa */
  min-width: 0;
  scroll-snap-align: start;
}

/* Escolhe por ocasião: oito cartões, cada um com a sua cor */
.categorias {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--e-3);
}
.cartao-cat a {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: var(--e-3);
  background: var(--cartao);
  border: 1px solid var(--linha);
  border-top: 4px solid var(--cat);        /* a barra fina na cor da categoria */
  border-radius: var(--raio-cartao);
  text-decoration: none;
  transition: border-color var(--dur);
}
.cartao-cat a:hover { border-color: var(--cat); }
.cartao-cat h3 { color: var(--cat); font-size: var(--t-base); }
.cartao-cat p {
  margin-top: var(--e-1);
  font-size: var(--t-pequeno);
  color: var(--texto-suave);
}

@media (min-width: 48rem) {
  .categorias { grid-template-columns: repeat(4, 1fr); gap: var(--e-4); }
  .cartao-cat a { padding: var(--e-4); }
  .cartao-cat h3 { font-size: var(--t-medio); }
}

/* Quem já ofereceu, A Kukii Store */
.sobre__texto p { font-size: var(--t-base); }
.sobre__texto p + p { margin-top: var(--e-4); }

/* Texto à esquerda, fotos à direita. Em ecrã estreito empilha. */
.sobre__grelha { display: grid; gap: var(--e-5); }

/* O vídeo ao lado do texto, à largura da coluna. O width e o height no
   HTML guardam o lugar (16:9) antes de ele carregar, e a página não salta. */
.sobre__media { display: grid; gap: var(--e-3); align-content: start; }
.sobre__video {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--raio-cartao);
  background: var(--fundo-alt);
}

/* Termos e Condições: texto corrido, numa coluna estreita para se ler bem
   (cerca de 70 letras por linha). Os títulos vão a negrito no início de
   cada parágrafo, por isso o espaço entre parágrafos é o que os separa. */
.termos { max-width: 46rem; }
.termos h1 { margin-bottom: var(--e-bloco); font-size: var(--t-enorme); line-height: 1.1; }
.termos p { font-size: var(--t-base); }
.termos p + p { margin-top: var(--e-4); }
.termos .a-confirmar { margin-top: var(--e-5); }

@media (min-width: 56rem) {
  .sobre__grelha {
    grid-template-columns: 1fr 1fr;
    gap: var(--e-6);
    align-items: start;
  }
}

/* Encomendar: fecho */
.fecho {
  display: grid;
  gap: var(--e-6);
}
.fecho__carrinho p { margin-top: var(--e-titulo); color: var(--texto-suave); }
.fecho__carrinho .botao { margin-top: var(--e-5); }
.fecho__form h3 { margin-bottom: var(--e-titulo); }
.fecho__form .form { margin-top: var(--e-5); }

@media (min-width: 56rem) {
  .fecho { grid-template-columns: 1fr 1fr; gap: var(--e-6); }
}


/* 10. Páginas de categoria --------------------------------------------------
   A faixa é a coisa ousada: cheia na cor da categoria, texto branco.
   Todo o resto da página fica no fundo claro.
   -------------------------------------------------------------------------- */
.faixa {
  display: flex;
  flex-direction: column;
  padding-block: var(--e-4);
  background: var(--cat);
  color: var(--branco);
}
.faixa :focus-visible { outline-color: var(--branco); }
/* Todos os títulos das faixas ocupam duas linhas, para as faixas terem a
   mesma altura e a mudança de página não dar um salto.
   Este número não foi escolhido a olho: escrevi os onze títulos lado a lado
   e contei as linhas de dez em dez centésimos de ch. De 20ch a 21ch todos
   dão duas linhas; abaixo, as "Lembranças de aniversário personalizadas"
   passam a três; acima, os "Porta-chaves e identificadores" caem para uma.
   20.5ch fica no meio dessa folga, que é onde aguenta melhor uma fonte que
   demore a carregar.
   Se mudares um título, conta outra vez. Os onze andam entre 30 e 40
   caracteres de propósito: é isso que permite uma largura só. */
.faixa h1 { max-width: 20.5ch; }

@media (min-width: 48rem) {
}

/* Migalhas de navegação */
.migalhas ol {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: var(--e-4);
  font-size: var(--t-pequeno);
}
.migalhas li + li::before {
  content: "/";
  margin: 0 var(--e-2);
  opacity: 0.8;
}
.migalhas a {
  display: inline-flex;
  align-items: center;
  min-height: var(--alvo);
}

/* Em ecrãs de computador a migalha deixa de reservar os 44px do alvo de
   toque: com eles, sobravam 10px acima e abaixo do texto e o espaçamento
   da faixa deixava de se ler como uniforme. 24px continua a cumprir o
   tamanho mínimo de alvo para rato (WCAG 2.2). No telemóvel mantém os 44. */
@media (min-width: 64rem) {
  .migalhas a { min-height: 1.5rem; }
}

/* Ferramentas do catálogo: filtros à esquerda, procura e ordenação à
   direita. Em ecrã estreito empilham, com os filtros primeiro. */
.ferramentas {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-3);
  /* O mesmo --recuo que separa o cabeçalho da faixa e a faixa dos filtros:
     dos filtros à contagem, e da contagem às peças, o espaço é sempre o
     mesmo, de cima a baixo. */
  margin-bottom: var(--recuo);
}
.ferramentas__lado {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-2);
  margin-left: auto;   /* encosta à direita mesmo quando não há filtros */
}

/* Campo de procura e selector de ordem: mesma altura e mesmo desenho dos
   filtros ao lado, para a linha ler como um só conjunto. */
.procura input,
.ordenar__resumo {
  display: flex;
  align-items: center;
  min-height: var(--alvo);
  padding: 0 var(--e-4);
  border: 1px solid var(--texto-suave);
  border-radius: var(--raio-botao);
  background: var(--cartao);
  color: var(--texto);
}
.procura input { width: 17rem; max-width: 100%; }
.procura input:focus-visible { border-color: var(--cat); }

/* Ordenação: o mesmo <details> do menu de produtos, com a mesma seta */
.ordenar { position: relative; }
.ordenar__resumo {
  gap: var(--e-3);
  justify-content: space-between;
  list-style: none;
  cursor: pointer;
  white-space: nowrap;
}
.ordenar__resumo::-webkit-details-marker { display: none; }
.ordenar__resumo::after {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--dur);
}
.ordenar[open] > .ordenar__resumo {
  border-color: var(--cat);
  color: var(--cat);
}
.ordenar[open] > .ordenar__resumo::after { transform: translateY(1px) rotate(-135deg); }

.ordenar__lista {
  position: absolute;
  top: calc(100% + var(--e-1));
  right: 0;
  z-index: 40;
  min-width: 100%;
  padding: var(--e-2) 0;
  list-style: none;
  background: var(--cartao);
  border: 1px solid var(--linha);
  border-radius: var(--raio-cartao);
  animation: menu-abrir var(--dur) ease-out;
}
.ordenar__lista button {
  display: block;
  width: 100%;
  min-height: var(--alvo);
  padding: 0 var(--e-4);
  border: 0;
  background: none;
  font: inherit;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}
.ordenar__lista button:hover { background: var(--fundo-alt); }
.ordenar__lista button[aria-pressed="true"] { color: var(--cat); font-weight: 700; }

/* Procura no site todo, no cabeçalho */
/* encostada ao ícone da mensagem, no grupo da direita */
.procura-site { position: relative; display: block; margin-right: calc(-1 * var(--e-1)); }
.procura-site input {
  width: 11rem;
  min-height: var(--alvo);
  padding: 0 var(--e-4);
  border: 1px solid var(--texto-suave);
  border-radius: var(--raio-botao);
  background: var(--cartao);
}
.procura-site input:focus-visible { border-color: var(--cat); }

@media (min-width: 72rem) {
  .procura-site input { width: 15rem; }
}

/* Painel dos resultados: flutua por cima da página, como o menu de
   produtos, e segue a mesma linguagem (fundo do cartão, linha fina). */
.procura-site__painel {
  position: absolute;
  top: calc(100% + var(--e-2));
  right: 0;
  z-index: 60;
  width: min(22rem, 90vw);
  max-height: 60vh;
  overflow-y: auto;
  padding: var(--e-2) 0;
  background: var(--cartao);
  border: 1px solid var(--linha);
  border-radius: var(--raio-cartao);
  animation: menu-abrir var(--dur) ease-out;
}
.procura-site__painel[hidden] { display: none; }

.procura-site__lista { list-style: none; }
.procura-site__lista button {
  display: flex;
  flex-direction: column;
  gap: var(--e-1);
  width: 100%;
  min-height: var(--alvo);
  padding: var(--e-2) var(--e-4);
  border: 0;
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.procura-site__lista button:hover { background: var(--fundo-alt); }
.procura-site__cat {
  font-size: var(--t-pequeno);
  font-weight: 700;
  color: var(--cat);
}
.procura-site__vazio {
  padding: var(--e-3) var(--e-4);
  font-size: var(--t-pequeno);
  color: var(--texto-suave);
}

/* Filtros secundários */
.filtros {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-2);
  /* a margem por baixo vive agora em .ferramentas */
}
.filtro {
  min-height: var(--alvo);
  padding: 0 var(--e-4);
  border: 2px solid var(--cat);
  border-radius: var(--raio-botao);
  background: var(--cartao);
  color: var(--cat);
  font-weight: 700;
  cursor: pointer;
  transition: background-color var(--dur), color var(--dur);
}
.filtro:hover { background: var(--fundo-alt); }
.filtro[aria-pressed="true"] { background: var(--cat); color: var(--branco); }

.contagem {
  margin-bottom: var(--recuo);   /* ver .ferramentas */
  font-size: var(--t-pequeno);
  color: var(--texto-suave);
}


/* 11. Cartões de produto --------------------------------------------------- */

/* Tamanho dos cartões de produto ------------------------------------------
   Um cartão mede o mesmo no "Em destaque" e na grelha das categorias. Antes
   cada um fazia a sua conta: a grelha dividia a largura toda por quatro, e
   o destaque dividia por cinco a largura que sobrava depois das setas. A
   1440px dava 306px num sítio e 217px no outro.
   Agora a conta é uma só: a largura do conteúdo, menos os espaços, a
   dividir pelo número de cartões por linha. "A largura do conteúdo" é a do
   .contentor da secção, lida com a unidade cqw (1cqw = 1% da largura do
   contentor), e não a da pista: assim as setas não roubam espaço aos
   cartões, e o destaque mostra um cartão inteiro e a ponta do seguinte.
   O número de cartões por linha sobe com o ecrã: 2, 3, 4 e 5. */
:root {
  --produto-n: 2;
  --produto-espaco: var(--e-3);
}
@media (min-width: 40rem) { :root { --produto-n: 3; --produto-espaco: var(--e-4); } }
@media (min-width: 64rem) { :root { --produto-n: 4; --produto-espaco: var(--e-5); } }
/* cinco no ecrã mais largo: com quatro, os cartões ficavam altos demais e
   a última linha era cortada pelo fundo do ecrã */
@media (min-width: 72rem) { :root { --produto-n: 5; } }

/* O cqw mede-se no contentor mais próximo que seja "container". São estes
   dois: o da secção do destaque e o do catálogo. */
[data-destaques] > .contentor,
[data-catalogo] > .contentor { container-type: inline-size; }
:root {
  --produto-largura: calc((100cqw - (var(--produto-n) - 1) * var(--produto-espaco)) / var(--produto-n));
}

.grelha {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(var(--produto-n), minmax(0, 1fr));
  gap: var(--produto-espaco);
}

.produto {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--e-2);
  padding: var(--e-3);
  background: var(--cartao);
  border: 1px solid var(--linha);
  border-radius: var(--raio-cartao);
  transition: border-color var(--dur);
}
/* realce na cor da categoria: muda a borda, não levanta o cartão */
.produto:hover { border-color: var(--cat); }
.produto:has(.produto__abrir:focus-visible) {
  outline: 3px solid var(--cat);
  outline-offset: 2px;
}

.produto__foto { position: relative; margin-bottom: var(--e-1); }

/* O ícone do botão do cartão: lápis no "Personalizar", carrinho no
   "Adicionar ao carrinho". O espaço até ao texto vem do gap do .botao. */
.produto__adicionar svg { width: 1.125rem; height: 1.125rem; flex: none; }
/* Num cartão de telemóvel, "Adicionar ao carrinho" com o ícone não cabe
   numa linha (sobram 119px para 140px de texto). Aí o botão mostra só
   "Adicionar", e o carrinho desenhado diz o resto. O "ao carrinho" fica
   escondido só à vista: o leitor de ecrã continua a ouvi-lo. */
@media (max-width: 39.99rem) {
  .produto__adicionar-resto {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* A linha debaixo do nome: a categoria à esquerda (só nos destaques) e o
   preço à direita, os dois na cor da categoria, pequenos e a negrito. O
   --cat vem do data-cat do cartão nos destaques, e do <body> nas páginas
   das categorias, por isso cada um aparece na sua cor.
   O margin-top: auto leva a linha e o botão, juntos, para o fundo do
   cartão: numa fila, ficam alinhados mesmo quando um nome tem duas linhas
   e o do lado uma. */
.produto__linha {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--e-2);
  margin-top: auto;
  color: var(--cat);
  font-size: var(--t-pequeno);
  font-weight: 700;
}
.produto__cat { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.produto__preco { margin-left: auto; white-space: nowrap; }
.produto__preco-antes { margin-right: var(--e-1); font-weight: 400; }

/* O nome a 17px em todos os ecrãs, e no máximo em duas linhas (com
   reticências se for mais comprido). Sem altura reservada: antes guardava
   sempre o lugar de duas linhas, e um nome curto deixava uma linha vazia.
   O corte nas duas linhas fica no botão (.produto__abrir, abaixo), porque
   é ele que tem o texto: posto no título, não chegava lá dentro. */
.produto__nome {
  font-size: var(--t-base);
  line-height: 1.2;
}

/* O botão ocupa o cartão inteiro (o ::after estica-se por cima de tudo):
   um só alvo grande, e um só elemento que o teclado precisa de visitar. */
.produto__abrir {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
  /* no máximo duas linhas, com reticências. O overflow não corta o ::after
     que cobre o cartão: esse mede-se a partir do .produto, não do botão. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}
.produto__abrir::after {
  content: "";
  position: absolute;
  inset: 0;
}
.produto__abrir:focus-visible { outline: none; } /* o foco é desenhado no cartão, acima */

.preco {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 var(--e-2);
}
.preco__atual { font-weight: 700; font-size: var(--t-base); }
.preco__antes { color: var(--texto-suave); font-size: var(--t-pequeno); }
.preco--consulta { font-weight: 700; color: var(--texto-suave); }

/* Selo de desconto: a marca fala */
.selo {
  position: absolute;
  top: var(--e-2);
  left: var(--e-2);
  padding: var(--e-1) var(--e-2);
  background: var(--marca);
  color: var(--branco);
  border-radius: var(--raio-cartao);
  font-size: var(--t-pequeno);
  font-weight: 700;
  line-height: 1.2;
}
.selo--linha { position: static; align-self: center; }

/* Pastilhas por cima da foto, no canto de baixo à esquerda. Fundo branco
   quase opaco, para o texto escuro se ler sobre qualquer foto. */
.etiquetas {
  position: absolute;
  left: var(--e-2);
  bottom: var(--e-2);
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-1);
}
.etiquetas li {
  display: inline-flex;
  align-items: center;
  gap: var(--e-1);
  padding: 0.125rem var(--e-2);
  background: rgb(255 255 255 / 0.94);
  color: var(--texto);
  border-radius: var(--raio-botao);
  font-size: var(--t-pequeno);
  font-weight: 700;
  line-height: 1.4;
  white-space: nowrap;
}
.etiquetas svg { width: 0.875rem; height: 0.875rem; flex: none; }

/* Adicionar ao carrinho, no próprio cartão. Só o contorno, para uma fila
   de cartões não virar uma fila de botões vermelhos: o vermelho fica para
   o Encomendar. Fica por cima do botão invisível que abre a peça (o
   z-index), senão o clique ia para ele. Desce para o fundo do cartão
   junto com a linha do preço, que fica por cima dele (ver .produto__linha). */
.produto__adicionar {
  position: relative;
  z-index: 1;
  width: 100%;
  min-height: var(--alvo);
  padding: var(--e-1) var(--e-2);
  font-size: var(--t-pequeno);
}


/* Esgotado: a peça continua à vista, mas a foto fica esbatida e sem cor, e
   ganha um selo por cima a dizê-lo. A descoloração é aplicada à imagem e
   não à caixa que a contém, senão levava o selo com ela.
   O texto do cartão mantém o contraste, para continuar legível. */
.produto--esgotado .produto__foto > .foto,
.produto--esgotado .produto__foto > .foto-vazia {
  opacity: 0.4;
  filter: grayscale(1);
}

.produto__esgotado {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: var(--e-2) var(--e-4);
  background: var(--texto);
  color: var(--branco);
  border-radius: var(--raio-botao);
  font-size: var(--t-pequeno);
  font-weight: 700;
  white-space: nowrap;
}

/* No bloco sem foto, o nome sai de debaixo do selo: os dois estavam
   centrados e chocavam. O nome continua logo abaixo, no cartão. */
.produto--esgotado .foto-vazia span { visibility: hidden; }

/* Sem aproximar a foto ao passar o rato: convidava a comprar o que não há */
.produto--esgotado:hover .produto__foto > .foto,
.produto--esgotado:hover .produto__foto > .foto-vazia { transform: none; }

/* Linha de espera e de erro. Aparece no lugar dos produtos, na grelha das
   categorias e na pista do carrossel, que é flex e por isso precisa de
   ocupar a largura toda em vez de encolher. */
.grelha-estado { color: var(--texto-suave); }
/* A carregar e vazia: a mensagem ocupa a largura toda da grelha, centrada,
   em vez de ficar espremida na primeira coluna. */
.grelha > .grelha-estado--a-carregar,
.grelha > .grelha-estado:has(.letreiro) {
  grid-column: 1 / -1;
  padding-block: var(--e-5);
  text-align: center;
}
.carrossel__pista > .grelha-estado--a-carregar { text-align: center; padding-block: var(--e-5); }
.carrossel__pista > .grelha-estado { flex: 1 1 100%; }


/* 12. Gavetas ---------------------------------------------------------------
   <dialog> nativo aberto com showModal(): prende o foco lá dentro, fecha
   com Esc e devolve o foco ao botão que o abriu, sem código extra.
   -------------------------------------------------------------------------- */
.gaveta {
  inset: 0 0 0 auto;
  width: min(30rem, 100%);
  max-width: 100%;
  height: 100dvh;
  max-height: 100dvh;
  margin: 0;
  padding: 0;
  border: 0;
  background: var(--fundo);
  color: var(--texto);
}
.gaveta::backdrop { background: rgb(43 29 23 / 0.5); }

.gaveta[open] { animation: gaveta-entrar var(--dur) ease-out; }
.gaveta[open]::backdrop { animation: fundo-entrar var(--dur) ease-out; }
@keyframes gaveta-entrar { from { transform: translateX(100%); } }
@keyframes fundo-entrar { from { opacity: 0; } }

@media (min-width: 30rem) {
  .gaveta { border-radius: var(--raio-bloco) 0 0 var(--raio-bloco); }
}

.gaveta__corpo {
  display: flex;
  flex-direction: column;
  height: 100%;
}
.gaveta__topo {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-3);
  padding: var(--e-3) var(--e-3) var(--e-3) var(--e-5);
  border-bottom: 1px solid var(--linha);
}
.gaveta__topo h2 { font-size: var(--t-medio); }
.gaveta__conteudo {
  flex: 1;
  overflow-y: auto;
  padding: var(--e-5);
}
.gaveta__pe {
  padding: var(--e-4) var(--e-5) var(--e-5);
  border-top: 1px solid var(--linha);
  background: var(--fundo-alt);
}

.fechar {
  display: inline-grid;
  place-items: center;
  width: var(--alvo);
  height: var(--alvo);
  padding: 0;
  border: 0;
  border-radius: var(--raio-botao);
  background: none;
  cursor: pointer;
}
.fechar:hover { background: var(--fundo-alt); }
.fechar svg { width: 22px; height: 22px; }

/* Painel de produto --------------------------------------------------------
   Montado como uma montra e não como um formulário: a peça em palco no
   topo, o nome e o preço com peso, o que se personaliza num cartão
   próprio, e o botão sempre à mão, preso ao fundo. Um pouco mais largo
   do que o carrinho (36rem em vez de 30), para a foto ter espaço. */
.gaveta.painel { width: min(36rem, 100%); }

/* Sem barra de título. O "Personalizar" continua lá para os leitores de
   ecrã, e o X flutua por cima da foto, num círculo branco. O topo deixa
   passar os toques, para não tapar a foto: só o X os recebe. */
.painel .gaveta__corpo { position: relative; }
.painel .gaveta__topo {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 2;
  justify-content: flex-end;
  padding: var(--e-3);
  border: 0;
  pointer-events: none;
}
.painel .gaveta__topo h2 {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.painel .fechar {
  pointer-events: auto;
  background: var(--cartao);
  box-shadow: 0 2px 12px rgb(34 24 20 / 0.18);
}
.painel .fechar:hover { background: var(--fundo-alt); }
.painel .gaveta__conteudo { padding-top: 0; scroll-padding-bottom: 6rem; }
.painel .gaveta__conteudo:focus { outline: none; }

/* O palco: a toda a largura do painel, tingido na cor da categoria, e a
   foto ao centro com sombra, como uma peça pousada. A foto mede-se pela
   altura (até metade do ecrã) e nunca passa a largura disponível. */
.painel__palco {
  --alto: min(52vh, 27rem);
  display: grid;
  justify-items: center;
  gap: var(--e-3);
  margin-inline: calc(-1 * var(--e-5));
  padding: var(--e-6) var(--e-5) var(--e-5);
  background: color-mix(in srgb, var(--cat) 10%, var(--fundo));
}
.painel__principal { position: relative; max-width: 100%; }
.painel__principal > .foto,
.painel__principal > .foto-vazia {
  width: min(calc(var(--alto) * 0.8), 100%);
  height: auto;
  aspect-ratio: 4 / 5;
  box-shadow: 0 20px 40px -20px rgb(34 24 20 / 0.5);
}
.painel__principal > .foto { display: block; }

/* Miniaturas: tocar numa troca a foto principal. A escolhida tem a borda
   na cor da categoria. 52px de largura: chega para o dedo. */
.painel__miniaturas {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--e-2);
}
.painel__miniaturas button {
  display: block;
  width: 3.25rem;
  padding: 3px;
  border: 2px solid transparent;
  border-radius: var(--raio-cartao);
  background: none;
  cursor: pointer;
}
.painel__miniaturas button[aria-pressed="true"] { border-color: var(--cat); }
.painel__miniaturas img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: calc(var(--raio-cartao) - 5px);
}

/* A peça: categoria na cor dela, nome grande, preço com o mesmo peso */
.painel__info { padding-top: var(--e-5); }
.painel__cat { font-size: var(--t-pequeno); font-weight: 700; color: var(--cat); }
.painel__titulo { margin-top: var(--e-1); font-size: var(--t-grande); line-height: 1.1; }
/* O preço com o tamanho, a cor e a distância ao nome da categoria, por cima:
   o nome fica entre os dois, como o centro da montra. */
.painel .preco { margin-top: var(--e-1); }
.painel .preco__atual { font-size: var(--t-pequeno); color: var(--cat); }
/* Descrição da peça, quando a coluna description tem texto. Sem texto, não
   aparece nada, nem o espaço. */
.painel__descricao { margin-top: var(--e-4); }

/* O que a pessoa tem de fazer */
.painel__form { margin-top: var(--e-5); display: grid; gap: var(--e-3); }

/* O cartão do que se personaliza: tudo o que é para preencher, junto */
.painel__personaliza {
  display: grid;
  gap: var(--e-4);
  padding: var(--e-5);
  border-radius: var(--raio-cartao);
  background: var(--fundo-alt);
}
/* Selecionado pelo "Adicionar ao carrinho" do cartão, numa peça só com
   foto (ver selecionarPersonalizacao no site.js). :focus e não
   :focus-visible: o foco chega depois de um clique, e aí o browser não
   desenharia o contorno sozinho. */
.painel__personaliza:focus { outline: 3px solid var(--cat); outline-offset: 2px; }
.painel__personaliza-titulo { font-family: var(--f-titulo); font-size: var(--t-medio); font-weight: 700; }
.painel__personaliza label { display: flex; align-items: center; }
.painel__personaliza .campo textarea { background: var(--cartao); }
.painel__foto-nota { display: flex; align-items: flex-start; }

/* O círculo de cada ícone, na cor da categoria. O branco por cima dá pelo
   menos 5.48:1 em todas as onze cores. */
.painel__icone {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 1.75rem;
  height: 1.75rem;
  margin-right: var(--e-2);
  border-radius: var(--raio-botao);
  background: var(--cat);
  color: var(--branco);
}
.painel__icone svg { width: 1rem; height: 1rem; }

/* As indicações extra: fechadas, abrem para quem precisar. O + roda e
   passa a x quando abrem. */
.painel__nota summary {
  display: inline-flex;
  align-items: center;
  min-height: var(--alvo);
  font-weight: 700;
  cursor: pointer;
  list-style: none;
}
.painel__nota summary::-webkit-details-marker { display: none; }
.painel__nota summary .painel__icone {
  background: var(--fundo-alt);
  color: var(--texto);
  transition: transform var(--dur);
}
.painel__nota[open] summary .painel__icone { transform: rotate(45deg); }
.painel__nota .campo { margin-top: var(--e-2); }

/* O botão, preso ao fundo enquanto se desce pela peça. O margin negativo
   cobre o padding do painel, para o botão encostar à borda e o texto não
   aparecer por baixo dele. A sombra por cima diz que há mais por baixo. */
.painel__acao {
  position: sticky;
  bottom: calc(-1 * var(--e-5));
  z-index: 1;
  margin: var(--e-2) calc(-1 * var(--e-5)) calc(-1 * var(--e-5));
  padding: var(--e-3) var(--e-5) var(--e-5);
  background: var(--fundo);
  box-shadow: 0 -12px 24px -18px rgb(34 24 20 / 0.4);
}

/* Carrinho */
.carrinho__lista { list-style: none; display: grid; }
.carrinho__item {
  display: grid;
  /* miniatura | nome e detalhes | preço */
  grid-template-columns: 3.5rem 1fr auto;
  gap: var(--e-1) var(--e-3);
  padding-block: var(--e-4);
  border-bottom: 1px solid var(--linha);
}
.carrinho__item:first-child { padding-top: 0; }
.carrinho__nome { font-weight: 700; }
.carrinho__preco { font-weight: 700; text-align: right; white-space: nowrap; }
/* A miniatura ocupa a coluna da esquerda de cima a baixo. 4:5, como todas
   as fotos de produto do site, e com o raio dos cartões. */
.carrinho__miniatura {
  grid-row: span 3;
  align-self: start;
  width: 3.5rem;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: var(--raio-cartao);
  background: var(--fundo-alt);   /* enquanto carrega */
}
.carrinho__miniatura--vazia { display: block; background: var(--cat); }

.carrinho__detalhes {
  grid-column: 2 / -1;
  font-size: var(--t-pequeno);
  color: var(--texto-suave);
}
.carrinho__detalhes p + p { margin-top: var(--e-1); }
.carrinho__remover { grid-column: 2 / -1; justify-self: start; margin-left: calc(-1 * var(--e-2)); }

.carrinho__total {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--e-2);
  font-size: var(--t-base);
  font-weight: 700;
}
.carrinho__aviso {
  margin-top: var(--e-2);
  font-size: var(--t-pequeno);
  color: var(--texto-suave);
}
.carrinho__acoes { margin-top: var(--e-4); display: grid; gap: var(--e-2); }
.carrinho__acoes .botao-texto { justify-self: center; }

.carrinho__vazio p + p { margin-top: var(--e-3); }
.carrinho__vazio .botao { margin-top: var(--e-5); }


/* 13. Formulários ---------------------------------------------------------- */
.campo { display: grid; gap: var(--e-2); }
.campo label { font-weight: 700; }
.campo .opcional { font-weight: 400; color: var(--texto-suave); }
.ajuda {
  font-size: var(--t-pequeno);
  color: var(--texto-suave);
}

/* A borda dos campos usa o texto suave: 6.9:1, acima dos 3:1 exigidos para
   limites de componentes (WCAG 1.4.11). */
.campo input,
.campo textarea {
  width: 100%;
  min-height: 48px;
  padding: var(--e-3) var(--e-4);
  background: var(--cartao);
  border: 1px solid var(--texto-suave);
  border-radius: var(--raio-cartao);
}
.campo textarea { resize: vertical; min-height: 6rem; }
.campo input:focus-visible,
.campo textarea:focus-visible { outline-offset: 0; border-color: var(--cat); }

.campo--erro input,
.campo--erro textarea { border: 2px solid var(--marca); }
.erro {
  font-size: var(--t-pequeno);
  font-weight: 700;
  color: var(--marca);
}

.form { display: grid; gap: var(--e-5); }
.form__privacidade {
  font-size: var(--t-pequeno);
  color: var(--texto-suave);
}
.form__estado { font-weight: 700; }
.form__estado:empty { display: none; }



/* 14. Aviso "juntaste ao carrinho" ------------------------------------------- */
.aviso {
  position: fixed;
  left: var(--e-4);
  right: calc(var(--e-4) + 3.5rem + var(--e-3));   /* não tapa o WhatsApp flutuante */
  bottom: var(--e-4);
  z-index: 45;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-2) var(--e-4);
  padding: var(--e-3) var(--e-3) var(--e-3) var(--e-4);
  background: var(--texto);
  color: var(--branco);
  border-radius: var(--raio-cartao);
}
.aviso[hidden] { display: none; }
.aviso:not([hidden]) { animation: aviso-entrar var(--dur) ease-out; }
.aviso :focus-visible { outline-color: var(--branco); }
.aviso .botao { min-height: var(--alvo); padding-inline: var(--e-4); }
@keyframes aviso-entrar { from { opacity: 0; transform: translateY(var(--e-2)); } }

@media (min-width: 64rem) {
  .aviso { left: auto; right: var(--e-5); bottom: var(--e-5); max-width: 26rem; }
}


/* 15. Movimento reduzido ----------------------------------------------------
   Quem pediu ao sistema menos movimento não vê nenhuma animação.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
  }
}


/* ==========================================================================
   16. Identidade: blocos de filamento
   --------------------------------------------------------------------------
   Esta secção é a camada visual do site, e vem no fim de propósito: o que
   está aqui ganha ao que está acima quando as duas regras dizem respeito à
   mesma coisa.

   A ideia vem do próprio ofício: cada cor de categoria é uma bobina de
   filamento, e cada bloco é um campo cheio dessa cor, sem textura nenhuma
   por cima. Fundo branco limpo, sem linhas de jornal a separar tudo: as
   secções separam-se por blocos recuados, de cantos redondos, todos com a
   mesma geometria.
   ========================================================================== */

:root {
  /* Geometria comum de todos os blocos recuados (banners e blocos neutros).
     O bloco é mais largo do que o conteúdo exactamente pelo seu padding,
     por isso o texto lá dentro fica na mesma linha vertical que o resto da
     página. Tudo alinhado, com ou sem bloco à volta. */
  --recuo: var(--e-3);                                        /* do bloco à borda do ecrã */
  --folga-bloco: max(var(--e-4), calc(var(--margem) - var(--recuo)));
  --largura-bloco: min(100% - 2 * var(--recuo), var(--largura) + 2 * var(--folga-bloco));


  /* Rodapé escuro. Contrastes verificados: texto 15.2:1, suave 9.4:1. */
  --noite: #221814;
  --noite-texto: #F4EFEC;
  --noite-suave: #C9BCB4;
}

/* O cabeçalho deixou de ter linha por baixo */
body { padding-top: var(--altura-topo); }
.topo {
  border-bottom: 0;
  transition: box-shadow var(--dur);
}
.topo--rolado { box-shadow: 0 1px 0 var(--linha), 0 10px 30px rgb(34 24 20 / 0.06); }

main { padding-bottom: var(--e-secao); }


/* Blocos recuados ---------------------------------------------------------- */
.faixa,
.secao--alt {
  width: var(--largura-bloco);
  margin-inline: auto;
  padding-inline: var(--folga-bloco);
  border: 0;
  border-radius: var(--raio-bloco);
}
.faixa > .contentor,
.secao--alt > .contentor { width: 100%; }

.secao--alt { background: var(--fundo-alt); }


/* Banners de topo: mesma altura, mesma textura, mesma estrutura ------------ */
.faixa {
  position: relative;
  isolation: isolate;          /* a textura e a neve ficam por trás do texto */
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: center;
  margin-top: var(--recuo);
  padding-block: var(--e-5);
  color: var(--branco);
}
/* A faixa mede o que tem dentro, as migalhas e o título, mais 24px em cima
   e em baixo. Tinha uma altura fixa de 224px, do tempo em que havia uma
   frase por baixo do título; sem ela, sobravam cerca de 38px vazios de
   cada lado. Fica com cerca de 159px no telemóvel e 196px no computador.
   As doze continuam com a mesma altura entre si, porque todos os títulos
   ocupam duas linhas (ver o max-width do .faixa h1). */
/* entre as migalhas e o título, 12px */
.faixa .migalhas ol { margin-bottom: var(--e-3); }

/* Da faixa aos filtros, o mesmo espaço que do cabeçalho à faixa. As duas
   saem do mesmo --recuo, por isso ficam iguais por construção: se um dia
   o recuo mudar, mudam as duas juntas. A faixa lê assim como um bloco
   pousado entre o cabeçalho e as peças, com o mesmo ar por cima e por
   baixo. */
[data-catalogo] { padding-top: var(--recuo); }

/* A página inicial já não abre num bloco de cor: abre na frase, e a cor
   fica toda para as peças e para os cartões das categorias. */

/* Partículas de cada categoria (neve, corações, estrelas...): um canvas por
   trás do texto, desenhado pelo site.js. O mesmo nos banners e nos blocos
   das categorias da página inicial. */
.particulas {
  position: absolute;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
  pointer-events: none;
}


/* Menos espaço por cima das categorias do que o normal: na página inicial
   os destaques e as categorias são uma sequência, não duas paragens, e é o
   que faz a primeira fila de cartões espreitar na dobra em vez de ficar
   logo abaixo dela. O id só existe na página inicial, por isso as páginas
   de categoria não são tocadas. */
#categorias { padding-top: var(--e-5); }
/* Metade do espaço normal de secção por cima dos destaques (48px -> 24px).
   São a primeira coisa da página inicial, logo a seguir ao cabeçalho, e o
   respiro que uma secção precisa a meio da página é a mais quando não há
   nada por cima de que se afastar. O atributo só existe na página inicial,
   por isso as páginas de categoria ficam com o espaço normal. */
[data-destaques] { padding-top: var(--e-5); }

[data-destaques] .secao__cabeca { margin-bottom: var(--e-5); }

/* A janela existe só quando há desfile, e é o JavaScript que a põe à volta
   da pista. Corta o que sai para os lados e deixa as setas de fora, para o
   contorno de foco delas não ser cortado. O respiro em cima e em baixo é o
   mesmo da pista, e pela mesma razão: o contorno de foco de um cartão. */
.carrossel__janela {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  padding-block: var(--e-2);
  margin-block: calc(-1 * var(--e-2));
}

/* Em desfile a pista deixa de ter scroll próprio: anda por transform, que o
   browser trata na placa gráfica, sem passar pelo fio que desenha a página.
   Antes era o JavaScript a escrever o scrollLeft a cada frame, e a 22px por
   segundo isso dá menos de meio píxel de cada vez: saía aos solavancos.
   Com o transform fora não é preciso desligar o encaixe do scroll, mas fica
   desligado à mesma, porque a pista ainda o tem declarado.
   Os dois números vêm do JavaScript, porque dependem de quantas peças há:
   --desfile-largura é uma série, --desfile-dur é o tempo de a percorrer.
   O translate fica livre para as setas: soma-se ao transform da animação
   sem a interromper. */
.carrossel__pista--desfile {
  width: 100%;
  padding-inline: 0;
  margin-inline: 0;
  overflow: visible;
  scroll-snap-type: none;
  animation: desfile var(--desfile-dur, 60s) linear infinite;
  transition: translate 420ms ease-out;
  will-change: transform;
}
@keyframes desfile {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(calc(-1 * var(--desfile-largura, 0px)), 0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .carrossel__pista--desfile { animation: none; transition: none; }
}


/* Categorias na página inicial: blocos cheios de cor ---------------------- */
.categorias { gap: var(--e-4); }

.cartao-cat a {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  justify-content: flex-end;
  min-height: 10.5rem;
  padding: var(--e-5);
  background: var(--cat);
  color: var(--branco);
  border: 0;
  border-radius: var(--raio-cartao);
  transition: transform var(--dur) ease-out;
}
/* O furo no canto: quase todas as peças da Kukii têm um, por onde passa a
   fita ou a argola (bolas, porta-chaves, etiquetas). Cada categoria fica
   com cara de etiqueta de presente. */
.cartao-cat a::after {
  content: "";
  position: absolute;
  top: var(--e-4);
  right: var(--e-4);
  width: 1rem;
  height: 1rem;
  border: 3px solid rgb(255 255 255 / 0.55);
  border-radius: var(--raio-botao);
}
.cartao-cat a:hover { transform: translateY(-4px); border-color: transparent; }
.cartao-cat a:focus-visible { outline: 3px solid var(--cat); outline-offset: 3px; }
.cartao-cat h3,
.cartao-cat p { color: var(--branco); }
.cartao-cat h3 { font-size: var(--t-medio); }
.cartao-cat p { margin-top: var(--e-2); font-size: var(--t-pequeno); }


/* Peças: foto e texto, sem caixa à volta, como numa montra ----------------- */
.produto {
  padding: 0;
  border: 0;
  background: none;
}
.produto:hover { border-color: transparent; }
.produto__foto {
  overflow: hidden;
  border-radius: var(--raio-cartao);
  margin-bottom: 0;            /* o espaço até ao texto já vem do gap do cartão */
}
.produto__foto > .foto,
.produto__foto > .foto-vazia {
  border-radius: 0;            /* o canto é dado pelo contentor, que corta */
  transition: transform 280ms ease-out;
}
/* Ao passar o rato a foto aproxima-se um pouco, como quem pega na peça */
.produto:hover .produto__foto > .foto,
.produto:hover .produto__foto > .foto-vazia { transform: scale(1.04); }
.produto:has(.produto__abrir:focus-visible) {
  outline-offset: 6px;
  border-radius: var(--raio-cartao);
}


/* Como encomendar: sem linhas de jornal entre os passos -------------------- */
.passos > li {
  padding-top: 0;
  border-top: 0;
  /* Os passos de uma fila têm a altura do mais alto (o terceiro, por causa do
     aviso amarelo). Sem isto, os outros dois esticavam as linhas por dentro
     e abria-se um buraco entre o título e o texto. */
  align-content: start;
}


/* Botões: um pequeno aperto ao clicar, em resposta ao gesto --------------- */
.botao,
.botao-carrinho,
.seta,
.filtro,
.botao-whatsapp {
  transition: background-color var(--dur), color var(--dur), border-color var(--dur), transform 120ms ease-out;
}
.botao:active,
.botao-carrinho:active,
.seta:active:not(:disabled),
.filtro:active,
.botao-whatsapp:active { transform: scale(0.96); }


/* Rodapé escuro: fecha a página com peso, sem ser mais um bloco bege ------- */
.rodape {
  background: var(--noite);
  color: var(--noite-suave);
  border-top: 0;
}
.rodape a,
.rodape__titulo { color: var(--noite-texto); }
.rodape .credito { color: inherit; }
.rodape .credito:hover { color: var(--noite-texto); }
.rodape__fim { border-top-color: rgb(255 255 255 / 0.12); }
.rodape :focus-visible { outline-color: var(--noite-texto); }


/* Quem já ofereceu ---------------------------------------------------------
   Mensagens verdadeiras de clientes. Sem foto e sem nome, por isso o que
   sustenta cada uma é o texto: fica em primeiro plano, com as estrelas por
   cima e a origem por baixo, em letra pequena.
   -------------------------------------------------------------------------- */
.avaliacoes {
  list-style: none;
  display: grid;
  gap: var(--e-4);
}

.avaliacao {
  display: flex;
  flex-direction: column;
  gap: var(--e-3);
  padding: var(--e-5);
  background: var(--cartao);
  border-radius: var(--raio-cartao);
}

/* As cinco estrelas são desenhadas em CSS, a partir de uma só forma repetida.
   O dourado cumpre 3:1 nos dois fundos, que é o mínimo para um elemento
   gráfico que transporta informação. Quem usa leitor de ecrã ouve "5 em 5
   estrelas", escrito em texto ao lado. */
.avaliacao__estrelas {
  --estrela: #A8791F;
}
.avaliacao__estrelas::before {
  content: "";
  display: block;
  /* 5 estrelas de 1rem: a largura tem de ser exactamente 5 vezes o passo da
     repetição, senão aparece meia estrela no fim */
  width: 5rem;
  height: 1rem;
  background-color: var(--estrela);
  /* uma estrela de cinco pontas, repetida cinco vezes ao longo da barra */
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M10 1.5l2.6 5.3 5.9.9-4.3 4.1 1 5.8-5.2-2.7-5.2 2.7 1-5.8L1.5 7.7l5.9-.9z"/></svg>');
  mask-size: 1rem 1rem;
  mask-repeat: repeat-x;
  -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M10 1.5l2.6 5.3 5.9.9-4.3 4.1 1 5.8-5.2-2.7-5.2 2.7 1-5.8L1.5 7.7l5.9-.9z"/></svg>');
  -webkit-mask-size: 1rem 1rem;
  -webkit-mask-repeat: repeat-x;
}

/* A peça a que a mensagem se refere. Fica logo abaixo das estrelas, antes
   do texto: é o que dá contexto à avaliação e liga o elogio a algo concreto.
   Pequena e discreta, para não competir com a mensagem. */
.avaliacao__peca {
  margin-top: calc(-1 * var(--e-2));
  font-size: var(--t-pequeno);
  font-weight: 700;
}

.avaliacao blockquote {
  margin: 0;
  flex: 1;
  font-size: var(--t-base);
  line-height: 1.4;
  text-wrap: pretty;
}

.avaliacao__origem {
  font-size: var(--t-pequeno);
  color: var(--texto-suave);
}

@media (min-width: 48rem) {
  .avaliacoes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 64rem) {
  .avaliacoes { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--e-5); }
}


/* Fotografia de fundo das categorias --------------------------------------------
   Cada categoria tem uma fotografia por trás do texto e dos efeitos, nos
   dois sítios onde aparece: a faixa da sua página e o cartão da inicial.
   A ordem das camadas, de baixo para cima:

     1. a cor da categoria, que é o fundo do próprio banner
     2. a fotografia, a 75%, o que deixa a cor tingi-la por baixo
     3. um véu escuro, mais forte à esquerda, onde fica o texto
     4. as partículas (neve, corações, estrelas), no canvas
     5. o texto

   O véu não é decoração: uma fotografia tem zonas claras e zonas escuras, e
   sem ele o texto branco deixava de se ler por cima das luzes. É o mínimo
   para o contraste se manter em qualquer ponto.

   As fotografias vivem em assets/banners/, uma por categoria, e são
   declaradas aqui. Uma categoria sem fotografia fica só com a cor, como
   antes: não é preciso mudar nada para isso funcionar.
   -------------------------------------------------------------------------- */
/* Uma linha por categoria, e é o único sítio onde se escolhe a fotografia.
   Está no próprio [data-cat] e não na .faixa porque há dois sítios a lê-la:
   a faixa da página de categoria e o cartão da página inicial. O --veu anda
   sempre com o --foto: sem fotografia não há véu, e a categoria fica só com
   a cor, exactamente como antes.

   Cada categoria tem a fotografia em duas larguras. A faixa ocupa a largura
   toda do ecrã e leva a de 1600px; o cartão da inicial tem 276px e leva a de
   640px. Sem as duas, a página inicial descarregava 365KB de fotografias
   para as mostrar do tamanho de um postal: assim são 102KB. Uma categoria
   precisa das duas versões, e o nome da pequena acaba em -640. */
[data-cat="natal"]        { --foto: url("banners/natal.webp");        --foto-cartao: url("banners/natal-640.webp");        --veu: 1; }
[data-cat="articulados"]  { --foto: url("banners/articulados.webp");  --foto-cartao: url("banners/articulados-640.webp");  --veu: 1; }
[data-cat="criancas"]     { --foto: url("banners/criancas.webp");     --foto-cartao: url("banners/criancas-640.webp");     --veu: 1; }
[data-cat="dia-da-mae"]   { --foto: url("banners/dia-da-mae.webp");   --foto-cartao: url("banners/dia-da-mae-640.webp");   --veu: 1; }
[data-cat="dia-do-pai"]   { --foto: url("banners/dia-do-pai.webp");   --foto-cartao: url("banners/dia-do-pai-640.webp");   --veu: 1; }
[data-cat="decoracao"]    { --foto: url("banners/decoracao.webp");    --foto-cartao: url("banners/decoracao-640.webp");    --veu: 1; }
[data-cat="escola"]       { --foto: url("banners/escola.webp");       --foto-cartao: url("banners/escola-640.webp");       --veu: 1; }
[data-cat="lembrancas"]   { --foto: url("banners/lembrancas.webp");   --foto-cartao: url("banners/lembrancas-640.webp");   --veu: 1; }
[data-cat="iluminados"]   { --foto: url("banners/iluminados.webp");   --foto-cartao: url("banners/iluminados-640.webp");   --veu: 1; }
[data-cat="porta-chaves"] { --foto: url("banners/porta-chaves.webp"); --foto-cartao: url("banners/porta-chaves-640.webp"); --veu: 1; }
[data-cat="religiosos"]   { --foto: url("banners/religiosos.webp");   --foto-cartao: url("banners/religiosos-640.webp");   --veu: 1; }
[data-cat="toppers"]      { --foto: url("banners/toppers.webp");      --foto-cartao: url("banners/toppers-640.webp");      --veu: 1; }
/* As doze têm fotografia, e todas foram medidas nos seis sítios onde
   aparecem: a faixa a 1192 e a 900px, o tablet, o telemóvel, e o cartão da
   inicial no computador e no telemóvel. O pior ponto delas dá 5.2:1,
   com o mínimo do WCAG AA em 4.5:1. Uma fotografia nova obriga a medir
   outra vez: uma mais clara pode precisar de mais véu. */

/* A faixa é muito mais larga do que alta: de uma fotografia 2:1 mostra só
   uma tira do meio, com pouco mais de um terço da altura. Onde o motivo
   está em baixo, essa tira apanhava o fundo vazio por cima dele. O --foco
   baixa o corte, e só na faixa: no cartão da página inicial a fotografia
   cabe quase toda, e ao centro está bem. */
[data-cat="escola"] .faixa { --foco: 50% 85%; }

/* Os articulados não estão nesta lista porque não há foco que os salve: a
   fotografia é um grande plano de uma impressora, e uma tira de 37% da
   altura não chega para se perceber o que é. Baixar o corte mostrava outra
   tira, não mostrava mais. A escala está presa à largura da faixa, e a
   largura da fotografia já é toda usada.
   Por isso a articulados.webp é o único ficheiro com a forma da faixa
   (5.3:1) em vez de 2:1: tem a fotografia inteira à direita, do topo ao
   fundo, e o resto é uma versão desfocada dela própria, onde o texto
   assenta. O cartão da página inicial continua com a articulados-640.webp,
   que é 2:1 como as outras, porque lá a forma é quase quadrada e a
   fotografia já cabia. */

.faixa::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;                     /* debaixo do canvas das partículas (-1) */
  background-image: var(--foto, none);
  background-size: cover;
  background-position: var(--foco, center);
  opacity: 0.75;
  pointer-events: none;
}

/* O véu só existe onde há fotografia */
.faixa:has(::before) { position: relative; }
.faixa::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  /* Estes valores não foram escolhidos a olho. Simulei as camadas todas
     num canvas e medi o contraste do branco em cada ponto onde há texto,
     nas migalhas, no título e na legenda. Com o véu mais fraco que tinha, o
     pior ponto dava 2.5:1, por causa das luzes da árvore. Com estes dá
     5.5:1, acima do mínimo de 4.5:1.
     Se trocares a fotografia de uma categoria, vale a pena medir outra vez:
     uma foto mais clara pode precisar de mais véu. */
  background: linear-gradient(90deg, rgb(0 0 0 / 0.75) 0%, rgb(0 0 0 / 0.62) 55%, rgb(0 0 0 / 0.4) 100%);
  opacity: var(--veu, 0);
  pointer-events: none;
}
/* Os mesmos efeitos no cartão da página inicial ---------------------------
   O cartão tem as mesmas cinco camadas da faixa, mas encaixadas de outra
   maneira. Na faixa, a fotografia e o véu são dois pseudo-elementos; no
   cartão só há um livre, porque o ::after já é o furo do canto. Por isso as
   três camadas de fundo vão todas no ::before, empilhadas na propriedade
   background-image, que desenha a primeira por cima:

     1. o véu
     2. a cor da categoria a 25%, que é o mesmo que a foto a 75% por cima
        dela: 0.75*foto + 0.25*cor dá o mesmo resultado dos dois lados
     3. a fotografia

   O véu do cartão desce em vez de ir para o lado, porque é aí que o texto
   está: o nome e a descrição encostam ao fundo. Em cima fica quase limpo,
   para a fotografia respirar.

   Medido da mesma maneira que o da faixa, com as camadas reproduzidas e o
   contraste do branco calculado em cada ponto da metade de baixo, em três
   tamanhos de cartão e nas oito categorias: o pior ponto dá 5.2:1. Na faixa
   o pior é 6.1:1. O mínimo do WCAG AA é 4.5:1.
   A fotografia dos religiosos é a que manda nos dois números: é a mais
   clara depois do corte. Se mudares uma fotografia, mede outra vez. */
.cartao-cat a::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;                     /* debaixo do canvas das partículas (-1) */
  background-image:
    linear-gradient(180deg, rgb(0 0 0 / 0.10) 0%, rgb(0 0 0 / 0.5) 40%, rgb(0 0 0 / 0.9) 100%),
    linear-gradient(color-mix(in srgb, var(--cat) 25%, transparent) 0 100%),
    var(--foto-cartao, none);
  background-size: cover;
  background-position: center;
  opacity: var(--veu, 0);          /* sem fotografia, o cartão fica só com a cor */
  pointer-events: none;
}

/* Com fotografia por baixo, a subida no hover precisa de companhia: a
   fotografia aproxima-se um pouco, como um cartaz que se levanta. */
.cartao-cat a:hover::before { transform: scale(1.04); }
.cartao-cat a::before { transition: transform var(--dur) ease-out; }


/* ==========================================================================
   Telemóvel
   A passagem feita a 390px de largura, o de um iPhone normal (12 a 16), que
   é onde a maior parte das encomendas vai acontecer.
   Fica tudo aqui, no fim, dentro de max-width, e de propósito: o site foi
   afinado primeiro no ecrã largo, e estas regras só existem abaixo dele.
   Assim nenhuma mexe no computador sem se dar por isso.
   ========================================================================== */
@media (max-width: 63.99rem) {

  /* Cabeçalho: uma linha só, com menu, logo, lupa e carrinho.
     Antes, o campo de procura queria 176px na mesma linha, não cabia, e o
     carrinho caía para uma segunda linha por cima do conteúdo da página.
     O order muda o sítio de cada peça sem mexer no HTML: o menu e a procura
     ficam sempre depois do carrinho, e por serem de largura inteira caem
     para baixo da barra quando abrem. */
  .topo__barra { column-gap: var(--e-1); }
  .topo__menu     { order: 0; }
  .logo           { order: 1; }
  .topo__lupa     { order: 2; }
  .botao-carrinho { order: 3; }
  .topo__nav      { order: 4; }
  .procura-site {
    order: 5;
    display: none;
    flex-basis: 100%;
    margin: 0 0 var(--e-3);
  }
  .topo--procura .procura-site { display: block; }
  .procura-site input { width: 100%; }
  /* os resultados ocupam a largura toda, colados à linha da procura */
  .procura-site__painel {
    left: 0;
    right: 0;
    width: auto;
    max-height: calc(100dvh - 9rem);
  }
}

@media (max-width: 63.99rem) {

  /* Menu aberto: cobre o ecrã até ao fundo. Antes acabava a meio e via-se
     a página a espreitar por baixo, como se fizesse parte do menu.
     Não se dá altura à lista: estica-se o próprio cabeçalho até ao fundo do
     ecrã, e o fundo branco dele cobre tudo. Assim não há conta de altura
     que falhe por 8px, e se a lista for maior do que o ecrã, rola.
     A página de trás deixa de rolar enquanto o menu está aberto, senão o
     dedo que queria descer na lista arrastava a página. */
  .topo--aberto { bottom: 0; overflow-y: auto; overscroll-behavior: contain; }
  .topo--aberto .topo__nav { max-height: none; }
  body:has(.topo--aberto) { overflow: hidden; }
  /* o botão flutuante do WhatsApp ficava por cima do menu */
  .topo--aberto .botao-whatsapp { display: none; }

  /* Categorias da página inicial: o título a 17px em vez de 21. Aos 21,
     "Lembranças de aniversário" e "Gadgets para crianças" partiam em três
     linhas e chegavam ao furo do canto. */
  .cartao-cat a { min-height: 9.5rem; padding: var(--e-4); }
  .cartao-cat a::after { top: var(--e-3); right: var(--e-3); }
  .cartao-cat h3 { font-size: var(--t-base); }

  /* Página de categoria: procura e ordenação na mesma linha, a procura com
     o que sobra. Antes cada uma tinha a sua, e as duas comiam 96px antes
     de aparecer a primeira peça. */
  .ferramentas__lado {
    flex-wrap: nowrap;
    width: 100%;
    margin-left: 0;
  }
  .ferramentas__lado .procura { flex: 1; min-width: 0; }
  .procura input { width: 100%; }



  /* Botões só de texto (Remover, Esvaziar, Voltar ao carrinho): o alvo
     cresce para os 44px sem o texto mudar de tamanho. */
  .botao-texto {
    display: inline-flex;
    align-items: center;
    min-height: var(--alvo);
  }

  /* O crédito da Mondra tinha 17px de altura para tocar. A área cresce
     para os 44px por dentro do link; o desenho fica exactamente igual. */
  /* O gap repõe o espaço entre "por" e "Mondra": num inline-flex, o espaço
     em branco junto a uma peça desaparece. */
  .credito { display: inline-flex; align-items: center; gap: 0.3em; min-height: var(--alvo); }
  /* As duas linhas do fim alinhadas pelo meio: o crédito tem 44px de altura
     para o dedo, e o "© 2026" ficava encostado ao topo dele. */
  .rodape__fim { align-items: center; }

  /* Rodapé: as onze categorias em duas colunas, em vez de uma torre */
  .rodape__lista-cat {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: var(--e-4);
  }
}

/* Avaliações: lado a lado, a deslizar com o dedo, em vez de quatro cartões
   empilhados. Empilhadas davam quase 1600px de scroll para quatro frases. */
@media (max-width: 47.99rem) {
  .avaliacoes {
    display: flex;
    gap: var(--e-3);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    /* o mesmo truque dos destaques: a fila vai até às bordas do bloco */
    margin-inline: calc(-1 * var(--folga-bloco));
    padding-inline: var(--folga-bloco);
    scroll-padding-inline: var(--folga-bloco);
  }
  .avaliacoes::-webkit-scrollbar { display: none; }
  /* 85%: vê-se a ponta da seguinte, que é o que diz que há mais */
  /* position: relative é o que impede a página de alargar. Cada cartão
     tem um texto escondido para leitores de ecrã ("5 em 5 estrelas"), e a
     classe vh posiciona-o em absolute. Sem nenhum antepassado posicionado
     dentro da fila, esse texto não ficava preso ao cartão: escapava ao
     corte da fila e marcava a sua posição lá no quarto cartão, a mais de
     900px, e o telemóvel afastava o zoom da página inteira para o incluir.
     Com o cartão posicionado, o texto fica dentro dele e a fila corta-o. */
  .avaliacao {
    position: relative;
    flex: 0 0 85%;
    scroll-snap-align: start;
  }
}

/* Destaques num ecrã de toque: sem setas e sem desfile, a deslizar com o
   dedo. Sem as setas, a pista ganha os 110px que elas ocupavam, e passa a
   ir de borda a borda do ecrã, como as filas das lojas no telemóvel. */
/* E também em qualquer ecrã estreito, com ou sem rato: uma janela pequena
   no computador fica igual ao telemóvel. */
@media (hover: none), (max-width: 47.99rem) {
  .carrossel > .seta { display: none; }
  .carrossel { margin-inline: calc(-1 * var(--margem)); }
  .carrossel__pista {
    margin-inline: 0;
    padding-inline: var(--margem);
    scroll-padding-inline: var(--margem);
  }
}
/* No telemóvel, os dois cartões têm o tamanho dos da grelha. A pista vai
   de borda a borda do ecrã, e por isso sobra a ponta de um terceiro: é ela
   que diz que a fila continua para o lado. */

/* Num ecrã de toque não há rato a passar por cima. O :hover fica preso
   depois do toque, e o cartão ficava levantado ou com a foto ampliada
   depois de fechar o painel. Em troca, o toque dá uma resposta própria: o
   cartão encolhe um pouco enquanto o dedo está lá. */
@media (hover: none) {
  .cartao-cat a:hover,
  .cartao-cat a:hover::before,
  .produto:hover .produto__foto > .foto,
  .produto:hover .produto__foto > .foto-vazia { transform: none; }

  .cartao-cat a,
  .produto { -webkit-tap-highlight-color: transparent; }
  .cartao-cat a:active { transform: scale(0.97); }
  .produto:active .produto__foto > .foto,
  .produto:active .produto__foto > .foto-vazia { transform: scale(0.97); }
}

/* Faixas das categorias abaixo do ecrã largo -------------------------------
   No computador o texto vive à esquerda e o véu é mais forte desse lado.
   Aqui o texto ocupa a largura toda, e do lado direito, onde o véu era mais
   fraco, o Natal e os Porta-chaves caíam para 4.4:1 e 4.3:1, abaixo do
   mínimo. Com um véu igual de ponta a ponta, a 50%, o pior ponto das seis
   fotografias dá 5.2:1, medido a 390, a 768 e a 1000 de largura. E do lado
   esquerdo fica mais leve do que no computador: as fotos veem-se melhor. */
@media (max-width: 63.99rem) {
  .faixa::after { background: rgb(0 0 0 / 0.5); }
}

@media (max-width: 39.99rem) {
  /* Título a 26px: é o tamanho a que os onze cabem em duas linhas, a mesma
     regra do computador, e com isso as doze faixas ficam todas com a mesma
     altura. Aos 32px três partiam em três linhas, e as faixas tinham
     alturas diferentes: a mudança de página dava saltos. */
  .faixa h1 { font-size: min(1.625rem, 6.6vw); }
  /* O 6.6vw é para os ecrãs mais estreitos, o iPhone SE e o mini (375px):
     aí o título encolhe o bocadinho que falta para continuar a caber em
     duas linhas. A partir dos 394px o teto dos 26px manda. */

  /* A fotografia pequena, a de 640px que os cartões da inicial já usam.
     Chega para uma faixa de 366px, poupa dados (o Natal passa de 104KB
     para 29KB) e resolve os articulados: a versão larga tem a fotografia
     à direita e o desfocado à esquerda, e o telemóvel, ao cortar o meio,
     só mostrava o desfocado. */
  .faixa::before { background-image: var(--foto-cartao, none); }
}


/* Letreiro "Kukii" ---------------------------------------------------------
   O SVG chega colado no HTML, com cada letra num grupo .letra. O contorno
   de cada letra é outro grupo .letra com os mesmos valores, por isso as
   regras abaixo mexem nos dois de igual maneira e o contorno vai com ela.
   Cada letra traz no style a sua ordem (--i) e o meio do fundo (--ox,
   --oy): é desse ponto que ela encolhe e estica, como uma bola a bater no
   chão. As medidas dos saltos estão nas unidades do desenho, que tem 679
   de largura. Para quem pediu menos movimento ao sistema, a regra geral
   do movimento reduzido desliga tudo. */
.letreiro { display: block; height: auto; }
.letreiro .letra { transform-box: view-box; transform-origin: var(--ox) var(--oy); }

/* A carregar: aos saltinhos, uma letra de cada vez, sem parar */
.letreiro--a-carregar { width: 8rem; margin: 0 auto var(--e-3); }
.letreiro--a-carregar .letra {
  animation: letreiro-saltinho 1.2s ease-in-out infinite;
  animation-delay: calc(var(--i) * 0.12s);
}
@keyframes letreiro-saltinho {
  0%, 55%, 100% { transform: translateY(0); }
  25%           { transform: translateY(-36px); }
}

/* Estados vazios: grande e quase transparente, a ilustrar o momento sem
   competir com o texto, que continua a ser o que diz o que se passa. */
.letreiro--vazio { width: min(15rem, 70%); margin: 0 auto var(--e-4); opacity: 0.16; }
.carrinho__vazio .letreiro--vazio { margin-inline: 0; }

/* Rodapé: o letreiro a fechar a página */
.rodape__letreiro { margin-top: var(--e-6); }
.letreiro--rodape { width: min(10rem, 35%); margin-inline: auto; }

/* O aviso de peça adicionada: as letras saltam de contentes, uma de cada
   vez. Agacham-se, saltam a esticar, aterram a achatar e dão um ressalto
   pequeno antes de pararem. Uma vez só, de cada vez que o aviso aparece. */
.aviso .letreiro { width: 4.5rem; flex: none; }
.letreiro--feliz { overflow: visible; }
.letreiro--feliz .letra {
  animation: letreiro-feliz 0.9s cubic-bezier(0.3, 0.7, 0.4, 1) both;
  animation-delay: calc(0.12s + var(--i) * 0.07s);
}
@keyframes letreiro-feliz {
  0%   { transform: none; }
  15%  { transform: scale(1.12, 0.82); }
  40%  { transform: translateY(-80px) scale(0.92, 1.1); }
  62%  { transform: translateY(0) scale(1.1, 0.88); }
  78%  { transform: translateY(-18px) scale(1, 1); }
  100% { transform: none; }
}

/* Mensagem de contacto enviada: o mesmo salto do carrinho */
.letreiro--estado { width: 4.5rem; margin-bottom: var(--e-2); }

/* Rodapé: as letras saltam ao passar o rato ou ao tocar */
.letreiro--rodape { -webkit-tap-highlight-color: transparent; }

/* Quando algo corre mal (a procura não encontrou nada, as peças não
   carregaram): as letras abanam a cabeça, um "não" desajeitado, uma de
   cada vez. Uma vez só, e depois ficam quietas e esbatidas, como nos
   estados vazios. Mais à vista do que esses, porque aqui são uma reação. */
.letreiro--nao { width: min(12rem, 60%); margin: 0 auto var(--e-4); opacity: 0.35; overflow: visible; }
.letreiro--nao .letra {
  animation: letreiro-nao 0.9s ease-in-out both;
  animation-delay: calc(0.1s + var(--i) * 0.05s);
}
@keyframes letreiro-nao {
  0%, 100% { transform: none; }
  18%      { transform: rotate(-10deg); }
  38%      { transform: rotate(9deg); }
  58%      { transform: rotate(-6deg); }
  78%      { transform: rotate(3deg); }
}

/* Página 404: as letras começam caídas, espalhadas e tombadas para os
   lados, e levantam-se uma a uma até voltarem ao sítio, com um balanço no
   fim. A queda de cada letra sai da sua ordem: as das pontas caem mais. */
.perdido__corpo {
  display: grid;
  justify-items: center;
  gap: var(--e-4);
  padding-block: var(--e-6) var(--e-5);
  text-align: center;
}
.perdido__corpo p { max-width: 36ch; color: var(--texto-suave); }
/* A caixa à volta do letreiro ocupa a largura toda: sem isto ficava com
   a largura natural do desenho (679px), e o letreiro encostava-se à
   esquerda dela, fora do centro do título. */
[data-letreiro-perdido] { justify-self: stretch; }
.letreiro--perdido { width: min(18rem, 70%); overflow: visible; margin: 0 auto var(--e-3); }
.letreiro--perdido .letra {
  animation: letreiro-levantar 1.3s cubic-bezier(0.34, 1.56, 0.64, 1) both;
  animation-delay: calc(0.5s + var(--i) * 0.18s);
}
@keyframes letreiro-levantar {
  from { transform: translateY(48px) rotate(calc((var(--i) - 2) * 28deg)); }
  to   { transform: none; }
}

/* O comboio do "Como encomendar" -------------------------------------------
   Uma linha tracejada por cima dos passos, como um carril, e o letreiro a
   andar por cima dela. O JavaScript põe-no a andar e acende cada número
   quando ele passa. Enquanto anda, as letras vão aos saltinhos pequenos,
   como uma composição a rodar. */
.comboio {
  position: relative;
  height: 2.75rem;
  margin-bottom: var(--e-4);
  overflow: hidden;
}
.comboio::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 4px;
  border-bottom: 2px dashed var(--linha);
}
.letreiro--comboio {
  position: absolute;
  left: 0;
  bottom: 7px;
  width: 4.5rem;
  overflow: visible;
  transform: translateX(-120%);   /* fica fora da linha até arrancar */
}
.letreiro--a-andar .letra {
  animation: letreiro-andar 0.6s ease-in-out infinite;   /* ao passo de um comboio mais lento */
  animation-delay: calc(var(--i) * -0.09s);
}
@keyframes letreiro-andar {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-45px); }
}

/* Os números à espera do comboio ficam apagados, mas o texto de cada passo
   não: lê-se sempre, com ou sem comboio. Quando ele passa, o número acende
   na cor da marca e dá um pulo. */
.passos--a-espera > li::before { color: var(--linha); transition: color 0.25s; }
.passos--a-espera > li.passo--aceso::before {
  color: var(--marca);
  animation: passo-acende 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
  transform-origin: left bottom;
}
@keyframes passo-acende {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.3); }
  100% { transform: scale(1); }
}

/* Painel da peça no telemóvel: a foto mais pequena. A metade do ecrã que
   tinha no computador, aqui, com a largura toda, enchia o ecrã de imagem
   e o nome e o preço só apareciam depois de descer. Um terço da altura
   deixa ver a peça, o nome e o preço logo ao abrir. */
@media (max-width: 39.99rem) {
  .painel__palco { --alto: 34vh; }
}

/* "A nossa história" no telemóvel -----------------------------------------
   No ecrã largo o vídeo fica ao lado do texto. Aqui abre a secção, à
   largura toda, e o texto vem depois. A ordem muda só no ecrã: no HTML o
   texto continua primeiro, para quem usa leitor de ecrã. */
@media (max-width: 47.99rem) {
  .sobre__grelha { gap: var(--e-5); }
  .sobre__media { order: -1; }
}

/* Estilo Título nos blocos sem foto: o mesmo tamanho do nome nos cartões */
@media (min-width: 40rem) { .foto-vazia span { font-size: var(--t-medio); } }
