/* ============================================================
   LU OLIARI — Camada de design sobre o tema Morelia
   Sistema travado no wireframe v4
   Carregar por último no <head> do layout.tpl
   ============================================================ */

/* ------------------------------------------------------------
   1. SOBRESCRITA DOS TOKENS DO MORELIA
   O Morelia já expõe variáveis em style-tokens.tpl alimentadas
   pelo admin. O que dá para configurar no painel, configuramos
   lá. Aqui ficam só as que o painel não alcança.
   ------------------------------------------------------------ */

:root {

  /* Tipografia — famílias próprias LUO Display (Lemon Milk) e LUO
     Text (Milliard), auto-hospedadas via @font-face em
     snipplets/luoliari/fonts.tpl (incluído no layout.tpl, ver
     CLAUDE.md §4). Nomes próprios em vez do nome comercial: troca
     futura de arquivo (licença web quando sair) não exige tocar
     neste CSS. 'LUO Display Fallback'/'LUO Text Fallback' são faces
     locais (Helvetica Neue/Arial) com size-adjust/ascent-override
     calculados pra reduzir o salto de layout durante o swap — ver o
     mesmo snipplet. */

  --heading-font: 'LUO Display', 'LUO Display Fallback', 'Helvetica Neue', Arial, sans-serif;
  --body-font: 'LUO Text', 'LUO Text Fallback', 'Helvetica Neue', Arial, sans-serif;

  /* Título nunca em Bold — sistema do site inteiro, não só da
     página de série (h1-h6 e .h1-.h6 usam esta variável direto, ver
     bloco 3). Decisão original veio de testar o fallback de sistema
     (Helvetica Neue/Arial): 100/300 renderizavam idênticos ao 400
     nesse fallback. Com o arquivo real da Lemon Milk instalado (ver
     CLAUDE.md §4), a licença web ainda cobre só Regular (400) e
     Medium (500) — Light (300) nem chegou a ser preparado, então a
     comparação lado a lado real continua pendente. 400 segue sendo
     a escolha. */

  --title-font-weight: 400;

  /* Token nativo continua zerado — badges circulares, alerts, thumb
     de carrinho etc. seguem retos, sem herdar arredondamento. */

  --border-radius: 0px;
  --border-radius-half: 0px;
  --border-radius-quarter: 0px;

  /* Tokens próprios do projeto — arredondamento controlado, só onde
     for aplicado explicitamente abaixo (nunca por herança de
     --border-radius nativo). --luo-radius-btn é cápsula (referência
     do print); --luo-radius-input mais discreto de propósito —
     cápsula nos 7 tamanhos de variação leria como chip de filtro,
     não opção de configuração. Trocar --luo-radius-btn sozinho
     estende cápsula pra tudo, se um dia for essa a decisão. */

  --luo-radius-btn: 999px;
  --luo-radius-input: 8px;
  --luo-radius-img: 8px;
  --luo-radius-panel: 16px; /* modais laterais: busca, carrinho, menu mobile */

  /* Sem sombra. */

  --shadow-distance: 0 0 0;
}

/* ------------------------------------------------------------
   2. TOKENS PRÓPRIOS DO PROJETO
   Nomes com prefixo luo- para nunca colidir com o Morelia.
   ------------------------------------------------------------ */

:root {

  /* Texto */
  --luo-ink: #111111;      /* preto principal, títulos */
  --luo-ink-soft: #3A3A3A; /* repouso do menu principal (hover/ativo vão a --luo-ink) */
  --luo-body: #55554F;     /* corpo de texto */
  --luo-muted: #8A8A84;    /* labels e metadados */
  --luo-soft: #77776F;     /* barra utilitária, preço secundário */
  --luo-faint: #9A9A94;    /* notas e textos legais */

  /* Superfícies */
  --luo-bg: #FFFFFF;
  --luo-surface: #F8F8F6;  /* barra utilitária, faixas de seção */
  --luo-line: #ECECE8;     /* divisores */
  --luo-border: #C9C9C4;   /* bordas de input */

  /* Placeholders de imagem */
  --luo-ph-1: #F3F3F0;
  --luo-ph-2: #EBEBE7;
  --luo-ph-3: #E3E3DF;

  /* Única cor de marca — exclusiva do CTA de compra */
  --luo-buy: #2F6B4F;

  /* Escala tipográfica — reduzida em 2026-09-18 (pedido do Victor:
     ~20% menor no mobile, ~10% menor no desktop, mantendo a
     hierarquia H1>H2>H3 e o nome de entidade como piso). Valores
     abaixo são o lado DESKTOP de --luo-hero/--luo-h2 (o mobile de
     cada um é um número solto na regra que os usa — .h1-huge e
     .luo-sec-head h2 — nunca leu o token nesse lado; arquitetura já
     era assim antes desta rodada, só os números mudaram). --luo-h3
     ganhou split mobile/desktop pela primeira vez (era flat, único
     uso em "A obra"): base aqui é o mobile, redefinido dentro do
     media query de 1024px logo abaixo. */
  --luo-hero: 52px;
  --luo-h2: 29px;
  --luo-h3: 19px;
  --luo-label: 11px;

  /* Corpo do site inteiro — reduzido (era 15px fixo) e fluido em vez
     de saltar entre um valor mobile e um desktop: 13px até ~390px,
     sobe suave até 14px por volta de 1024px, trava em 14px dali pra
     frente. O piso de 13px existe pra nunca ficar ilegível numa tela
     de 320px. Todo corpo de texto do site consome esta variável —
     nenhuma seção declara o próprio tamanho de corpo (ver blocos 7,
     8, 11, 12, 15). */
  --luo-body-size: clamp(13px, 12.4px + 0.16vw, 14px);

  /* Letter-spacing. Logo: era 6px fixo (3,5px no mobile); agora -0.04em —
     em, não px, pra a proporção entre letras seguir o tamanho da fonte
     em cada lugar (header 22-32px, rodapé 16px). Medido na tinta real
     das letras (canvas, LUO Display 21px): 0em dá 1,7-2,4px de vão
     entre glifos; -0.04em dá 0,9-1,5px (quase coladas, sem colisão —
     -0.05em já encosta a 0,7px). word-spacing compensa o espaço entre
     "LU" e "OLIARI", que o letter-spacing negativo também encolhe. */
  --luo-ls-logo: -0.04em;
  --luo-ws-logo: 0.2em;

  /* Tamanho do logo do header (2026-09-19, 2ª rodada: 22→32px ficou
     grande demais; pedido do cliente: 19px no mobile, 26px no desktop —
     26px = 2x o menu de 13px, "não mais que isso"). clamp() linear entre
     19px em 390px e 26px em 1440px: inclinação (26-19)/(1440-390) =
     0,6667vw; base 19 - 390*0,006667 = 16,4px. Abaixo de 390px trava em
     19px, acima de 1440px em 26px. Vale pra TODAS as larguras — sem px
     avulso por breakpoint (1024px dá 23,2px). O menu (13px) não muda.
     REDUZIDO EM 10% (2026-09-26, pedido do cliente): 17,1px/23,4px nas
     pontas (mesma reta, coeficientes recalculados — 0,6vw, base 14,76px).
     REDUZIDO DE NOVO, SÓ NA PONTA DESKTOP (2026-09-26, mesmo dia, 2ª
     rodada — pedido explícito "mobile não muda"): 23,4px → 17,55px
     (-25%, 23.4*0.75). Piso de 390px continua 17,1px (não mexido). Reta
     recalculada com as duas pontas novas: inclinação (17,55-17,1)/
     (1440-390) = 0,042857vw; base 17,1 - 390*0,00042857 = 16,933px.
     Faixa responsiva ficou bem mais estreita que antes (17,1→17,55px em
     vez de 17,1→23,4px) — consequência matemática de cortar 25% só no
     topo mantendo o piso; se parecer pouca variação entre mobile e
     desktop, é esperado, não é bug. */
  --luo-logo-size: clamp(17.1px, 16.933px + 0.042857vw, 17.55px);
  --luo-ls-label: 3px;
  --luo-ls-serie: 2px;

  /* Layout */
  /* 2026-09-30: 1280 -> 1520px (conteudo ate ~1390px em tela grande). */
  --luo-container: 1520px;
  --luo-gutter-desktop: 80px;
  --luo-gutter-mobile: 20px;

  /* Gutter lateral das seções luo_* (.luo-section, bloco 3b) — mesmo
     valor do gutter nativo (.container, --guter-container em
     style-critical.scss), constante em todos os breakpoints, porque
     é assim que o nativo funciona: só --guter-container-md (40px)
     muda, e só para .container-fluid, não para .container comum. */
  --luo-gutter: 30px;
}

/* Desktop (>=1024px): gutter fluido 53px (1024) -> 76px (>=1460). Notebook
   de 1440px fica com 75px de cada lado (era 110px); tela grande limita
   pelo --luo-container. Mobile/tablet (<1024px) continuam em 30px. */
@media (min-width: 1024px) {
  :root {
    --luo-gutter: clamp(40px, 5.2vw, 76px);
    /* Corpo +10% no desktop (2026-09-30): 14px -> 15.4px, token do tema e
       --font-base nativo (texto de produto, descricoes). */
    --luo-body-size: 15.4px;
    --font-base: 15.4px;
  }

  /* Header usa o .container nativo (largura do admin + 60px, padding 30px):
     alinha com a grade das secoes. */
  .head-main .container,
  .head-main .container-fluid {
    max-width: var(--luo-container);
    padding-left: var(--luo-gutter);
    padding-right: var(--luo-gutter);
  }
}

/* 1024-1199px: com 7 itens (Loja entrou no menu) o menu nao cabia numa
   linha e os icones saiam da tela. Itens mais justos so nessa faixa. */
@media (min-width: 1024px) and (max-width: 1199px) {
  .head-main .desktop-nav-col .nav-desktop-list { gap: 0; }
  .head-main .desktop-nav-col .nav-desktop-list > li {
    padding-left: 10px;
    padding-right: 10px;
  }
  .head-main .desktop-nav-col .nav-desktop-list > li:first-of-type { padding-left: 20px; }
}

@media (min-width: 1024px) {
  :root {
    --luo-h3: 22px;
  }
}

/* Respiro vertical padrão ENTRE as seções (.luo-section, bloco 3b, e
   a faixa da Newsletter, bloco 14) — padding-top e padding-bottom de
   cada seção. Um token só: mudar o ritmo da página é mudar estes dois
   números. 2026-09-18: 64/128px → 48/96px (−25%). Vão entre duas
   seções empilhadas = 2× o token (96px mobile / 192px desktop, era
   128/256px). */
:root {
  --luo-section-gap: 48px;
}

@media (min-width: 1024px) {
  :root {
    --luo-section-gap: 96px;
  }
}

/* Home (2026-09-28, pedido explícito: −25% SÓ na home, desktop) —
   redeclara o token escopado a `body.template-home` (classe nativa,
   `<body class="... template-{{ template }}">` em layout.tpl), nunca
   o `:root` global acima — qualquer outra página (série, coleção,
   Sobre, Loja etc.) continua nos 96px normais. 96×0,75=72px. Mobile
   (<1024px) não muda em lugar nenhum, pedido explícito também.
   Investigação prévia (Ambientação "mais afastada que as demais",
   mesmo pedido): medido ao vivo ANTES desta mudança — todo par de
   seções da home, incluindo as duas que cercam a Ambientação, já
   dava exatamente 2×--luo-section-gap (192px desktop / 96px mobile),
   sem margin nem padding extra em lugar nenhum (conferido computed
   style de .luo-ambientacao e do wrapper .luo-ambientacao-section,
   os dois 0/0 de margin). Não havia excesso pra remover — o full-
   bleed da Ambientação (rodada anterior) já tinha eliminado qualquer
   resíduo do modo "contido" antigo. Efeito colateral esperado e
   correto desta mudança: como a Ambientação usa o MESMO token, sem
   regra própria, ela cai pra 72px igual às outras automaticamente. */
@media (min-width: 1024px) {
  body.template-home {
    --luo-section-gap: 72px;
  }
}

/* Rodapé escuro (bloco 33). Fundo quase preto puxado pro quente, em
   harmonia com o bege do site (--luo-surface, #F8F8F6): mesma família
   de matiz, sem chegar ao preto puro. Texto sempre branco; repouso dos
   links e legendas por transparência do branco (o contraste real
   contra o fundo está no relatório da rodada — todos acima de 7:1). */
:root {
  --luo-footer-bg: #1B1A17;
  --luo-footer-text: #FFFFFF;
  --luo-footer-link: rgba(255, 255, 255, 0.78);
  --luo-footer-muted: rgba(255, 255, 255, 0.64);
  --luo-footer-line: rgba(255, 255, 255, 0.16);
}

/* ------------------------------------------------------------
   3. BASE
   ------------------------------------------------------------ */

body {
  background: var(--luo-bg);
  color: var(--luo-body);
  font-family: var(--body-font);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
  font-family: var(--heading-font);
  font-weight: var(--title-font-weight);
  color: var(--luo-ink);
}

/* Label em caixa alta — padrão que se repete em toda a home */

.luo-label {
  display: block;
  font-family: var(--body-font);
  font-size: var(--luo-label);
  letter-spacing: var(--luo-ls-label);
  text-transform: uppercase;
  color: var(--luo-muted);
  margin-bottom: 10px;
}

/* Nome de entidade — nível de título intermediário, sistema do site
   inteiro. Caixa alta, peso 500 — o tamanho já NÃO é único entre os
   dois usos (ver ajuste abaixo): nome de coleção ficou menor que
   nome de produto, de propósito, depois do primeiro ajuste visual.
   "Nome de série" fica documentado aqui pra usar quando existir um
   lugar de verdade pra ele: hoje só existe como H1 da página de
   série (28-44px, registro de título de página, não de rótulo
   compacto) — o candidato natural seria a futura página de listagem
   "Séries" (.docs/series-v2-luoliari.html), ainda não implementada.

   Peso 500 é a variável, não um valor mágico: testado ao vivo no
   fallback atual (Helvetica Neue/Arial, ver CLAUDE.md §4) — colapsa
   pro mesmo desenho do 400 (confirmado lado a lado, sem diferença de
   traço visível). Aplicado mesmo assim: passa a valer sozinho quando
   a fonte real (Lemon Milk) carregar via @font-face. */
.luo-colecoes-name,
.item-name {
  font-family: var(--heading-font);
  font-weight: 500;
  text-transform: uppercase;
  color: var(--luo-ink);
}

/* Nome de coleção — mesmo tamanho do nome de produto (.item-name),
   mesma variável, sem media query: o nome de produto usa um valor
   único pra todos os breakpoints, então a coleção acompanha. */
.luo-colecoes-name {
  font-size: var(--font-base) !important;
}

/* Nome de produto — mesmo tamanho do preço (não mais o tamanho do
   nome de coleção): o contraste entre os dois passa a vir só do peso
   (500 vs 400), nunca do tamanho. Por isso o valor é a MESMA
   variável usada em .item-price logo abaixo, num lugar só — se o
   preço mudar de tamanho no futuro, o nome acompanha sozinho. */
.item-name {
  font-size: var(--font-base) !important;
}

/* .item-name nativo carrega .font-small (!important do Bootstrap,
   por isso o !important acima é necessário, não estilístico) e
   .opacity-80 — essa opacidade fazia sentido pro nome pequeno e
   discreto de antes; nesse nível novo (caixa alta, peso 500) o nome
   vira uma informação primária, mesmo tom de --luo-ink que nome de
   coleção, sem esmaecer. */
.item-name {
  opacity: 1;
}

/* Preço: sobe do tamanho pequeno nativo (--font-small, 13px) pro
   tamanho base (--font-base, 15px — a mesma variável de "corpo" que
   o painel do Lu já configura) e fixa peso de corpo (400) — o
   contraste com o nome vem do peso (500 vs 400) e da caixa alta, não
   do tamanho. É a MESMA variável usada em .item-name acima. */
.item-price {
  font-size: var(--font-base);
  font-weight: 400;
}

/* Card de produto no MOBILE (<768px): nome e preço 20% menores
   (2026-09-18, segunda rodada) — 15px → 12px, calculado sobre a mesma
   variável (calc * 0.8) pra continuar acompanhando --font-base se ela
   mudar. Escopo .item-product (wrapper do snipplets/grid/item.tpl):
   vale pra série, home (best sellers, série em destaque), Loja/busca e
   Produtos similares, e NÃO pega a página de produto aberta (H1 e
   preço grande dela não são .item-name/.item-price) nem o nome de
   post do blog (templates/blog.tpl também usa .item-name). O preço
   riscado (.price-compare) herda a fonte de .item-price-container
   (--font-small, 13px) — reduzido junto (10,4px) pra não ficar maior
   que o preço atual. Desktop intocado. */
@media (max-width: 767px) {
  .item-product .item-name {
    font-size: calc(var(--font-base) * 0.8) !important;
  }

  .item-product .item-price {
    font-size: calc(var(--font-base) * 0.8);
  }

  .item-product .item-price-container {
    font-size: calc(var(--font-small) * 0.8);
  }
}

/* Cabeçalho de seção — label + h2 + link à direita.
   Padrão canônico usado em todas as seções da home. */

.luo-sec-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  margin-bottom: 40px;
}

.luo-sec-head h2 {
  font-size: var(--luo-h2);
  margin: 0;
}

.luo-sec-head .luo-sec-link {
  font-size: 13px;
  letter-spacing: 0.3px;
  color: var(--luo-ink);
  white-space: nowrap;
}

@media (max-width: 1023px) {
  .luo-sec-head { margin-bottom: 22px; }
  .luo-sec-head h2 { font-size: 19px; }
}

/* Container do projeto */

.luo-inner {
  max-width: var(--luo-container);
  margin: 0 auto;
  padding: 0 var(--luo-gutter-mobile);
}

@media (min-width: 1024px) {
  .luo-inner { padding: 0 40px; }
}

/* ------------------------------------------------------------
   3b. WRAPPER PADRÃO DAS SEÇÕES LUO_*
   Nasce em TODA seção nova (luo_obra, luo_colecoes, luo_sobre,
   luo_arquiteto, ...) — largura de container (--luo-container,
   travada no wireframe) e gutter lateral (--luo-gutter, tirado do
   nativo — ver comentário no bloco 2) + respiro vertical único
   entre seções, tudo num só lugar. Nenhuma seção declara padding
   próprio: era isso que fazia a luo_obra ficar mais recuada que as
   outras no desktop (40px hardcoded, maior que o gutter nativo) e o
   mosaico/sobre ficarem colados na borda no mobile (o padding do
   .luo-colecoes/.luo-sobre, declarado depois de .luo-inner no
   arquivo, tinha a mesma especificidade e vencia por ordem de
   cascata — zerava o padding lateral inteiro via shorthand).

   Exceção consciente: imagem full-bleed de propósito (como o hero,
   bloco 6) sai do container por regra própria (width:100vw + margin
   negativa), nunca tirando o padding daqui — o wrapper da seção
   sempre respeita o container; quem sangra é o elemento full-bleed
   dentro dela.
   ------------------------------------------------------------ */

/* .luo-inset = só o alinhamento horizontal (container + gutter) de
   .luo-section, sem o respiro vertical — pra trechos que continuam o
   fluxo de uma seção já aberta (ex.: cabeçalho "Obras" na página de
   série) e não podem abrir um respiro de seção novo por cima do que
   já existe. */
.luo-section,
.luo-inset {
  max-width: var(--luo-container);
  margin: 0 auto;
  padding-left: var(--luo-gutter);
  padding-right: var(--luo-gutter);
}

.luo-section {
  /* Era 64px mobile / 128px desktop — agora vem do token único
     --luo-section-gap (48/96px, bloco 2). */
  padding-top: var(--luo-section-gap);
  padding-bottom: var(--luo-section-gap);
}

/* 3c. TOPO DE PÁGINA INTERNA (2026-09-18)
   .luo-section sozinho tem o respiro pensado pra SEPARAR seções
   empilhadas (Coleções → A obra → Best sellers...) — 64/128px. Como
   primeiro elemento de uma página interna (logo abaixo do header),
   esse mesmo valor virava um vão enorme e vazio (medido ao vivo:
   747px de altura de seção em 1440px, 128px inteiros disso era só
   espaço em branco antes da imagem do herói começar — nenhuma outra
   margem/padding envolvida, causa única confirmada). Modificador
   .luo-section--top substitui só o padding-top por um valor menor,
   pensado pra "primeiro bloco depois do header", não pra intervalo
   entre seções — usado em .luo-serie-hero (série E coleção,
   category-serie-header.tpl/category-colecao-header.tpl),
   .luo-cs-listagem (/colecoes//séries) e .luo-contato. */
.luo-section--top {
  padding-top: 32px;
}

@media (min-width: 1024px) {
  .luo-section--top {
    padding-top: 48px;
  }
}

/* Placeholder de imagem enquanto as fotos reais não entram */

.luo-ph { background: var(--luo-ph-1); }
.luo-ph.d2 { background: var(--luo-ph-2); }
.luo-ph.d3 { background: var(--luo-ph-3); }

/* 3d. VÉU GRADIENTE — componente único dos banners com legenda sobre
   foto (2026-09-18): hoje o Hero (.section-slider .slide-container,
   bloco 6) e a Ambientação (.luo-ambientacao-media, bloco 13). Antes
   eram dois véus diferentes, um em cada bloco.

   Forma: preto de baixo pra cima, 0% no topo do véu até --luo-veil-
   -alpha na base, cobrindo só o terço inferior do bloco (--luo-veil-
   -height, fração do PRÓPRIO bloco — acompanha qualquer altura,
   mobile ou desktop). Cada banner só declara a INTENSIDADE (var) no
   próprio bloco; a regra abaixo não se repete. Padrão 45% (Ambientação);
   o Hero pede "bem sutil" e sobrescreve pra 25% no bloco 6.

   Pseudo-elemento ::after DENTRO do bloco, que já corta o overflow
   (Ambientação: overflow:hidden + radius no desktop; slide do Hero:
   overflow:hidden nativo) — o radius, quando existe, corta o véu junto
   com a foto sem vazar nos cantos; border-radius:inherit garante o
   mesmo se um bloco futuro não cortar o overflow. z-index:1 põe o véu
   acima da foto (.slider-image do Hero é z-index:1 e vem antes no DOM)
   e ABAIXO da legenda: .swiper-text é z-index:9 (nativo) e
   .luo-ambientacao-cap é z-index:2. pointer-events:none: nunca
   intercepta clique (o slide do Hero inteiro é um <a>).

   Restrição do projeto: nada de escurecer a foto inteira.

   CRITÉRIO PRA IMAGENS DO CLIENTE (decisão 2026-09-18): o véu só
   garante contraste onde a legenda cai sobre área escura ou vazia da
   foto. Banner com legenda precisa de área ESCURA OU VAZIA no canto
   inferior esquerdo (onde a legenda ancora). Medido ao vivo, com as
   fotos atuais o branco não atinge AA (4,5:1) em toda a área do texto
   — Ambientação: contraste médio ~3,8-4,0:1 no eyebrow e ~3,3-3,5:1 no
   título, ~1/3 a 1/2 dos pixels passam; a legenda é mais alta que o
   terço do bloco, então o eyebrow começa acima do véu. O véu NÃO deve
   ser reforçado pra compensar (escureceria a fotografia). Se a foto
   nova resolver, ótimo; se não, revisitamos. */
.luo-ambientacao-media::after,
.section-slider .slide-container::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  height: var(--luo-veil-height, 33.334%);
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(to top, rgba(0, 0, 0, var(--luo-veil-alpha, 0.45)), rgba(0, 0, 0, 0));
}

/* ------------------------------------------------------------
   4. CABEÇALHO
   Classes reais do Morelia: .head-main, .head-logo-row,
   .desktop-nav-col. Re-estilizamos, não recriamos.
   ------------------------------------------------------------ */

.head-main {
  background: var(--luo-bg);
  border-bottom: 1px solid var(--luo-line);
}

/* Altura reduzida ~20% (2026-09-28, pedido explícito): era 84px
   desktop / 60px mobile, agora 67px / 48px (−20,24% / −20%). A altura
   é só este `min-height` (não há padding-top/bottom próprio aqui) —
   `display:flex; align-items:center` centraliza o conteúdo dentro
   dele, então reduzir o min-height reduz o respiro acima/abaixo de
   logo/menu/ícones sem encolher os próprios elementos (nenhum dos
   dois novos valores fica menor que o conteúdo mais alto: 32,5px
   desktop/ícone de busca, 44px mobile/área de toque do hambúrguer —
   medido ao vivo antes de escolher o número). Isso muda a barra
   branca inteira (`.head-main`), não a faixa escura de anúncio
   (`.ad-bar`, bloco 5, `min-height` própria, intocada). */

.head-main .head-logo-row {
  min-height: 48px;
  display: flex;
  align-items: center;
}

/* Desktop de verdade só a partir de 1024px (2026-09-19): de 768 a 1023px
   o header é o MESMO do mobile (hambúrguer) — ver blocos 4d/4e. */
@media (min-width: 1024px) {
  .head-main .head-logo-row { min-height: 67px; }
}

/* Logo em caixa alta com letter-spacing largo */

.head-main .logo-container-col .h3 {
  font-family: var(--heading-font);
  font-size: var(--luo-logo-size);
  /* 500 (Medium), não --title-font-weight (400): pedido do cliente é
     Bold (700), que ainda não existe no tema (ver fonts.tpl) — 500 é o
     mais pesado disponível hoje, só na logo. */
  font-weight: 500;
  letter-spacing: var(--luo-ls-logo);
  word-spacing: var(--luo-ws-logo);
  text-transform: uppercase;
  margin: 0;
  color: var(--luo-ink);
}

/* Logo = texto fixo "LU OLIARI" (snipplets/header/header.tpl), com o
   link da home dentro do .h3 — herda cor/tamanho/tracking do título. */
.head-main .logo-container-col .h3 a {
  color: inherit;
  text-decoration: none;
}

/* Navegação ao lado do logo, centralizada no eixo */

@media (min-width: 1024px) {
  .head-main .desktop-nav-col {
    justify-content: center;
  }
}

/* ------------------------------------------------------------
   5. BARRA UTILITÁRIA (barra de anúncios nativa)
   Fundo --luo-ink (preto), texto branco — referência Galeria9.
   Revertido de --luo-surface (bege claro, decisão anterior — ver
   histórico de contraste abaixo, superada). --luo-surface CONTINUA
   valendo pras faixas bege do site (banner Sobre, série em destaque),
   só não nesta barra. Não usei #000 puro: --luo-ink (#111111) já dá
   18.1:1 contra branco, folga enorme sobre o mínimo AAA (7:1) — não
   precisa de preto absoluto. Só a altura/padding não mudam (min-
   height igual ao anterior) — só cor de fundo e de texto. */
.head-main .ad-bar,
.head-main [class*="adbar"] {
  background: var(--luo-ink);
  color: #FFFFFF;
  min-height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11.5px;
  letter-spacing: 1px;
}

.head-main .ad-bar a,
.head-main [class*="adbar"] a {
  color: #FFFFFF;
  text-decoration: underline;
}

@media (max-width: 767px) {
  .head-main .ad-bar,
  .head-main [class*="adbar"] {
    min-height: 32px;
    font-size: 10px;
    letter-spacing: 0.8px;
  }
}

/* ------------------------------------------------------------
   4b. CABEÇALHO — distribuição em três zonas (DESKTOP, ≥ 1024px)
   Assume o controle do grid do Morelia na linha do logo. Era 768px
   (breakpoint md do Bootstrap); desde 2026-09-19 só a partir de
   1024px — abaixo disso vale o header mobile (blocos 4d/4e).
   ------------------------------------------------------------ */

@media (min-width: 1024px) {

  .head-main .head-logo-row > .row {
    display: flex !important;
    flex-wrap: nowrap !important;
    align-items: center;
    width: 100%;
  }

  /* Logo: largura natural, à esquerda */

  .head-main .head-logo-row > .row > .logo-container-col {
    flex: 0 0 auto !important;
    width: auto !important;
    max-width: none !important;
  }

  /* Navegação: ocupa todo o espaço livre e centraliza os links */

  .head-main .head-logo-row > .row > .desktop-nav-col {
    flex: 1 1 auto !important;
    width: auto !important;
    max-width: none !important;
    display: flex !important;
    justify-content: center;
    align-items: center;
  }

  /* Ícones: largura natural, empurrados para a direita */

  .head-main .head-logo-row > .row > .js-utility-col {
    flex: 0 0 auto !important;
    width: auto !important;
    max-width: none !important;
  }

  /* Espaçamento entre os links do menu: FLUIDO (2026-09-19, 3ª rodada) —
     32px de 1280px pra cima (idêntico ao de sempre), encolhendo até 16px
     em telas menores. Junto com o nowrap abaixo: sem ele "Sou Arquiteto"
     quebrava em 2 linhas entre 1024 e ~1060px (o menu ficava na largura
     MÍNIMA, 716px); com nowrap o mínimo sobe ~27px e o gap fluido devolve
     mais que isso a 1024px (5 vãos × ~6,4px = 32px). */

  .head-main .desktop-nav-col ul {
    display: flex;
    gap: clamp(16px, 2.5vw, 32px);
    margin: 0;
    padding: 0;
  }

  .head-main .desktop-nav-col a.nav-list-link {
    white-space: nowrap;
  }

  /* Logo → primeiro item do menu (2026-09-27, pedido: mesma distância
     que existe ENTRE dois itens do menu). Achado medindo ao vivo em
     1440px: o gap real entre itens não é o `gap: 32px` do `ul` sozinho —
     o nativo soma padding lateral de 15px em cada `.nav-item`
     (style-critical.scss, `.nav-item{padding:0 15px}`), então o vão
     visual entre "Início" e "Coleções" é 32+15+15=62px. O PRIMEIRO
     `<li>` (`.nav-desktop-list > li:first-of-type`, nativo) tem
     `padding-left:40px` em vez dos 15px dos demais — é só esse padding
     que separa a logo do "Início" (a `<ul>` já começa colada na borda
     direita da logo, sem margem própria), daí o gap medido de 40px, não
     62px. Corrigido igualando o padding-left do 1º item à MESMA soma
     (gap fluido + 15+15 do padding nativo dos outros itens) — sem
     número mágico solto, acompanha o gap fluido do `ul` em qualquer
     largura, não só em 1440px. Medido depois do fix: 62px nos dois
     lugares. Especificidade (0,4,0) vence o nativo (0,2,0) sem
     precisar de !important. */
  .head-main .desktop-nav-col .nav-desktop-list > li:first-of-type {
    padding-left: calc(clamp(16px, 2.5vw, 32px) + 30px);
  }
}

/* ------------------------------------------------------------
   4c. NAVEGAÇÃO — itens do menu (desktop + hambúrguer)
   Classe real do Morelia: .nav-list-link (mesma classe nos dois
   contextos — snipplets/navigation/navigation-nav-list.tpl usa ela
   tanto no <a> de item de topo quanto dentro do painel do
   hambúrguer/mobile — uma regra só cobre os dois, sem reescrever
   nada). "Página atual" também já é nativo: o próprio .tpl gera
   `{{ item.current ? 'selected' : '' }}` no mesmo <a> — não precisou
   inventar detecção nenhuma, só mirar a classe que já existe.
   Transição só de color (nunca font-weight/tamanho, que reflui).

   Duas exceções de especificidade do nativo, achadas testando ao
   vivo (uma regra só de classe não bastava em nenhum dos dois
   contextos abaixo — sem eles, só o painel do hambúrguer, que não
   mora dentro de .head-main, pegava --luo-ink-soft):
   1. `.head-main a` (style-colors.scss, 0,1,1 — classe + tag) vence
      `.nav-list-link` sozinho (0,1,0) nos itens de TOPO (sem
      dropdown). Resolvido escrevendo `a.nav-list-link` (também 0,1,1)
      — mesma especificidade, e como nosso CSS carrega por último no
      layout.tpl, o empate cai pra nós.
   2. `.desktop-dropdown .nav-item a` (0,2,1) vence os dois acima nos
      subitens DENTRO do mega-menu aberto (2 classes bate 1). Precisa
      de uma terceira regra, mais específica ainda, só pra esse
      contexto aninhado.

   Peso/tamanho — referência Galeria9: 13px (era 15px nativo, sem
   ajuste nosso até então — primeira vez que o tamanho é tocado; -2px
   por pedido). Peso 600 (Milliard SemiBold, já hospedada — ver
   CLAUDE.md §4) — revisado de 700 (Bold) em 2026-09-17, achado pesado
   demais pelo cliente; SemiBold já estava hospedada (usada em
   accordion aberto/variação selecionada/cart-total), só trocar o
   número. Sublinhado por `text-decoration`, nunca `border-bottom`:
   não participa do box model, então não move layout nem muda altura
   de linha (`transition` continua só em color, igual antes — nunca
   font-weight/tamanho, que reflui). Truque de entrada: o sublinhado
   fica sempre presente (text-decoration-line: underline), só a COR
   dele anima de transparent pra --luo-ink — é a cor que "revela" o
   traço, não o traço aparecendo/sumindo.

   `font-size` com `!important`, único caso aqui — achado testando ao
   vivo cada nível do menu: o nativo tem font-size em CASCATA de
   especificidade crescente pro mesmo `.nav-list-link`, uma pra cada
   profundidade (`.modal-nav-hamburger .nav-list-link` no hambúrguer
   — 0,2,0; `.desktop-list-subitems .nav-item .nav-list-link` no 1º
   nível do mega-menu — 0,3,0; `...list-subitems .nav-item .nav-list-
   link` no 2º nível — 0,5,0). `a.nav-list-link` sozinho (0,1,1) só
   ganha no topo do menu, sem dropdown — replicar uma regra por
   profundidade seria frágil (quebra se a Nuvemshop mudar a marcação
   nativa). font-weight não precisou do mesmo tratamento — conferido
   nos 3 arquivos CSS nativos, nenhum declara font-weight pra
   `.nav-list-link` em nenhum contexto, só font-size. */
a.nav-list-link {
  font-size: 13px !important;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: -0.03em;
  color: var(--luo-ink-soft);
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 6px;
  text-decoration-color: transparent;
  transition: color 0.2s, text-decoration-color 0.2s;
}

a.nav-list-link:hover,
a.nav-list-link.selected {
  color: var(--luo-ink);
  text-decoration-color: var(--luo-ink);
}

a.nav-list-link:focus-visible {
  outline: 2px solid var(--luo-ink);
  outline-offset: 3px;
}

.desktop-dropdown .nav-item a.nav-list-link {
  color: var(--luo-ink-soft);
  text-decoration-color: transparent;
}

.desktop-dropdown .nav-item a.nav-list-link:hover,
.desktop-dropdown .nav-item a.nav-list-link.selected {
  color: var(--luo-ink);
  text-decoration-color: var(--luo-ink);
}

/* Mobile (hambúrguer, #nav-hamburger): só o item ativo (.selected)
   fica sublinhado — sem sublinhado em :hover/tap, que não é um
   estado de repouso real em touch. ID vence a especificidade das
   regras acima sem depender de ordem no arquivo. */
#nav-hamburger a.nav-list-link:hover {
  text-decoration-color: transparent;
}

/* ------------------------------------------------------------
   4d. HEADER MOBILE — UMA LINHA SÓ (< 1024px). Era < 768px (breakpoint
   md do Bootstrap, onde os ícones nativos trocam via `d-md-none`/
   `d-md-inline-block`); desde 2026-09-19 vale até 1023px — tablet em pé
   (768/820px) e paisagem pequena usam o hambúrguer, menu horizontal só
   a partir de 1024px. De 768 a 1023px as classes `d-md-*` nativas ainda
   trocam sozinhas pro desktop; o bloco 4e desfaz isso.

   Hoje a logo cai numa 2ª linha por causa de DUAS classes nativas
   condicionais (logo_position_mobile == 'below', settings.txt):
   `col-12` (100% de largura, força quebra) + `order-last` (13,
   depois dos ícones na ordem do flex). O ícone de hambúrguer some
   por padrão porque herda `.col` puro (flex-grow:1) e cresce mais
   que precisa. Nada disso é !important nativo (conferido em
   style-critical.scss) — mas como são classes condicionadas por
   settings que podem mudar, sobrescrever com !important aqui é mais
   seguro do que confiar só em especificidade: garante que a regra
   continue funcionando mesmo se o Lu trocar `logo_position_mobile`
   no admin.

   Ordem final: logo (1, esquerda) → carrinho (2) → hambúrguer
   (3, ponta direita — ver seletores abaixo, únicos o bastante pra
   não precisar tocar no .tpl). Busca já não aparece aqui (nativo:
   settings.search_type_mobile == 'hidden' bota o campo dentro do
   hambúrguer, ver header-modals.tpl) — só ganhou o radius abaixo.
   ------------------------------------------------------------ */
@media (max-width: 1023px) {
  /* CORREÇÃO (achado ao vivo numa rodada seguinte): faltava
     width:100% aqui. `.head-main .head-logo-row` (bloco 4, acima)
     já é display:flex — então `.row`, como filho único dela, vira
     item de flex sem largura própria (flex-basis:auto) e encolhe
     pro tamanho do CONTEÚDO em vez de esticar pros 100% do
     container. Resultado: a linha inteira (logo + ícones) parava
     em ~195px em vez de ir até a borda dos 390px — "termina na
     metade da tela". O bloco desktop (4b, `min-width:768px`) já
     tinha esse width:100% explícito; só faltou espelhar aqui. */
  .head-logo-row .row {
    flex-wrap: nowrap;
    width: 100%;
  }

  /* CORREÇÃO (achado ao vivo, só aparecia com a página rolada):
     o nativo (logo_position_mobile == 'below') tem um JS de scroll
     que, ao detectar o header sticky, aplica INLINE em 3 elementos —
     `style="margin-top: -40px"` na .logo-container-col (+ classe
     `.logo-inside-nav`) e `style="height: 40px; padding-top: 10px"`
     nos dois .js-utility-col (ícones). É um truque pensado pro
     layout nativo de 2 linhas (puxar a logo pra cima simula 1 linha
     só quando ele mesmo ainda está em 2). Como aqui a logo já nasce
     na MESMA linha dos ícones via flex — não por esse truque — o
     JS descolava a logo ~40px pra cima da barra de anúncios assim
     que a página rolava, e comprimia a altura dos ícones. Não
     aparecia no topo da página (o JS só age depois do primeiro
     scroll), por isso passou despercebido na 1ª validação. `!important`
     nos 3 porque são inline styles — só especificidade máxima vence,
     não basta ordem de cascata. */
  .head-main .js-utility-col {
    height: auto !important;
    padding-top: 0 !important;
  }

  /* Hambúrguer — único utility-col com d-md-none */
  .js-utility-col.col-utility.d-md-none {
    flex: 0 0 auto !important;
    width: auto !important;
    order: 3 !important;
  }

  /* Logo — ocupa o espaço do meio, empurra os ícones pra ponta */
  .logo-container-col {
    flex: 1 1 auto !important;
    width: auto !important;
    max-width: none !important;
    order: 1 !important;
    text-align: left !important;
    padding-top: 0 !important;
    padding-bottom: 0 !important;
    margin-top: 0 !important;
  }

  .logo-container-col .h3 {
    white-space: nowrap;
  }

  /* Carrinho (+ conta/idiomas, mesma coluna) — único utility-col
     com d-flex nativo (a busca, que também herda .desktop-utility-col,
     não tem essa classe — distingue os dois sem ambiguidade) */
  .js-utility-col.desktop-utility-col.d-flex {
    order: 2 !important;
  }

  /* Área de toque 44×44, ícone centralizado — escopado a .head-main
     pra não afetar o botão do WhatsApp (mesma classe .btn-utility,
     snipplets/whatsapp-chat.tpl, fora do header). */
  .head-main .btn-utility {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    padding: 0 !important;
  }

  /* Traço do hambúrguer encostado na borda direita do CONTEÚDO, e
     traço do carrinho a 16px do traço do menu — achado medindo ao
     vivo (getBBox do <use> convertido pra tela, 2026-09-17): com os
     dois botões em 44×44 (largura igual à altura) coladas um no
     outro, o mínimo de gap possível entre os DOIS TRAÇOS sem encolher
     nem sobrepor as áreas de toque já dava ~26,5px — mais que os
     16px pedidos. Decisão: largura própria de 36px pros dois (altura
     continua 44px — ainda folgado sobre o mínimo WCAG 2.2 AA de
     24px), + justify-content:flex-end nos dois. Só a largura muda
     (min-width sobrescreve o 44px do bloco acima); altura/toque
     vertical intactos. Resultado medido, não assumido — ver relatório
     com os valores antes/depois. */
  #ajax-cart.cart-summary a.btn-utility,
  [data-component="menu-button"].btn-utility {
    min-width: 36px;
    width: 36px;
    justify-content: flex-end;
  }

  /* Badge do carrinho: hoje é só um número solto (sem fundo, sem
     raio — conferido ao vivo, style-critical.scss só posiciona,
     nunca estiliza a aparência). Vira pill preto discreto, fixo no
     canto do ícone via top/right (troca o transform:translate(-50%)
     nativo, pensado pra outro layout, que jogava o número acima do
     ícone em vez de no canto dele). */
  #ajax-cart .badge {
    position: absolute;
    top: 2px;
    right: 2px;
    left: auto;
    margin: 0;
    transform: none;
    min-width: 14px;
    height: 14px;
    padding: 0 3px;
    border-radius: 999px;
    background: var(--luo-ink);
    color: #FFFFFF;
    font-size: 9px;
    line-height: 14px;
    text-align: center;
  }

  /* Campo de busca dentro do hambúrguer (settings.search_type_mobile
     == 'hidden' bota o header-search.tpl direto no modal_body, sem
     o wrapper #nav-search — precisa de seletor próprio). */
  #nav-hamburger .search-input {
    border-radius: var(--luo-radius-input);
  }
}

/* ------------------------------------------------------------
   4e. HEADER — FAIXA 768–1023px (hambúrguer no lugar do menu horizontal)
   O nativo troca mobile↔desktop em 768px pelas classes `d-md-*` e por
   um JS de carga (store.js.tpl, `if (window.innerWidth > 768)`) que só
   REVELA o menu/ícones (visibility:hidden nativo) quando a tela já
   nasce > 768px. Consequências que este bloco resolve, sem editar o
   arquivo nativo:
   - a 768px EXATOS o JS não revela nada e o header ficava só com o
     logo (nem menu, nem carrinho, nem hambúrguer) — a visibilidade
     agora é forçada por CSS, não depende mais do JS nem de a página
     ter carregado nessa largura (resize/rotação sem recarregar);
   - de 768 a 1023px o hambúrguer (.d-md-none) sumia e o menu
     horizontal aparecia — aqui inverte: hambúrguer visível, menu,
     busca e ícone de conta (que no mobile moram dentro do drawer)
     escondidos. Layout de uma linha = o do bloco 4d.
   `!important` porque `.d-md-none`/`.d-none.d-md-*` são !important
   nativos — só especificidade maior vence.
   ------------------------------------------------------------ */
@media (min-width: 768px) and (max-width: 1023px) {
  .head-main .js-utility-col.col-utility.d-md-none {
    display: block !important;
  }

  .head-main .desktop-nav-col,
  .head-main .js-search-utility,
  .head-main .desktop-utility-col.d-flex > span.d-md-inline-block {
    display: none !important;
  }

  /* Campo de busca dentro do hambúrguer (header-modals.tpl o embrulha
     em `d-block d-md-none`) — sem isto a busca sumia no tablet. */
  #nav-hamburger .d-md-none {
    display: block !important;
  }
}

@media (min-width: 768px) {
  /* O nativo esconde o carrinho/ícones (visibility:hidden; height:0) de
     .head-logo-md-left até o JS de carga revelar — ver comentário acima. */
  .head-main .desktop-utility-col {
    visibility: visible;
    height: auto;
  }
}

@media (min-width: 1024px) {
  .head-main .desktop-nav-col {
    visibility: visible;
    height: auto;
  }
}

/* ------------------------------------------------------------
   6. HERO — seção 1 da home (slider nativo)
   Classes reais de snipplets/home/home-slider.tpl: .section-slider,
   .js-home-slider-container, .js-home-slider-row, .swiper-container,
   .slide-container, .slider-slide, .slider-image, .swiper-text,
   .h1-huge, .btn-link, .js-swiper-home-pagination,
   .swiper-pagination-bullet, .swiper-button-prev/-next. Classe
   .section-slider é exclusiva deste snipplet (verificado, não
   aparece em outro template).

   Sangria total sempre — não depende do checkbox "Extender al
   ancho de la pantalla" do admin, porque o wireframe exige full-bleed
   incondicional. Altura fixa via cascata nativa: .swiper-wrapper,
   .swiper-slide e .slider-image do Morelia já usam height:100%,
   então basta fixar a altura no .swiper-container.

   !important nos itens abaixo é proposital: o framework do Morelia
   que estiliza .swiper-text/.h1-huge/.mb-1/.mb-2/.btn-link é injetado
   pela plataforma (via {% head_content %} em layout.tpl) e não fica
   nos arquivos deste tema — não dá pra ler as regras nem vencer por
   especificidade quando elas usam !important, então revidamos só
   nas propriedades em disputa (posição, largura, espaçamento).
   ------------------------------------------------------------ */

/* --luo-hero-gutter seguia a MESMA fórmula (e o mesmo bug) que
   --luo-bleed-gutter tinha antes do fix da Ambientação (bloco 12,
   ver comentário ali): piso de 20px + só metade do espaço sobrando,
   sem somar --luo-gutter — por isso o texto do Hero nascia 10-30px
   mais à esquerda que "A obra"/"Coleções" (20px fixo no mobile
   contra os 30px de --luo-gutter; 80px em 1440px contra os 110px
   reais de .luo-section = (100vw-1280)/2 + 30). Corrigido pra usar a
   MESMA fórmula do inset de .luo-section (bloco 3b), confirmado ao
   vivo nos dois breakpoints. */
:root {
  --luo-hero-gutter: calc(max(0px, (100vw - var(--luo-container)) / 2) + var(--luo-gutter));
}

/* Vão branco de 24px entre o cabeçalho e o Hero — causa raiz encontrada
   2026-09-26: o Morelia aplica `mt-4` (margin-top: 1,5rem = 24px,
   !important — bloco de utilitárias nativas) condicionado a
   "not settings.slider_full and not settings.head_transparent" em DOIS
   lugares que se empilham: no `<section class="js-home-slider-section">`
   (home-section-switch.tpl) e, um nível mais fundo, no wrapper
   `.js-home-(main|mobile)-slider-visibility` (home-slider.tpl) — os
   dois pensados pro hero NÃO sangrado (respiro antes da foto). Como a
   sangria aqui é incondicional (regra abaixo, sempre full-bleed, não
   depende do checkbox), os dois mt-4 ficaram órfãos e só empurravam o
   Hero pra baixo do cabeçalho (medido ao vivo: os dois setavam 24px
   cada, mas por estarem só um dentro do outro sem margin-collapse —
   .section-slider tem position:relative — o efeito somado ainda dava
   só 24px, não 48px; mesmo assim os dois precisam ser zerados, senão o
   de fora sozinho já reproduz o bug). Zerados na origem (os wrappers, o
   `.section-slider` nunca teve margin) — nunca reintroduzir sem
   revisitar por que o Morelia aplica essa classe nesses dois níveis. */
.js-home-slider-section.mt-4,
.js-home-main-slider-visibility.mt-4,
.js-home-mobile-slider-visibility.mt-4 {
  margin-top: 0 !important;
}

/* Sangria total do bloco */
.section-slider {
  position: relative;
  width: 100vw;
  left: 50%;
  margin-left: -50vw;
}

/* Neutraliza container/row/col internos — sempre edge-to-edge,
   independente da classe que o admin aplicou (.container ou
   .container-fluid) */
.section-slider .js-home-slider-container {
  max-width: none;
  width: 100%;
  padding: 0;
}

.section-slider .js-home-slider-row {
  margin: 0;
}

.section-slider .js-home-slider-row > .col-12 {
  padding: 0;
}

/* Altura do slide — proporção, não altura fixa (2026-09-26): antes
   700px desktop / 580px mobile (arte precisava bater exatamente esse
   pixel); agora aspect-ratio, a arte entra em qualquer resolução e o
   navegador calcula a altura a partir da largura (100vw, bloco acima).
   object-fit: cover no <img> (abaixo) faz o recorte central — mesmo
   comportamento visual de antes, só que sem exigir um tamanho de
   arquivo exato. Mobile 16/17 (retrato, ~9% mais baixo que o 4/5
   inicial — reduzido 15% em cima do resultado medido de 4/5, pedido
   do cliente em 2026-09-26: 487,5px → 414,4px em 390px de largura,
   390×17/16=414,375) e 20/7 desktop (arte 2400×840) — proporções
   combinadas com o cliente. */
.section-slider .swiper-container {
  aspect-ratio: 16 / 17;
  height: auto;
}

@media (min-width: 1024px) {
  .section-slider .swiper-container {
    aspect-ratio: 20 / 7;
  }
}

.section-slider .slider-image {
  object-fit: cover;
  object-position: center;
}

/* Overlay de texto — sai do centralizado nativo, ancora embaixo à
   esquerda na mesma coluna do container de 1280px das seções
   seguintes (mesmo cálculo de gutter usado em .luo-inner) */
.section-slider .swiper-text {
  display: flex !important;
  flex-direction: column !important;
  align-items: flex-start !important;
  text-align: left !important;
  top: auto !important;
  transform: none !important;
  bottom: 64px !important;
  left: var(--luo-hero-gutter) !important;
  right: auto !important;
  width: auto !important;
  max-width: calc(100vw - 2 * var(--luo-gutter-mobile)) !important;
  padding: 0 !important;
}

@media (min-width: 1024px) {
  .section-slider .swiper-text {
    bottom: 96px !important;
    max-width: 640px !important;
  }
}

/* Neutraliza qualquer posicionamento próprio que o framework da
   plataforma aplique em cada filho (título/descrição/botão) — sem
   isso, cada um pode ficar centralizado por conta própria e empilhar
   por cima do outro em vez de respeitar a ordem do flex acima */
.section-slider .swiper-text > * {
  position: static !important;
  width: auto !important;
  max-width: 100% !important;
}

/* Reordena sem tocar no HTML — 2026-09-28: revertido, era descrição
   (eyebrow) ACIMA do título, agora título PRIMEIRO e descrição como
   texto de corpo ABAIXO dele (pedido explícito); botão continua por
   último. */
.section-slider .swiper-text p { order: 2; }
.section-slider .swiper-text .h1-huge { order: 1; }
.section-slider .swiper-text .btn-link { order: 3; }

/* Cor de título/descrição — GLOBAL pro carrossel inteiro (2026-09-28,
   settings.luo_slider_titulo_cor/_descricao_cor; não é possível por
   slide, ver CLAUDE.md). Valor calculado em home-slider.tpl e
   passado por custom property inline no wrapper .swiper-text — as
   regras aqui só consomem a variável, com fallback branco (visual de
   antes desta rodada) pro caso raro de faltar. Continua sem condicionar
   por slide: o véu no rodapé (adiante) é quem garante contraste contra
   a foto, agora reforçado pelo aviso de imagem clara/escura no admin
   (ver settings.txt). */
.section-slider .swiper-text p {
  font-family: var(--body-font);
  font-size: var(--luo-body-size) !important;
  letter-spacing: normal;
  text-transform: none;
  color: var(--luo-slide-desc-color, #FFFFFF);
  margin: 0 0 20px !important;
}

.section-slider .h1-huge {
  font-family: var(--heading-font);
  font-weight: var(--title-font-weight);
  font-size: 27px !important;
  line-height: 1.18 !important;
  white-space: normal !important;
  color: var(--luo-slide-title-color, #FFFFFF);
  margin: 0 0 12px !important;
}

@media (min-width: 1024px) {
  .section-slider .h1-huge {
    font-size: var(--luo-hero) !important;
    line-height: 1.12 !important;
    margin-bottom: 16px !important;
  }
  .section-slider .swiper-text p {
    margin-bottom: 30px !important;
  }
}

/* Véu no rodapé da foto — agora o COMPONENTE ÚNICO do bloco 3d (o
   mesmo da Ambientação, bloco 13): terço inferior, preto 0% → --luo-
   -veil-alpha na base. Antes o Hero tinha um véu próprio (gradiente
   sobre a foto inteira, 45% na base → 0 aos 55% da altura). Aqui só a
   INTENSIDADE, "bem sutil" por pedido: 25% (Ambientação usa o padrão
   de 45%). Medido antes/depois em 2026-09-18 (slide com texto, pixels
   reais): o véu novo cobre menos que o antigo (o texto, 316px/221px
   desde a base, é mais alto que o terço de 233px/193px), então o
   contraste médio do branco caiu — desktop: eyebrow 7,6 → 6,7 e título
   6,0 → 4,5; mobile: eyebrow 4,5 → 3,4 e título 5,1 → 3,6 (ver
   relatório). Reforçar é só subir a variável abaixo. */
.section-slider .slide-container {
  position: relative;
  --luo-veil-alpha: 0.25;
}

/* CTA — único disponível no slide nativo (pendência: ver aviso sobre
   o segundo CTA fantasma). Reaproveita o componente compartilhado
   (snipplets/luoliari/luo-btn.tpl, variante light) desde 2026-09-18 —
   antes era um .btn-link com todas as propriedades redeclaradas à
   mão, porque não dava pra reaproveitar a classe (ver histórico:
   o framework nativo da plataforma estiliza .btn-link com !important,
   injetado via {% head_content %}, fora de qualquer arquivo do tema).
   Continua precisando de !important só nas propriedades que ainda
   disputam contra esse framework (display/altura/padding/largura) —
   cor, borda, radius, fonte e a animação de letras agora vêm 100% de
   .luo-btn--light (bloco 30) e .luo-btn-anim (bloco 30b), sem
   duplicar nada. btn_tag:'div' no include (não 'a') porque o slide
   inteiro já é um <a> nativo (home-slider.tpl) — um <a> aninhado
   seria HTML inválido; o aria-label do botão soma no nome acessível
   do link de fora do mesmo jeito (cálculo padrão por conteúdo). */
.section-slider .btn-link {
  display: inline-flex !important;
  align-items: center;
  justify-content: center;
  height: 44px !important;
  padding: 0 32px !important;
  width: auto !important;
}

/* Achado ao vivo (2026-09-18, testado em 390px): `.swiper-text > *`
   logo acima força `position: static !important` em TODO filho
   direto do texto do slide — inclusive este botão, que também é
   filho direto. Sem `position: relative` de verdade, o
   `.luo-btn-face--back` (position:absolute;inset:0, bloco 30b) para
   de resolver contra a caixa do BOTÃO e passa a resolver contra o
   ancestral posicionado mais próximo — as letras saíam espalhadas
   por cima do H1/descrição em vez de ficarem presas dentro do botão.
   `!important` aqui é o único jeito de vencer a regra `> *` acima
   (mesmo elemento, mesma especificidade de classe — quem decide é a
   ordem: `!important` sempre vence `!important` por especificidade
   normal depois). */
.section-slider .swiper-text > .luo-btn-anim {
  position: relative !important;
}

/* Sem setas na home — navegação só pelos bullets */
.section-slider .swiper-button-prev,
.section-slider .swiper-button-next {
  display: none;
}

/* Paginação nativa (prev/pagination/next) vira overlay DENTRO do
   slider, sobreposta à imagem, ancorada na base — não empurra o
   conteúdo abaixo do hero. Alinhada à direita, na mesma coluna do
   container de 1280 do resto do conteúdo (mesmo gutter do
   .swiper-text). Depende de static/js/store.js.tpl usar
   type: 'bullets' na paginação do slider (ver aviso). */
.section-slider .js-home-slider-row .mt-2.text-center {
  position: absolute !important;
  z-index: 20;
  bottom: 40px !important;
  left: var(--luo-hero-gutter) !important;
  right: var(--luo-hero-gutter) !important;
  top: auto !important;
  margin: 0 !important;
  display: flex !important;
  justify-content: flex-end !important;
  align-items: center !important;
}

/* Container dos bullets — classe estável independente do type do
   Swiper (existe no .tpl, não é adicionada dinamicamente) */
.section-slider .js-swiper-home-pagination {
  display: flex !important;
  align-items: center !important;
  gap: 10px;
  width: auto !important;
}

/* Bullets: 8px, sem preenchimento, borda branca — com um anel sutil
   em preto por baixo pra não sumir nas fotos claras (pedido
   explícito no lugar do drop-shadow, pra não abrir uma exceção de
   sombra no sistema por causa de um detalhe de contraste) */
.section-slider .swiper-pagination-bullet {
  width: 8px;
  height: 8px;
  margin: 0 !important;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.85);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
  opacity: 1;
}

.section-slider .swiper-pagination-bullet-active {
  background: #FFFFFF;
  border-color: rgba(255, 255, 255, 0.85);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
}

/* ------------------------------------------------------------
   7. A OBRA — seção 3 da home (snipplets/luoliari/home-a-obra.tpl)
   Classes próprias (.luo-*), sem depender de nada nativo do Morelia
   além do .luo-inner já existente — por isso sem !important aqui.

   Um item = botão + painel juntos no DOM (ver comentário no .tpl).
   Mobile (base): painel no fluxo normal, logo abaixo do botão —
   isso já É o accordion, controlado pelo atributo [hidden] nativo
   do HTML, sem precisar de classe própria pra esconder.
   Desktop (min-width:1024px): painéis empilhados via position:
   absolute sobre a mesma área, comportamento de abas — troquei
   [hidden] por opacity/visibility porque os 4 painéis precisam
   existir ao mesmo tempo no layout absoluto.

   Padding lateral e vertical vêm de .luo-section no wrapper (ver
   bloco 3b) — antes a luo_obra tinha padding próprio (136px/120px
   no desktop) maior que o das outras seções, ficando visivelmente
   recuada. Investigado o vão grande abaixo do painel ativo: não há
   min-height nem margem acumulada no CSS (painel inativo é
   display:none, não reserva altura; grid-item não colapsa margem
   dos filhos) — o vão vinha só desse padding bespoke, resolvido ao
   herdar o mesmo respiro das demais seções.
   ------------------------------------------------------------ */

/* Cabeçalho: empilhado no mobile, grid 6fr/5fr no desktop */
.luo-obra-head {
  margin-bottom: 32px;
}

/* font-family explícito — achado ao investigar o bug do título de
   "Sou Arquiteto" (bloco 12): esta e outras 2 seções (Ambientação,
   Sou Arquiteto) usam <p>, não <h1-6>, então não herdavam
   --heading-font pela regra global do bloco 3 — caíam no
   --body-font por omissão. Sem efeito visível no fallback de hoje
   (os dois caem na mesma fonte de sistema), mas errado assim que a
   fonte real entrar. .luo-sobre-quote já fazia certo; corrigido nos
   outros 3 (ver blocos 12 e 13 também). */
.luo-obra-title {
  font-family: var(--heading-font);
  font-size: 21px;
  line-height: 1.35;
  font-weight: var(--title-font-weight);
  color: var(--luo-ink);
  margin: 12px 0 0;
  text-transform: uppercase;
}

.luo-obra-title em {
  font-style: normal;
  color: var(--luo-muted);
}

.luo-obra-lead {
  font-size: var(--luo-body-size);
  line-height: 1.8;
  color: var(--luo-body);
  margin: 14px 0 0;
}

@media (min-width: 1024px) {
  .luo-obra-head {
    display: grid;
    grid-template-columns: 6fr 5fr;
    gap: 96px;
    align-items: end;
    margin-bottom: 52px;
  }

  .luo-obra-title {
    font-size: 36px;
    line-height: 1.3;
    margin-top: 18px;
  }

  .luo-obra-lead {
    max-width: 400px;
    padding-bottom: 6px;
    margin-top: 0;
  }
}

/* Faixa de abas — accordion no mobile (borda por item), tabs no
   desktop (borda em cima/embaixo da faixa inteira) */
.luo-obra-item {
  border-top: 1px solid var(--luo-line);
}

.luo-obra-item:last-child {
  border-bottom: 1px solid var(--luo-line);
}

.luo-obra-tab {
  display: flex;
  align-items: baseline;
  gap: 12px;
  width: 100%;
  padding: 19px 0;
  background: none;
  border: none;
  font-family: var(--body-font);
  font-size: 15px;
  color: var(--luo-muted);
  text-align: left;
  cursor: pointer;
}

.luo-obra-tab-n {
  font-size: 10px;
  letter-spacing: 1.5px;
}

.luo-obra-tab-x {
  margin-left: auto;
  font-size: 16px;
  line-height: 1;
}

.luo-obra-tab-x::before {
  content: '+';
}

.luo-obra-item.is-active .luo-obra-tab {
  color: var(--luo-ink);
  font-weight: 500;
}

.luo-obra-item.is-active .luo-obra-tab-x::before {
  content: '\2212';
}

.luo-obra-panel {
  padding: 4px 0 26px;
}

.luo-obra-panel .luo-obra-image {
  aspect-ratio: 16 / 9;
  margin-bottom: 16px;
  display: block;
  width: 100%;
  object-fit: cover;
  border-radius: var(--luo-radius-img);
}

.luo-obra-text p {
  font-size: var(--luo-body-size);
  line-height: 1.75;
  color: var(--luo-body);
  margin: 0;
}

.luo-obra-text h3 {
  font-size: var(--luo-h3);
  margin: 14px 0;
}

@media (min-width: 1024px) {
  /* Grid de 2 linhas: linha 1 = as 4 abas lado a lado, linha 2 = um
     único painel span full-width, abaixo da faixa inteira.
     .luo-obra-item vira display:contents — some da caixa, mas seus
     filhos (o botão e o painel) continuam no DOM, então entram
     direto como itens do grid do pai. Isso resolve sem posicionar
     nada como absolute: o painel inativo é display:none (não
     participa do grid, não ocupa espaço) e só o painel ativo (o
     único com display:grid) dita a altura da linha 2 — por isso o
     contêiner encolhe/cresce sozinho e o rodapé para de subir por
     cima. Sem crossfade: troca é seca, display none↔grid. */
  .luo-obra-tabs {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    border-top: 1px solid var(--luo-line);
    border-bottom: 1px solid var(--luo-line);
  }

  .luo-obra-item {
    display: contents;
  }

  .luo-obra-tab {
    grid-row: 1;
    align-items: baseline;
    gap: 12px;
    padding: 24px 8px 22px;
    font-size: 15px;
  }

  .luo-obra-tab-n {
    font-size: 11px;
  }

  /* +/- é recurso só do accordion mobile */
  .luo-obra-tab-x {
    display: none;
  }

  .luo-obra-item.is-active .luo-obra-tab {
    border-bottom: 2px solid var(--luo-ink);
    margin-bottom: -1px;
  }

  .luo-obra-panel {
    grid-row: 2;
    grid-column: 1 / -1;
    display: none;
  }

  .luo-obra-item.is-active .luo-obra-panel {
    display: grid;
    grid-template-columns: 7fr 5fr;
    gap: 88px;
    align-items: center;
    padding: 60px 0 0;
  }

  .luo-obra-panel .luo-obra-image {
    aspect-ratio: 16 / 9;
    margin-bottom: 0;
  }

  .luo-obra-text h3 {
    margin: 14px 0;
  }

  .luo-obra-text p {
    line-height: 1.9;
    max-width: 400px;
  }
}

/* ------------------------------------------------------------
   8. TEXTO LONGO DA SÉRIE (categoria)
   snipplets/luoliari/category-serie-text.tpl, incluído de dentro de
   category-serie-header.tpl (coluna de texto do cabeçalho da série —
   bloco 8b). Renderizado no SERVIDOR desde 2026-09-17 (era fetch
   client-side pra uma Página "serie-X" — trocado por um campo só,
   settings.luo_series_textos, parseado em Twig; texto já chega no
   HTML da primeira resposta, sem atraso nem salto de layout, sem JS
   nenhum envolvido — static/js/luoliari-home-N.js perdeu o módulo
   initSerieLongText inteiro). O parágrafo fixo idêntico em toda série
   ("Ao decorar seus espaços...") também saiu nessa mudança — não
   existe mais, nem como texto fixo nem como campo.

   Tipografia: "p{line-height:1.4286em}" é regra global nativa
   (style-critical.scss) — declarada aqui de novo, explícita, não por
   acidente de herança (mesmo valor, só documentado). */

.luo-serie-text-wrap p {
  font-size: var(--luo-body-size);
  line-height: 1.4286;
  color: var(--luo-body);
  margin-bottom: 20px;
}

/* ------------------------------------------------------------
   8b. CABEÇALHO DA PÁGINA DE SÉRIE
   snipplets/luoliari/category-serie-header.tpl. Referência:
   .docs/serie-v2-luoliari.html (desktop) e
   .docs/serie-v2-mobile-luoliari.html (mobile).

   Mobile (base, a partir de 390px — mas testado até 320px):
   pilha, imagem antes do texto — mesma ordem de leitura do DOM nos
   dois breakpoints, sem precisar de "order" (diferente do bloco 12,
   Sou Arquiteto, onde mobile e desktop invertem a ordem visual).

   Desktop (min-width:1024px — breakpoint principal do projeto,
   mesmo dos outros cabeçalhos em 2 colunas do tema): grid 7fr/5fr.

   Título em clamp() — interpola em vez de saltar entre dois valores
   fixos, para não quebrar feio em larguras intermediárias (tablet,
   telas grandes) que os wireframes não cobrem. Reduzido em
   2026-09-18 (pedido do Victor, ~20% menor no mobile/~10% menor no
   desktop): ~28px em 390px, trava em 40px a partir de ~658px —
   compartilhado com .luo-contato-title (mesma expressão, mesmo
   motivo: os dois são H1 de página, sem cabeçalho de seção acima).
   ------------------------------------------------------------ */

.luo-serie-hero-grid {
  display: grid;
  gap: 40px;
}

.luo-serie-hero-image-wrap {
  aspect-ratio: 4 / 3;
  overflow: hidden;
}

.luo-serie-hero-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Sem isso, entre ~600px e o breakpoint de 1024px (onde a própria
   proporção 7fr/5fr do grid já limita a largura), o texto empilhado
   esticava quase de ponta a ponta do container — linha longa demais
   pra leitura confortável. Testado em 768px. */
.luo-serie-hero-text {
  max-width: 640px;
}

.luo-serie-hero-title {
  font-size: clamp(1.4rem, 0.65rem + 4.5vw, 2.5rem);
  line-height: 1.15;
  margin: 10px 0 14px;
}

.luo-serie-hero-lead {
  font-size: var(--luo-body-size);
  line-height: 1.8;
  color: var(--luo-body);
  margin: 0 0 18px;
}

/* flex-wrap é o que impede a ficha de estourar ou virar rolagem
   horizontal em tela estreita — os itens quebram linha em vez de
   comprimir ou vazar. margin-top aumentado (era 18px) — é o respiro
   entre o fim do texto curatorial e a ficha, apertado demais antes. */
.luo-serie-ficha {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  border-top: 1px solid var(--luo-line);
  padding-top: 14px;
  margin-top: 40px;
  font-size: 11.5px;
  letter-spacing: 0.3px;
  color: var(--luo-soft);
}

.luo-serie-ficha b {
  color: var(--luo-ink);
  font-weight: 500;
}

@media (min-width: 1024px) {
  .luo-serie-hero-grid {
    grid-template-columns: 7fr 5fr;
    gap: 96px;
    align-items: center;
  }

  .luo-serie-hero-lead {
    line-height: 1.9;
    max-width: 440px;
  }

  .luo-serie-ficha {
    margin-top: 48px;
  }

  .luo-serie-ficha {
    font-size: 12.5px;
    gap: 12px 28px;
  }
}

/* ------------------------------------------------------------
   8c. GRID ESCALONADO DAS OBRAS (página de série)
   Escopo: .luo-serie-grid, classe condicional em templates/
   category.tpl só quando is_serie — não toca coleção nem busca
   (templates/search.tpl tem seu próprio include de
   filters-modals.tpl e sua própria grade, intocados).

   Reaproveita o grid de produtos 100% nativo (snipplets/grid/
   product-list.tpl → product_grid.tpl → grid/item.tpl, com toda a
   paginação/infinite-scroll/estado-vazio resolvidos lá) — só
   sobrescreve o CONTAINER (de flex/Bootstrap pra CSS Grid) e o item
   (neutraliza col-N nativo) pra conseguir o escalonamento por
   nth-child do wireframe, independente de quantas colunas o admin
   configurou em "Listado de productos" pra categoria/busca comuns.

   3 breakpoints com comportamento próprio (não só mobile/desktop):
   mobile (base) = 2 colunas, coluna da direita descendo; tablet
   (min-width:700px, breakpoint dedicado só do grid — o cabeçalho
   acima continua no principal de 1024px) já assume o desenho final
   de 3 colunas com a coluna do meio descendo, que também vale pro
   desktop.
   ------------------------------------------------------------ */

.luo-serie-grid .js-product-table {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
  margin: 0;
}

.luo-serie-grid .js-item-product {
  flex: none;
  width: auto;
  max-width: none;
  padding: 0;
}

/* `of .js-item-product`: conta só os cards, ignorando irmãos que não
   são produto. snipplets/product_grid.tpl solta um
   <div class="last-page" style="display:none"> como PRIMEIRO filho do
   grid sempre que a página é a última (série com poucas obras = sempre)
   — sem o `of`, esse filho invisível deslocava toda a contagem em 1:
   o escalonamento caía na 1ª obra (+40px mobile, +64px desktop de vão
   antes dela, medido ao vivo) e na coluna errada (esquerda em vez da
   direita/do meio). Navegador sem suporte a `of S` ignora a regra
   inteira: sem escalonamento, nunca escalonamento errado. */
.luo-serie-grid .js-item-product:nth-child(2n of .js-item-product) {
  margin-top: 40px;
}

@media (min-width: 700px) {
  .luo-serie-grid .js-product-table {
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
    row-gap: 60px;
  }

  .luo-serie-grid .js-item-product:nth-child(2n of .js-item-product) {
    margin-top: 0;
  }

  .luo-serie-grid .js-item-product:nth-child(3n+2 of .js-item-product) {
    margin-top: 64px;
  }
}

/* Respiro entre o fim do cabeçalho da série e "Obras" — era 8px,
   apertado demais (a única outra separação vinha do padding-bottom
   de .luo-section no herói, pensado pra separar SEÇÕES da home, não
   dois blocos dentro da mesma página de série). */
.luo-serie-obras-head-wrap {
  margin-top: 32px;
}

@media (min-width: 1024px) {
  .luo-serie-obras-head-wrap {
    margin-top: 56px;
  }
}

/* Respiro entre o título "Obras" e a 1ª obra (2026-09-18, segunda
   rodada) — era 64px no mobile / 104px no desktop, medido ao vivo.
   Composição do vão: (a) o offset do escalonamento caindo na 1ª obra
   (40/64px — corrigido acima com `of .js-item-product`), (b)
   .luo-sec-head { margin-bottom } de 22px mobile / 40px desktop
   (bloco 3, pensado pra cabeçalho de seção da home) e (c) o `.mt-4`
   nativo (24px !important) do .container do grid — (b) e (c) colapsam
   entre si (vence o maior). Agora: (b) vira 16px/24px só neste
   cabeçalho (escopo por .luo-serie-obras-head-wrap) e (c) é zerado só
   dentro de .luo-serie-grid, com !important porque .mt-4 também é. O
   vão final é o próprio margin-bottom do cabeçalho: 16px mobile, 24px
   desktop. A coluna do meio (desktop) continua 64px mais baixa que as
   outras por desenho, não por este vão. */
.luo-serie-obras-head-wrap .luo-sec-head {
  margin-bottom: 16px;
}

.luo-serie-grid > .container {
  margin-top: 0 !important;
  /* Alinhamento com o título "Obras" e o resto do conteúdo (2026-09-18,
     terceira rodada): o .container nativo tem max-width 1340px — 60px
     mais largo que o .luo-inset do título (1280px, bloco 3b). Em 1440px
     o conteúdo do grid começava em x=80 e o título em x=110 (e o grid
     passava 30px do lado direito). max-width e padding lateral agora
     seguem os tokens do .luo-inset: conteúdo a partir de x=110, mesma
     largura útil de 1220px. Abaixo de 1280px nada muda (o container já
     era a largura da tela com o mesmo gutter de 30px). */
  max-width: var(--luo-container);
  padding-left: var(--luo-gutter);
  padding-right: var(--luo-gutter);
}

@media (min-width: 1024px) {
  .luo-serie-obras-head-wrap .luo-sec-head {
    margin-bottom: 24px;
  }
}

/* ------------------------------------------------------------
   9. COLEÇÕES — MOSAICO (seção 2 da home)
   snipplets/luoliari/home-colecoes.tpl. Loop sobre `categories`
   (categorias raiz).

   Padding lateral e vertical vêm de .luo-section no wrapper (bloco
   3b) — não fica mais nada aqui.

   Grid uniforme, 2 colunas / N linhas (redesenhado 2026-09-18) — TODO
   card do mesmo tamanho, mesma proporção, sem card grande. Antes era
   1 card grande (.is-big) + resto num grid fixo de 3 colunas × 2
   linhas (wireframe v5) — quebrava com número PAR de coleções:
   testado ao vivo com a 6ª ("Amazônia"), o 6º card sobrava sozinho
   numa linha nova, órfão, sem preencher a grade (2 colunas vazias ao
   lado dele). Uniforme cresce pra qualquer N sem nunca sobrar espaço
   — 768-1023px (tablet) e ≥1024px (desktop) caem na MESMA regra base
   (não tem mais um breakpoint próprio de desktop só pra isso); < 768
   continua rail horizontal (bloco 9b), intocado.

   Padding-top: decisão revista em 2026-09-26. Uma rodada anterior
   zerava o padding-top daqui pra caber mais do 1º card na primeira
   dobra (critério antigo, "~120px do card visível"). Pedido explícito
   do cliente nesta rodada substitui esse critério: o vão entre o Hero
   e "Coleções" tem que usar o MESMO token de --luo-section-gap das
   demais seções (herdado normalmente de .luo-section, bloco 3b — por
   isso não sobra nenhuma declaração própria aqui). Não reintroduzir o
   padding-top:0 sem confirmar de novo com o cliente — as duas
   instruções são mutuamente exclusivas (zerar x manter o token).
   ------------------------------------------------------------ */

.luo-colecoes-mosaic {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

.luo-colecoes-card {
  position: relative;
  display: block;
  text-decoration: none;
  color: inherit;
}

.luo-colecoes-image {
  position: relative;
  aspect-ratio: 4 / 3.4;
  overflow: hidden;
}

.luo-colecoes-photo {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* font-size/font-weight/text-transform/color vêm do nível "nome de
   entidade" compartilhado (bloco 3, perto de .luo-label) — aqui só o
   que é específico deste card. */
.luo-colecoes-name {
  margin: 14px 0 0;
}

/* ------------------------------------------------------------
   9b. COMPONENTE — FAIXA ARRASTÁVEL (.luo-rail), só < 768px
   Extraído da 1ª versão (só Coleções) pra virar genérico — Best
   Sellers (bloco 16b) usa o mesmo componente agora. CSS puro, sem
   JS/setas/bolinhas, pedido explícito nos dois casos.

   API do componente: `.luo-rail` no container (vira faixa) +
   `--luo-rail-item` (largura de cada item, em % — decidida por quem
   usa, não pelo componente) declarada na instância. `.luo-rail__item`
   existe como classe pública explícita pra quando o próprio card é
   nosso (ex.: .luo-colecoes-card, abaixo) — mas o seletor `.luo-rail
   > *` também cobre o item sem exigir a classe, necessário pro Best
   Sellers: o card ali vem de snipplets/grid/item.tpl, componente
   nativo compartilhado por TODA listagem do site, sem como (nem
   motivo) adicionar uma classe só nossa nele.

   Não sangra a viewport: fica DENTRO do container já centralizado
   (.luo-section no wrapper, bloco 3b) — como o container já ocupa a
   viewport inteira abaixo de 1280px (só o padding lateral separa
   conteúdo de borda), o primeiro/último item já nascem alinhados
   com a margem do site sem precisar de padding extra aqui.
   ------------------------------------------------------------ */
@media (max-width: 767px) {
  .luo-rail {
    display: flex;
    flex-wrap: nowrap;
    gap: 12px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    touch-action: pan-x;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }

  .luo-rail::-webkit-scrollbar {
    display: none;
  }

  .luo-rail > *,
  .luo-rail__item {
    flex: 0 0 var(--luo-rail-item, 80%);
    /* max-width:none precisa vir junto — achado ao vivo no Best
       Sellers: .col-6 nativo (snipplets/grid/item.tpl) define
       flex-basis E max-width como par (50%/50%), então sobrescrever
       só o flex-basis (acima) não bastava — o max-width nativo
       continuava clampando o item em 50%, ignorando o
       --luo-rail-item:70% da instância. Sem esse conflito em
       Coleções (o <a> não tem max-width nativo pra começo de
       conversa), mas inofensivo aplicar nos dois. */
    max-width: none;
    scroll-snap-align: start;
  }

  /* Coleções: --luo-rail-item: 82% (mesmo valor de sempre) — todo
     card na mesma proporção (4/5 aqui, mais alta que o 4/3.4 da
     regra base), próximo aparece cortado, sinalizando que dá pra
     arrastar. Rail intocado nesta rodada (pedido explícito). */
  .luo-colecoes-mosaic {
    --luo-rail-item: 82%;
  }

  .luo-colecoes-image {
    aspect-ratio: 4 / 5;
  }
}

@media (min-width: 1024px) {
  .luo-colecoes-mosaic {
    gap: 20px;
  }
}

/* Só desktop (pedido veio na lista "Desktop:" da rodada do carrossel;
   mobile tem que continuar EXATAMENTE como estava — sem botão novo). */
.luo-colecoes-cta {
  display: none;
}

@media (min-width: 1024px) {
  .luo-colecoes-cta {
    display: flex;
    justify-content: flex-start;
    margin-top: 32px;
  }
}

/* ------------------------------------------------------------
   9c. COLEÇÕES — CARROSSEL DESKTOP (≥1280px, 2026-09-27)

   As coleções não param de crescer — o grid empilhado de 2 colunas
   ficava comprido demais no desktop. Só entra em cena com >3
   coleções visíveis (`is_carousel`, home-colecoes.tpl); com 3 ou
   menos o grid estático da regra base (bloco 9) já resolve sem
   sobrar espaço, então nada aqui se aplica.

   REAPROVEITA a técnica do .luo-rail mobile (bloco 9b) — flex +
   overflow-x:auto + scroll-snap — mas por um MODIFICADOR próprio
   (`.luo-colecoes-mosaic--carousel`, só nesta instância) em vez de
   estender `.luo-rail` puro pra desktop: `.luo-rail` também é usado
   pelo Best Sellers (bloco 16b), que precisa continuar 100%
   estático no desktop — mudar o `.luo-rail` base vazaria pra lá.

   LARGURA DO CARD — derivada, não estimada. Pedido do cliente: "4
   cards inteiros + parte de um 5º (~40% visível)" dentro da largura
   real da tela em QUALQUER breakpoint entre 1280 e 1920px (não só
   no container de 1280 — o rail vaza até a borda da viewport, feito
   por `margin-right: -var(--luo-hero-gutter)`, mesma variável que já
   resolve "distância do início do conteúdo até a borda real da
   tela" pro Hero — ver bloco 2/8a). Com a largura disponível
   `D = 100vw - var(--luo-hero-gutter)` e gap fixo de 20px (mesmo
   valor da regra base ≥1024px):

     4×card + 3×20px + 0.4×card = D
     4.4×card = D - 60px
     card = (D - 60px) / 4.4

   Conferido nos 3 breakpoints pedidos: 1280px → ~270px por card;
   1440px → ~289px (perto do "~400px" original, mas 400px+gaps não
   cabe em 4 cards dentro de nenhuma largura de tela até 1920px —
   contradição matemática resolvida priorizando a CONTAGEM, decisão
   do cliente); 1920px → ~343px. `--luo-colecoes-card-w` só existe
   dentro deste breakpoint — não é um token global.
   ------------------------------------------------------------ */
@media (min-width: 1280px) {
  .luo-colecoes-mosaic--carousel {
    --luo-colecoes-card-w: calc((100vw - var(--luo-hero-gutter) - 60px) / 4.4);
    display: flex;
    flex-wrap: nowrap;
    gap: 20px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    cursor: grab;
    /* Sangra só a ponta direita até a borda da viewport — a esquerda
       continua alinhada ao container (mesma linha do título
       "Coleções"), como qualquer outra seção. */
    margin-right: calc(-1 * var(--luo-hero-gutter));
    padding-bottom: 4px; /* respiro pro scroll-snap não cortar a sombra/borda de foco do card */
  }

  .luo-colecoes-mosaic--carousel::-webkit-scrollbar {
    display: none;
  }

  .luo-colecoes-mosaic--carousel.is-dragging {
    cursor: grabbing;
  }

  .luo-colecoes-mosaic--carousel > .luo-colecoes-card {
    flex: 0 0 var(--luo-colecoes-card-w);
    max-width: none;
    scroll-snap-align: start;
  }
}

/* Setas — par anterior/próximo no cabeçalho da seção (slot
   `head_extra` de section-head.tpl), alinhadas ao título. Escondidas
   fora do breakpoint do carrossel (mobile/tablet/desktop pequeno) —
   is_carousel já não as renderiza com ≤3 coleções, isto aqui cobre
   também o caso de a página ter carregado abaixo de 1280px. */
.luo-carousel-nav {
  display: none;
}

@media (min-width: 1280px) {
  .luo-carousel-nav {
    display: flex;
    align-items: center;
    gap: 4px;
  }
}

.luo-carousel-arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  margin: 0;
  background: none;
  border: none;
  font-size: 20px; /* .icon-inline (nativo) dimensiona o svg em 1em */
  color: var(--luo-muted);
  cursor: pointer;
  transition: color 0.2s ease, opacity 0.2s ease;
}

.luo-carousel-arrow svg {
  fill: currentColor;
}

.luo-carousel-arrow:hover:not(:disabled) {
  color: var(--luo-ink);
}

.luo-carousel-arrow:disabled {
  opacity: 0.35;
  cursor: default;
}

/* ------------------------------------------------------------
   10. BANNER DE CATEGORIA — recorte para imagem vertical
   snipplets/category-banner.tpl (nativo, classe .category-banner-image
   real — verificado, sem estilo próprio nos arquivos do tema; só
   Bootstrap .w-100 no <img>, então sem !important aqui). O Lu vai
   subir a mesma imagem 1600×2000 (retrato) usada no card da coleção
   pra esse banner — sem altura fixa, a imagem inteira renderiza no
   topo da página de categoria. Corte por cima com object-fit: cover
   em vez de esticar/deformar.
   ------------------------------------------------------------ */

.category-banner-image {
  width: 100%;
  height: 280px;
  object-fit: cover;
  display: block;
}

@media (min-width: 1024px) {
  .category-banner-image {
    height: 420px;
  }
}

/* ------------------------------------------------------------
   11. SOBRE — seção da home (snipplets/luoliari/home-sobre.tpl)
   Imagem empilhada acima do texto no mobile, grid 5fr/7fr no
   desktop (v4 mobile e v5 desktop concordam nesse layout — não
   mudou entre versões, ao contrário do mosaico de coleções).

   A foto é ESTÁTICA (2026-09-19): o efeito de escala no scroll
   (scale(0.92) → 1, IntersectionObserver em luoliari-home-N.js) foi
   removido na origem — CSS, JS e atributo data-sobre-scale do .tpl.
   Nenhuma outra seção usava o mesmo mecanismo.

   Padding lateral e vertical vêm de .luo-section no wrapper (bloco
   3b) — não fica mais nada aqui.
   ------------------------------------------------------------ */

.luo-sobre-grid {
  display: grid;
  gap: 32px;
}

.luo-sobre-image {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: var(--luo-radius-img);
}

/* text-transform:uppercase — chegou a virar `none` por um tempo (ver
   comentário em home-sobre.tpl), na suposição de que a caixa alta em
   teste local vinha só da Lemon Milk real instalada no navegador de
   QA. Suposição descartada: caixa alta é regra fixa de marca aqui. */
.luo-sobre-quote {
  font-family: var(--heading-font);
  font-weight: var(--title-font-weight);
  color: var(--luo-ink);
  font-size: 17px;
  line-height: 1.5;
  margin: 12px 0 14px;
  text-transform: uppercase;
}

.luo-sobre-lead {
  font-size: var(--luo-body-size);
  line-height: 1.8;
  color: var(--luo-body);
  margin: 0 0 14px;
}

/* Botão — classe .luo-btn--dark (bloco 30), aplicada direto no .tpl.
   Nada específico de "Sobre" a declarar aqui além do texto/markup. */

@media (min-width: 1024px) {
  .luo-sobre-grid {
    grid-template-columns: 5fr 7fr;
    gap: 96px;
    align-items: center;
  }

  .luo-sobre-quote {
    font-size: 27px;
    line-height: 1.45;
    margin: 18px 0 22px;
  }

  .luo-sobre-lead {
    line-height: 1.9;
    max-width: 560px;
    margin-bottom: 22px;
  }
}

/* ------------------------------------------------------------
   12. SOU ARQUITETO — seção da home
   (snipplets/luoliari/home-arquiteto.tpl). Borda superior/inferior
   full-bleed no <section> externo gerado por home-section-switch.tpl
   (.luo-arquiteto-section) — o wrapper .luo-arquiteto dentro dela só
   cuida do container/gutter via .luo-section, nunca da borda.

   DOM = ordem mobile (imagem, depois texto). No desktop, "order" no
   grid inverte a leitura sem duplicar HTML — mesmo recurso do bloco
   6 (hero).
   ------------------------------------------------------------ */

.luo-arquiteto-section {
  border-top: 1px solid var(--luo-line);
  border-bottom: 1px solid var(--luo-line);
}

.luo-arquiteto-grid {
  display: grid;
  gap: 24px;
}

.luo-arquiteto-image {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: var(--luo-radius-img);
}

/* Causa raiz do "sentence case" reportado: faltava font-family aqui
   (era <p>, não herdava --heading-font da regra global de h1-h6 —
   ver bloco 7 pra mais contexto sobre o mesmo bug). text-transform
   é o que garante caixa alta pra qualquer visitante de verdade —
   depender só da fonte carregar seria arriscado (nem toda fonte
   substituta tem esse comportamento). */
.luo-arquiteto-title {
  font-family: var(--heading-font);
  font-size: 21px;
  font-weight: var(--title-font-weight);
  text-transform: uppercase;
  color: var(--luo-ink);
  margin: 10px 0;
}

.luo-arquiteto-lead {
  font-size: var(--luo-body-size);
  line-height: 1.8;
  color: var(--luo-body);
  margin: 0 0 18px;
}

/* Botão — classe .luo-btn--dark (bloco 30), aplicada direto no .tpl.
   Era <span cursor:default> (placeholder inerte); virou <a href="#">
   real — ver .docs/estado-atual.md, pendência de destino. */

@media (min-width: 1024px) {
  .luo-arquiteto-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 80px;
    align-items: center;
  }

  /* Texto visualmente primeiro (esquerda) mesmo vindo depois da
     imagem no DOM — ver comentário no .tpl */
  .luo-arquiteto-text {
    order: -1;
  }

  .luo-arquiteto-title {
    font-size: 31px;
    margin: 14px 0 16px;
  }

  .luo-arquiteto-lead {
    line-height: 1.85;
    max-width: 480px;
    margin-bottom: 26px;
  }
}

/* ------------------------------------------------------------
   13. AMBIENTAÇÃO — seção da home
   (snipplets/luoliari/home-ambientacao.tpl). O wrapper é
   .luo-section (respiro vertical padrão em relação às seções
   vizinhas); só a MÍDIA sangra a viewport inteira, com --luo-bleed-
   -gutter garantindo que a legenda alinhe na mesma coluna das
   outras seções. A legenda fica ancorada num canto (ver comentário
   no .tpl sobre enquadramento).

   2026-09-18 (terceira rodada, pedido explícito): texto (eyebrow e
   título) em BRANCO + véu gradiente só no terço inferior da foto, o
   mesmo tratamento do Hero (bloco 6) — antes era texto escuro sem
   véu nenhum e o eyebrow (cinza) sumia sobre a parede clara. Ver
   componente do bloco 3d pro detalhe do gradiente e o aviso de contraste.
   ------------------------------------------------------------ */

.luo-ambientacao-media {
  position: relative;
  width: 100vw;
  left: 50%;
  margin-left: -50vw;
  height: 340px;
  overflow: hidden;
}

@media (min-width: 1024px) {
  .luo-ambientacao-media {
    height: 560px;
  }
}

.luo-ambientacao-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Véu — componente único do bloco 3d (terço inferior, preto 0% → 45%
   na base, padrão do componente; dentro do bloco, cortado pelo radius
   do desktop). Aviso de contraste e critério pras fotos do cliente
   (legenda no canto inferior esquerdo precisa de área escura ou vazia)
   estão lá. */

/* left/right seguem a MESMA fórmula do inset de conteúdo de
   .luo-section (bloco 3b: max-width 1280 centralizado + padding
   --luo-gutter) — não --luo-bleed-gutter (bloco 2): aquele token tem
   piso de 20px pensado pro hero/full-bleed, que já não bate com o
   piso real de .luo-section (0, o padding cobre sozinho abaixo de
   1280px). Bug encontrado: com --luo-bleed-gutter, o texto ficava
   10-30px mais à esquerda que "A obra"/"Coleções" (20px fixo no
   mobile contra os 30px de --luo-gutter; 80px no desktop 1440px
   contra os 110px reais = (100vw-1280)/2 + 30). Essa media (a
   mídia já sangra 100vw, ver acima) fica como referência de
   viewport, então left/right calculados a partir dela batem
   com onde o CONTAINER de 1280px realmente começa. */
.luo-ambientacao-cap {
  position: absolute;
  left: calc(max(0px, (100vw - var(--luo-container)) / 2) + var(--luo-gutter));
  right: calc(max(0px, (100vw - var(--luo-container)) / 2) + var(--luo-gutter));
  bottom: 28px;
  z-index: 2;
}

/* .luo-label nativo é --luo-muted (cinza) — sobre a foto vira branco,
   como o eyebrow do Hero (bloco 6). */
.luo-ambientacao-cap .luo-label {
  color: #FFFFFF;
}

/* font-family explícito — mesmo bug do bloco 7/12 (<p>, não herdava
   --heading-font). */
.luo-ambientacao-title {
  font-family: var(--heading-font);
  font-size: 16px;
  font-weight: var(--title-font-weight);
  line-height: 1.35;
  color: #FFFFFF;
  margin: 8px 0 10px;
}

/* Botão — classe .luo-btn--light (bloco 30), aplicada direto no
   .tpl. Era <span> inerte; virou <a href="#"> real — ver
   .docs/estado-atual.md, pendência de destino ("Como escolher o
   tamanho"). Fundo claro de propósito: repousa sobre foto/legenda,
   precisa continuar visível mesmo em cima de imagem clara. */

/* Desktop — REVERTIDO EM 2026-09-27 pro full-bleed (pedido explícito:
   "no desktop a imagem vai de borda a borda da viewport"). Entre
   2026-09-17 e esta rodada o bloco tinha virado contido (mesma largura
   do conteúdo das outras seções, com --luo-radius-img) — ver histórico
   abaixo, mantido porque documenta a fórmula de altura por
   aspect-ratio, hoje substituída.

   Não cancelamos mais width/left/margin-left aqui: a media HERDA a
   sangria da regra base (mobile-first, topo deste bloco —
   width:100vw; left:50%; margin-left:-50vw, mesma técnica do Hero,
   bloco 6) também no desktop. Nenhum border-radius é declarado —
   banner de largura total nunca leva arredondamento (regra do
   projeto, CLAUDE.md §4); o véu (::after, bloco 3d) usa
   `border-radius:inherit`, então já acompanha sozinho.

   Altura — CRITÉRIO EXPLÍCITO: não pode mudar (medido ao vivo antes
   desta rodada: 533,75px em 1440px, não os 560px que o comentário
   antigo (abaixo) previa — o container é max-width:1280 em
   border-box, então o conteúdo real é 1280-2×30=1220px, não 1280;
   1220×7/16=533,75). Como agora a media é 100vw (mais larga que o
   container), manter a MESMA altura exige desacoplar de novo do
   `aspect-ratio` da própria caixa — ele resolveria contra a largura
   NOVA (maior) e a altura cresceria junto. Em vez disso, a altura é
   calculada a partir da largura que o CONTEÚDO teria (a mesma conta
   de .luo-inset/.luo-section, bloco 3b: min(1280, 100vw) − 2×30),
   nunca da largura real da media. Resultado: idêntico ao valor antigo
   em qualquer largura ≥1024px (não só 1440), não um número preso a um
   viewport só.

   Legenda: a MESMA fórmula viewport-relative do mobile (acima, calc
   com 100vw) — que era só do mobile antes — agora também alinha o
   desktop na mesma coluna x das outras seções (ex.: "A obra"; medido
   ao vivo, ambos em x=110 a 1440px), porque a media voltou a sangrar.
   Trocado o `left:48px` fixo (pensado pro modo contido) por essa
   fórmula; bottom/max-width continuam os mesmos.

   Histórico (2026-09-17, pra contexto — não vale mais mas explica a
   conta de 560px caso reapareça em algum lugar): "era 560px fixo
   (bloco só existia sangrando, isolado da largura do container).
   Trocado por aspect-ratio 16/7 — dá exatamente 560px de altura
   quando o bloco está nos 1280px cheios (1280 × 7/16 = 560)". */
@media (min-width: 1024px) {
  .luo-ambientacao-media {
    height: calc((min(var(--luo-container), 100vw) - 2 * var(--luo-gutter)) * 7 / 16);
  }

  .luo-ambientacao-cap {
    left: calc(max(0px, (100vw - var(--luo-container)) / 2) + var(--luo-gutter));
    right: auto;
    bottom: clamp(56px, 5.5vw, 88px);
    max-width: 760px;
  }

  /* 2026-09-30: titulo 23px -> fluido 30-44px (37px a 1440, 44px a
     1920+), mais respiro embaixo (era 48px). */
  .luo-ambientacao-title {
    font-size: clamp(30px, 2.6vw, 44px);
    line-height: 1.2;
    margin: 14px 0 22px;
  }
}

/* ------------------------------------------------------------
   14. NEWSLETTER — seção da home
   (snipplets/home/home-newsletter.tpl — arquivo NATIVO, editado por
   exceção em 2026-09-18: ganhou o eyebrow opcional e o botão virou o
   componente luo-btn.tpl; o cadastro em si — form, honeypot,
   /winnie-pooh, mensagens de sucesso/erro — não mudou). Resto é CSS
   sobre as classes estáveis do nativo. !important só onde o nativo já
   usa (utilitárias .my-3/.p-0 do Bootstrap, que forçam margin com
   !important).

   Respiro vertical da faixa = --luo-section-gap (mesmo token das
   seções, bloco 2) — antes era 64/128px solto aqui.

   Campo com --luo-radius-input e botão com --luo-radius-btn (via
   .luo-btn--dark, bloco 30) — pedido explícito; o botão nativo era um
   <input type=submit> absoluto dentro do campo, com borda reta.
   ------------------------------------------------------------ */

[data-store="home-newsletter"] {
  background: var(--luo-surface);
}

.js-newsletter-home-container {
  max-width: var(--luo-container);
  padding-left: var(--luo-gutter);
  padding-right: var(--luo-gutter);
  margin-top: var(--luo-section-gap) !important;
  margin-bottom: var(--luo-section-gap) !important;
  margin-left: auto !important;
  margin-right: auto !important;
}

/* O nativo limita a 400px (.section-newsletter-home .newsletter) —
   com campo + botão lado a lado precisa de mais respiro. */
.js-newsletter-home-container .newsletter {
  max-width: 520px;
}

/* Eyebrow opcional (settings.luo_newsletter_eyebrow) — .luo-label
   nativo do projeto (bloco 3), só ajusta a distância pro título. */
.js-newsletter-home-container .luo-label {
  margin-bottom: 14px;
}

.js-home-newsletter-title {
  font-family: var(--heading-font);
  font-weight: var(--title-font-weight);
  font-size: 19px;
  color: var(--luo-ink);
  margin-bottom: 8px !important;
}

@media (min-width: 1024px) {
  .js-home-newsletter-title {
    font-size: 27px;
  }
}

.js-home-newsletter-text {
  font-family: var(--body-font);
  font-size: 13.5px;
  color: var(--luo-soft);
  margin-bottom: 24px !important;
}

/* Campo e botão lado a lado, sem o botão absoluto do nativo
   (.newsletter form .newsletter-btn) — a classe .newsletter-btn saiu
   do botão, então nenhuma regra nativa dela vale mais. */
.js-newsletter-home-container .input-append {
  display: flex;
  align-items: stretch;
  gap: 12px;
}

.js-newsletter-home-container .input-append .form-group {
  flex: 1 1 auto;
  min-width: 0;
}

.js-newsletter-home-container .form-control {
  border: 1px solid var(--luo-border);
  border-radius: var(--luo-radius-input);
  font-family: var(--body-font);
  font-size: 13px;
  padding: 14px 16px;
  height: 100%;
}

/* Nativo reserva 70px à direita do campo pro botão absoluto. */
.js-newsletter-home-container .newsletter .form-control {
  padding-right: 16px;
}

/* .luo-btn--dark (bloco 30) fixa height:44px; aqui a altura acompanha o
   campo ao lado (align-items:stretch do .input-append), com piso de
   44px pro botão em largura cheia no mobile. */
.js-newsletter-home-container .luo-newsletter-submit {
  flex: 0 0 auto;
  height: auto;
  min-height: 44px;
}

@media (max-width: 480px) {
  .js-newsletter-home-container .input-append {
    flex-direction: column;
  }
}

/* ------------------------------------------------------------
   15. SÉRIE EM DESTAQUE — seção da home
   (snipplets/luoliari/home-serie-destaque.tpl). Faixa editorial
   (imagem + texto) igual ao wireframe, mais o grid de obras da
   série — ver comentário no .tpl sobre a decisão de settings.txt
   (campo de texto com o handle, não seleção de categoria — o tema
   não tem esse tipo de campo) e sobre a reutilização de
   snipplets/grid/item.tpl pros cards.
   ------------------------------------------------------------ */

.luo-serie-destaque {
  background: var(--luo-surface);
}

.luo-serie-destaque-grid {
  display: grid;
  gap: 24px;
}

.luo-serie-destaque-image {
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: var(--luo-radius-img);
}

/* font-family explícito — mesmo bug do bloco 7/12/13 (<p>, não
   herdava --heading-font). */
.luo-serie-destaque-title {
  font-family: var(--heading-font);
  font-size: 24px;
  font-weight: var(--title-font-weight);
  color: var(--luo-ink);
  margin: 14px 0 12px;
}

.luo-serie-destaque-lead {
  font-size: var(--luo-body-size);
  line-height: 1.8;
  color: var(--luo-body);
  margin: 0 0 18px;
  max-width: 420px;
}

.luo-serie-destaque-link {
  display: inline-block;
  font-size: 13px;
  letter-spacing: 0.3px;
  color: var(--luo-ink);
}

.luo-serie-destaque-products {
  margin-top: 48px;
}

@media (min-width: 1024px) {
  .luo-serie-destaque-grid {
    grid-template-columns: 7fr 5fr;
    gap: 80px;
    align-items: center;
  }

  .luo-serie-destaque-title {
    font-size: 40px;
    margin: 16px 0 20px;
  }

  .luo-serie-destaque-lead {
    line-height: 1.9;
    margin-bottom: 24px;
  }

  .luo-serie-destaque-products {
    margin-top: 64px;
  }
}

/* ------------------------------------------------------------
   16. BEST SELLERS — seção da home
   (snipplets/luoliari/home-best-sellers.tpl). Máximo 3 produtos,
   `section_columns_desktop = 3` no .tpl gera `col-md-4` nativo
   (33.33%) — 3 lado a lado a partir do breakpoint "md" do Bootstrap
   (768px, fixo no framework, não é o nosso 1024). Mobile
   (`section_columns_mobile = 2`) fica 2+1. Cards continuam
   snipplets/grid/item.tpl dentro de .row.row-grid nativo — não
   escrevemos card nem grid aqui; a altura igual entre cards vem do
   bloco 17 (correção no componente compartilhado, não só aqui).
   Botão abaixo usa `store.products_url` (nativo) — ver .tpl.
   Escalonamento "coluna do meio descendo 72px" do wireframe v5
   continua fora por ora (não foi pedido nesta rodada; documentado
   em .docs/estado-atual.md como refinamento futuro em aberto).
   ------------------------------------------------------------ */

/* 16b. Abaixo de 768px: faixa arrastável (componente .luo-rail,
   bloco 9b) em vez do grid 2+1 nativo. .row/.row-grid continuam na
   classe (não removidos do .tpl) só por segurança de especificidade
   em outras regras nativas que os esperem — mas o -15px de margem
   deles e o padding lateral de cada .col-6/col-md-4 (var(--gutter))
   são zerados aqui, senão somam com o gap:12px do .luo-rail e abrem
   um vão duplo entre os cards. */
@media (max-width: 767px) {
  .luo-best-sellers-grid {
    --luo-rail-item: 70%;
    margin-left: 0;
    margin-right: 0;
  }

  .luo-best-sellers-grid > * {
    padding-left: 0;
    padding-right: 0;
  }
}

.luo-best-sellers-cta {
  display: flex;
  justify-content: center;
  margin-top: 40px;
}

/* Botão — classe .luo-btn--dark (bloco 30), aplicada direto no
   .tpl (já era <a href> real, só ganhou a classe). */

@media (min-width: 1024px) {
  .luo-best-sellers-cta {
    margin-top: 56px;
  }
}

/* ------------------------------------------------------------
   17. GRID DE PRODUTO NATIVO — altura consistente (SITE INTEIRO)
   Escopo: .item-image / .js-item-image-padding, classes do
   componente nativo `product-item-image` (snipplets/grid/item.tpl)
   — usado em TODA listagem de produto do tema: best sellers, série
   em destaque, grid de categoria (coleção e série), busca, produtos
   relacionados. Não é scoped a nenhuma seção nossa de propósito —
   pedido explícito pra ficar igual em qualquer lugar que reaproveite
   esse card.

   CAUSA RAIZ (confirmada inspecionando o DOM ao vivo, não suposição):
   o componente nativo gera um <div class="js-item-image-padding"
   style="padding-bottom: 66.65%"> — uma porcentagem calculada por
   PRODUTO, a partir da proporção real de CADA imagem (o próprio
   comentário do tema em style-critical.scss confirma isso: "the
   image container should have a padding-bottom inline with image
   height/width * 100"). É por isso que os cards saem com alturas
   diferentes lado a lado — cada imagem dita a altura do próprio
   card. !important abaixo é necessário e não opcional: estamos
   batendo um valor inline (specificity mais alta que qualquer
   seletor de folha de estilo sem !important), não uma classe
   utilitária do Bootstrap.

   Proporção escolhida: 4:5 (retrato), já documentada em CLAUDE.md §5
   pro card de Best sellers — agora vale pra qualquer card de
   produto, não só ali.
   ------------------------------------------------------------ */

.js-item-image-padding {
  padding-bottom: 125% !important;
}

.item-image img {
  top: 0;
  width: 100%;
  height: 100%;
  max-height: none;
  object-fit: cover;
}

/* ------------------------------------------------------------
   18. SANFONA DA PÁGINA DE OBRA (snipplets/luo-obra-accordion.tpl)
   <details>/<summary> nativo, sem JS. O wrapper nativo do bloco de
   descrição (snipplets/product/product-description.tpl) é
   text-center no mobile — text-align: left aqui pra sanfona não
   herdar isso.
   ------------------------------------------------------------ */

.luo-acc {
  margin-top: 8px;
  text-align: left;
}
.luo-acc__item {
  border-top: 1px solid #E6E6E1;
}
.luo-acc__item:last-child {
  border-bottom: 1px solid #E6E6E1;
}
.luo-acc summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 22px 0;
  font-size: 16px;
  color: #4A4A46;
  font-weight: 400;
  transition: color .18s ease;
}
.luo-acc summary::-webkit-details-marker {
  display: none;
}
.luo-acc summary::after {
  content: "+";
  font-size: 18px;
  line-height: 1;
  transition: color .18s ease;
}
.luo-acc__item:not([open]) summary:hover {
  color: var(--luo-ink);
}
.luo-acc__item[open] summary {
  color: var(--luo-ink);
  font-weight: 600;
}
.luo-acc__item[open] summary::after {
  content: "−";
}
.luo-acc summary:focus-visible {
  outline: 1px solid var(--luo-ink);
  outline-offset: 4px;
}
.luo-acc__body {
  padding-bottom: 24px;
  color: #4A4A46;
  line-height: 1.7;
}
.luo-acc__body p {
  margin: 0 0 14px;
}
.luo-acc__body p:last-child {
  margin-bottom: 0;
}
.luo-acc__body--plain {
  white-space: pre-line;
}

/* ------------------------------------------------------------
   18b. TÍTULO DA PÁGINA DE PRODUTO (nome da obra)
   snipplets/product/product-form.tpl embeda snipplets/page-header.tpl
   com as classes nativas `js-product-name h4 h2-md` — h1 de verdade
   (page-header.tpl força a tag), mas o TAMANHO vem inteiro do token
   admin --h4/--h2 (style-tokens.tpl, settings.headings_size), no
   breakpoint nativo do Bootstrap (768px "-md", não os 1024px do
   projeto) — nenhuma regra nossa tocava nisso até agora. Reduzir
   junto do resto da escala (2026-09-18, ~20%/~10%) exigia OU mudar
   settings.headings_size no admin (afetaria todo heading nativo do
   tema, fora de escopo) OU sobrescrever aqui, escopado a
   #single-product (mesmo padrão já usado pra .js-price-display,
   CLAUDE.md §8) — feito assim, sem tocar no token nativo. Breakpoint
   próprio (1024px, não 768px) de propósito: alinhado ao resto do
   projeto, não ao framework nativo. */
#single-product .js-product-name {
  font-size: 18px;
}

@media (min-width: 1024px) {
  #single-product .js-product-name {
    font-size: 25px;
  }
}

/* ------------------------------------------------------------
   19. EYEBROW DOS GRUPOS DE VARIAÇÃO (página de produto)
   .form-label é classe nativa genérica — usada também em conta,
   frete, formulários de endereço etc (grep confirmou 12 templates).
   Por isso escopado a .js-product-variants-group, não .form-label
   sozinho, senão maiusculizava rótulo de todo formulário do site.
   Alvo: só o rótulo genérico (ACABAMENTO/MOLDURA/TAMANHO), nunca o
   valor selecionado — mostrar os dois é repetir a mesma informação
   (o pill selecionado, peso 600 no bloco 20, já indica a escolha).
   Nome da variação vive em <span class="js-insta-variation-title">,
   valor em <span class="js-insta-variation-label"> (ambos criados
   em product-variants.tpl) — é o valor que se esconde aqui.
   Fonte de sistema (Helvetica Neue/Arial), sem webfont nova — ver
   CLAUDE.md §4.
   ------------------------------------------------------------ */

.js-product-variants-group .form-label {
  text-transform: uppercase;
  font-family: 'Helvetica Neue', Arial, sans-serif;
  font-size: 12px;
  letter-spacing: 3px;
  color: #8A8A84;
  margin-bottom: 10px;
}
.js-product-variants-group .form-label .js-insta-variation-label {
  display: none;
}

/* ------------------------------------------------------------
   20. PILLS DE VARIAÇÃO — respiro, hover e selecionado
   Escopado a .js-product-variants-group pelo mesmo motivo do bloco
   19 — não mexer no .btn-variant fora da página de produto.

   O padding real do pill nativo mora no span interno
   (.btn-variant-content, margin: 4px), não no <a> (.btn-variant,
   padding: 0) — por isso o respiro é reconstruído no span, zerando
   min-width/min-height nativos dos dois níveis pra não competir com
   o padding novo. line-height: 10px do .btn-variant nativo também
   é neutralizado (normal), senão empurra a altura da linha.

   Hover é comportamento novo: o único hover nativo é opacity: 0.8
   herdado do .btn genérico (lava o texto todo). Aqui a borda escurece
   e a opacidade volta a 1 — só dentro do grupo de variação, o .btn
   genérico não é tocado.

   Transição nova: nativo é "all 0.4s ease" (herdado do .btn,
   declarado em style-colors.scss — não editado). Aqui só border-color,
   mais rápida (.18s), sem pegar outras propriedades.

   Selecionado: nativo já deixa a borda 100% opaca (mantido, não
   redeclarado aqui). font-weight: 600 é novo — 500 colapsa pro
   mesmo desenho do 400 no fallback de sistema (ver CLAUDE.md §4),
   e o nativo declara font-weight: normal no .btn-variant, então a
   maior especificidade de .selected resolve sem !important.

   ::after fantasma no span reserva a largura do texto em negrito
   (mesmo data-name do span real) pra escolher/hover não remontar a
   linha quando o peso muda — sem JS, só CSS.
   ------------------------------------------------------------ */

.js-product-variants-group .btn-variant-content {
  margin: 0;
  padding: 14px 20px;
  line-height: 1;
  min-width: 0;
  min-height: 0;
}
.js-product-variants-group .btn-variant {
  padding: 0;
  min-width: 0;
  min-height: 0;
  margin: 0 10px 10px 0;
  line-height: normal;
  transition: border-color .18s ease;
}
.js-product-variants-group .btn-variant:hover {
  border-color: var(--main-foreground);
  opacity: 1;
}
.js-product-variants-group .btn-variant.selected {
  font-weight: 600;
}
.js-product-variants-group .btn-variant-content::after {
  content: attr(data-name);
  display: block;
  height: 0;
  overflow: hidden;
  visibility: hidden;
  font-weight: 600;
}

/* ------------------------------------------------------------
   21. PREÇO DA PÁGINA DE PRODUTO
   .js-price-display e .js-max-installments-container são classes
   nativas compartilhadas com o card de grid (snipplets/grid/item.tpl
   usa as duas — confirmado antes de escrever isto). Escopado a
   #single-product (só existe no wrapper da página de produto,
   templates/product.tpl) pra não vazar pra Best sellers, categoria,
   busca e relacionados, que têm sua própria hierarquia
   (.item-price, .item-installments).

   .mb-4/.mb-md-3/.mb-2 nativos são !important (utilitárias
   Bootstrap-like, style-critical.scss) — !important aqui é a
   exceção já documentada (CLAUDE.md §8: "exceto contra as
   utilitárias do Morelia que já o usam"), não escolha estilística.

   Breakpoint 768px, não 1024px das seções luo_*: é o -md nativo do
   tema, o mesmo que já rege a troca do H1 (.h2-md) — preço e título
   trocam de tamanho no mesmo ponto.

   "Ver mais detalhes" (#btn-installments) não ganhou regra própria:
   é <a> inline, margin-top nele não teria efeito nenhum no layout.
   O respiro de ~16px vem de aumentar o margin-bottom do bloco de
   parcelamento que vem antes — mesmo resultado visual, sem tocar
   num elemento inline.
   ------------------------------------------------------------ */

/* Peso baixado de 700 pra 400 em 2026-09-18 (pedido do Victor): o
   preço em Bold ficava visualmente mais pesado que o nome da obra
   (H1 nativo, --title-font-weight: 400), invertendo a hierarquia.
   Não dá pra ir mais leve que 400 — é o peso mais leve hospedado
   (milliard-400.woff2, "Book"; Light/300 nunca foi preparado, ver
   CLAUDE.md §4) — mas 400 já resolve a inversão: nome (LUO Display
   400) continua lendo como o elemento principal, preço (LUO Text
   400) mais leve que antes, parcelamento (sem font-weight próprio,
   herda 400 do body) segue igual. */
#single-product .js-price-display {
  font-family: var(--body-font);
  font-size: 20px;
  font-weight: 400;
  line-height: 1.2;
  color: var(--luo-ink);
}
@media (min-width: 768px) {
  #single-product .js-price-display {
    font-size: 24px;
  }
}
#single-product .js-price-container {
  margin-bottom: 6px !important;
}
#single-product .js-max-installments-container {
  color: #4A4A46;
  margin-bottom: 16px !important;
}

/* ------------------------------------------------------------
   22. BREADCRUMB — remove o último item na página de produto
   snipplets/breadcrumbs.tpl é compartilhado com carrinho, busca,
   blog, conta e páginas estáticas. Escopado por template-product,
   classe nativa do <body> (layouts/layout.tpl:
   "template-{{ template }}") — não toca nenhuma outra página.
   Nome da obra já aparece no h1 logo abaixo; repetir no breadcrumb
   é ruído (decisão do cliente).
   :nth-last-child(-n+2) pega o crumb ativo E o separador logo antes
   dele — CSS não tem seletor de "irmão anterior", daí contar pelos
   dois últimos filhos em vez de mirar uma classe.
   ------------------------------------------------------------ */

body.template-product .breadcrumbs > *:nth-last-child(-n+2) {
  display: none;
}

/* ------------------------------------------------------------
   23. BOTÃO SECUNDÁRIO E LINKS DE APOIO (WhatsApp)
   CORREÇÃO: a versão anterior aplicava margin: 0 -15px nos wrappers
   pra "imitar" o truque do .row nativo, mas sem devolver o padding
   15px que a .col aplica por dentro — resultado: os dois wrappers
   ficavam 15px PRA FORA do box de conteúdo real (o botão estourava
   a linha). O conserto certo é o oposto: não usar o truque nenhum.
   .luo-secondary-actions/.luo-support-links são filhos diretos do
   <form>, sem margin nem padding lateral — herdam exatamente o
   mesmo box de conteúdo que o .row/.col já respeitam por padrão
   (confirmado: .js-product-quantity-container tem padding-left:
   15px nativo, então o conteúdo da coluna começa 15px pra dentro
   da própria coluna — é esse box que os wrappers têm que casar,
   não a borda externa da coluna).

   .luo-btn-secondary: altura 44px fixa (não padding+line-height
   como o nativo) porque a borda somaria à altura sem isso — box-
   sizing: border-box só evita crescimento de caixa quando a altura
   É declarada. Não reaproveitei .btn/.btn-big pra não herdar cor/
   estado do botão primário sem querer.
   Hover: borda sempre 1px, NUNCA muda de espessura (engrossar
   borda no hover força reflow e o botão pula) — só a cor troca,
   do token nativo var(--main-foreground-opacity-30) (mesmo repouso
   dos pills, bloco 20) pra var(--luo-ink), com transition em
   border-color, não em border-width.

   Links de apoio: os dois <a> ficam lado a lado no desktop (flex-
   wrap, mesma linha), empilhados no mobile. O <details> do cupom
   entra no mesmo fluxo flex — quando abre, só a própria célula
   cresce, sem empurrar os outros dois de lugar.
   ------------------------------------------------------------ */

/* .row que envolve quantidade+Comprar tem mb-4 nativo (24px
   !important) — margem de blocos adjacentes colapsa pelo MAIOR
   valor, então um margin-top de 16px aqui sozinho virava 24px na
   prática (o do .row vencendo o colapso). Neutralizo só esse .row
   (via :has, mira só o que contém o botão de compra, não qualquer
   .row da página) e a distância vira exatamente os 16px daqui. */
#single-product .row:has(.js-buy-button-container) {
  margin-bottom: 0 !important;
}
.luo-secondary-actions {
  margin-top: 16px;
}
.luo-btn-secondary {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 44px;
  box-sizing: border-box;
  padding: 0 13px;
  font-size: 13px;
  font-weight: 400;
  text-align: center;
  text-decoration: none;
  background: #FFFFFF;
  color: var(--luo-ink);
  border: 1px solid var(--main-foreground-opacity-30);
  border-radius: 0;
  cursor: pointer;
  transition: border-color .2s ease;
}
.luo-btn-secondary:hover {
  border-color: var(--luo-ink);
}

.luo-support-links {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 16px;
  margin-bottom: 32px;
}
@media (min-width: 768px) {
  .luo-support-links {
    flex-direction: row;
    flex-wrap: wrap;
    column-gap: 24px;
    row-gap: 8px;
  }
}
.luo-support-link,
.luo-support-coupon summary {
  font-size: 13px;
  color: #4A4A46;
  text-decoration: underline;
  cursor: pointer;
  transition: color .18s ease;
}
.luo-support-link:hover,
.luo-support-coupon summary:hover {
  color: var(--luo-ink);
}
.luo-support-coupon summary {
  list-style: none;
}
.luo-support-coupon summary::-webkit-details-marker {
  display: none;
}
.luo-support-coupon__body {
  font-size: 13px;
  color: #4A4A46;
  margin-top: 6px;
  padding-left: 4px;
}

/* ------------------------------------------------------------
   24. RESPIRO DO SHARE NO MOBILE (Tarefa 14)
   O bloco de compartilhamento tem dois wrappers genéricos
   (.text-center, sem classe própria) — um em templates/product.tpl
   (mobile, d-md-none, sem margem) e outro em product-image.tpl
   (desktop, d-none d-md-block mt-4, já com respiro). Miro o primeiro
   ícone (sempre o WhatsApp, único com d-inline-block d-md-none) em
   vez do wrapper, porque .text-center sozinho se repete em outros
   pontos do tema. Breakpoint 767px = o mesmo -md nativo que decide
   qual dos dois wrappers aparece.
   Ícone de WhatsApp aqui é do bloco nativo de compartilhamento
   (snipplets/social/social-share.tpl) — não tem relação com o
   recurso "Botão de WhatsApp" de Configurações > Comunicação.
   ------------------------------------------------------------ */

@media (max-width: 767px) {
  body.template-product .social-share-button:first-child {
    margin-top: 32px;
  }
}

/* ------------------------------------------------------------
   25. RAIO — BOTÕES E CAMPOS
   --luo-radius-btn (cápsula) só nos dois CTAs de ação (Comprar,
   Personalizar meu quadro). --luo-radius-input (8px) nos pills de
   variação, campo de CEP e selects.
   Achado ao vivo: "Calcular" (.js-calculate-shipping) não tem borda
   nem fundo hoje — é texto sublinhado puro, sem caixa. Apliquei o
   token mesmo assim (inofensivo, sem efeito visível até que ganhe
   uma caixa própria) — não pulei por já estar na lista pedida.
   .form-select é o <select> nativo escondido atrás dos pills
   (bullet_variants ligado) — token aplicado pra quando aparecer
   visível em outro contexto (ex. sem bullet_variants).
   ------------------------------------------------------------ */

#single-product .btn-add-to-cart,
.luo-btn-secondary {
  border-radius: var(--luo-radius-btn);
}

/* Placeholder "Incluindo/Agregando" (snipplets/placeholders/
   button-placeholder.tpl) — substitui o botão real durante o
   submit. Não tem classe .btn-add-to-cart (só .js-addtocart-
   placeholder), por isso ficava quadrado nesse instante — mesmo
   arquivo é reaproveitado na compra rápida das listagens
   (grid/item.tpl), então escopado a #single-product de propósito,
   igual ao botão real, pra não mexer no que ainda não padronizamos
   fora da página de produto. Sem height aqui: já nasce 44px, das
   mesmas classes nativas btn/btn-big que o botão real usa —
   confirmado clicando de verdade, sem salto de layout na troca. */
#single-product .js-addtocart-placeholder {
  border-radius: var(--luo-radius-btn);
}

.js-product-variants-group .btn-variant {
  border-radius: var(--luo-radius-input);
}

.js-shipping-input,
.form-select,
.js-calculate-shipping {
  border-radius: var(--luo-radius-input);
}

/* Seletor de quantidade do carrinho (snipplets/cart-item-ajax.tpl,
   wrapper nativo .form-quantity — mesma classe usada na compra
   rápida das listagens, por isso escopado a .cart-item-quantity,
   que só existe aqui). overflow:hidden junto, não só o radius:
   os ícones +/- ficam colados na borda (sem padding próprio,
   conferido ao vivo — 1px de distância, exatamente a espessura da
   borda), então sem isso os cantos quadrados dos ícones vazariam
   por cima do arredondamento. */
.cart-item-quantity.form-quantity {
  border-radius: var(--luo-radius-input);
  overflow: hidden;
}

/* ------------------------------------------------------------
   25b. RAIO — PAINÉIS LATERAIS (busca, carrinho, menu mobile)
   --luo-radius-panel (16px), só nos dois cantos voltados pro
   conteúdo da página — o painel encosta nas bordas superior/inferior
   da viewport (sem gap ali, arredondar lá não faria sentido visual)
   e entra pela lateral oposta ao lado que ele "empurra" a página.
   IDs nativos de snipplets/header/header-modals.tpl (via
   snipplets/modal.tpl, id = modal_id): os três — #nav-search,
   #modal-cart e #nav-hamburger — abrem pela DIREITA
   (modal_position/-desktop: 'right') desde que o ícone de hambúrguer
   mudou de lado no header mobile (bloco 4d); os três arredondam os
   cantos da ESQUERDA. overflow:auto já é nativo nos três (scroll do
   painel inteiro, header+body+footer juntos, não um .modal-body
   interno) — não precisou de overflow:hidden extra pra clipar o
   filho de dentro (.modal-header tem fundo próprio e ficaria com
   canto quadrado vazando se o pai não recortasse; auto já recorta
   do mesmo jeito que hidden recortaria, só muda se mostra
   scrollbar). Confirmado ao vivo depois de aplicar. */
#nav-search,
#modal-cart,
#nav-hamburger {
  border-top-left-radius: var(--luo-radius-panel);
  border-bottom-left-radius: var(--luo-radius-panel);
}

/* Campo de busca DENTRO do modal — .search-input é nativo
   (component('search/search-form')), escopado a #nav-search pra não
   vazar pra outras instâncias do mesmo componente fora do modal. */
#nav-search .search-input {
  border-radius: var(--luo-radius-input);
}

/* ------------------------------------------------------------
   26. RAIO — IMAGENS (produto, vitrine, mosaico de coleções)
   --luo-radius-img nos três lugares confirmados na investigação.
   Radius sempre no WRAPPER com overflow: hidden, nunca só na <img>
   — os dois wrappers (.item-image, .luo-colecoes-image) já tinham
   overflow: hidden nativo/nosso antes desta mudança, conferido
   antes de escrever isto. Banners de largura total (.section-slider,
   .luo-ambientacao-media) ficam de fora de propósito — não levam
   arredondamento.
   ------------------------------------------------------------ */

.item-image,
.luo-colecoes-image,
.product-slider-image,
.luo-cs-card-image,
.luo-colecao-hero-image-wrap,
.luo-colecao-idx-thumb {
  border-radius: var(--luo-radius-img);
}

/* ------------------------------------------------------------
   27. ZOOM NO HOVER — MOSAICO DE COLEÇÕES (+ listagens e índice de
   séries, bloco 34/35, mesmo efeito reaproveitado)
   Não existe hover de zoom no card padrão de produto (.item-image) —
   confirmado antes de escrever isto: só existe transition: all .3s
   ease pronto, sem transform companheiro, e só ativa de fato num
   caso condicional (.item-image-slider, opção nativa desligada
   aqui). Sem precedente pra replicar, então: scale(1.03),
   transition: transform .5s ease — INVENTADO, avisado.
   .luo-colecoes-image já tem overflow: hidden (bloco 9), então o
   zoom nunca vaza do card. O nome da coleção (.luo-colecoes-name) é
   irmão do wrapper da imagem, não filho — escala nenhuma alcança o
   texto. Mesma lógica vale pros seletores novos abaixo (imagem
   sempre irmã do texto, wrapper sempre com overflow:hidden).
   ------------------------------------------------------------ */

.luo-colecoes-photo,
.luo-cs-card-photo,
.luo-colecao-idx-thumb-img {
  transition: transform .5s ease;
}

@media (prefers-reduced-motion: no-preference) {
  .luo-colecoes-card:hover .luo-colecoes-photo,
  .luo-cs-card:hover .luo-cs-card-photo,
  .luo-colecao-idx-row:hover .luo-colecao-idx-thumb-img {
    transform: scale(1.03);
  }
}

/* ------------------------------------------------------------
   28. TRANSIÇÃO ENTRE PÁGINAS — View Transitions nativo
   CSS puro, sem JS, sem biblioteca — degrada sozinho em navegador
   sem suporte (a página só navega normal, sem erro). O cross-fade
   é o comportamento padrão do próprio navegador pra
   navigation: auto — só travo a duração em 200ms/ease, sem slide
   nem escala (não declarados, então não acontecem).
   ------------------------------------------------------------ */

@view-transition {
  navigation: auto;
}

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.2s;
  animation-timing-function: ease;
}

@media (prefers-reduced-motion: reduce) {
  @view-transition {
    navigation: none;
  }
}

/* ------------------------------------------------------------
   29. CARRINHO — refino da tipografia dos totais (DOIS CONTEXTOS)
   O carrinho existe em dois lugares com o MESMO markup de totais:
   a página /comprar/ (cart_page: true, snipplets/cart-totals.tpl
   embrulhado em #cart-sticky-summary.cart-page-totals) e o
   #modal-cart lateral (cart_page omitido, sem esse wrapper — o
   componente cai no ramo `{% else %}` do próprio .tpl). Regra já
   escrita uma vez com prefixo `.cart-page-totals` só valia na
   página — o modal ficava no font-size/peso nativo (bug relatado,
   confirmado ao vivo: total saía 25px/400 no modal contra 16px/600
   na página).

   Corrigido tirando o prefixo: as classes abaixo (cart-subtotal-
   label/-price, cart-shipping-costs-label/-price, cart-total-
   label/-price, cart-installments) são geradas pelo componente
   nativo `cart-totals` — confirmado por grep que esse componente só
   é chamado numa linha do tema inteira (dentro do próprio
   cart-totals.tpl), que por sua vez só é incluído nesses dois
   contextos (templates/cart.tpl e snipplets/cart-panel.tpl). Não
   têm como vazar pra fora do carrinho.

   input[name="go_to_checkout"] e .cart-item-image já cobriam os dois
   contextos desde sempre (atributo e classe de <img>, nenhum dos
   dois dependia do wrapper) — mantidos como estavam.

   .luo-continue-shopping-link é classe nossa, adicionada direto no
   <a> de "Ver mais produtos" em cart-totals.tpl (arquivo nativo,
   editado por exceção — ver CLAUDE.md, rastreio de arquivos
   tocados): a classe nativa .btn-link sozinha não dá pra mirar sem
   escopo — aparece também no cupom (remover/aplicar) e em "Alterar
   CEP", que não fazem parte deste ajuste.
   ------------------------------------------------------------ */

.cart-subtotal-label,
.cart-subtotal-price,
.cart-shipping-costs-label,
.cart-shipping-costs-price {
  font-size: 14px;
  font-weight: 400;
  color: #4A4A46;
}

.cart-total-label,
.cart-total-price {
  font-size: 16px;
  font-weight: 600;
  color: var(--luo-ink);
}

.cart-installments {
  /* .font-small nativo (na mesma div) usa !important — exceção
     já documentada (CLAUDE.md §8), não escolha estilística. */
  font-size: 12px !important;
  color: #4A4A46;
  /* Respiro até o botão "Iniciar Compra" logo abaixo — sem isso os
     dois ficam colados (nenhum dos dois lados declarava margem). */
  margin-bottom: 24px;
}

.luo-continue-shopping-link {
  font-size: 13px;
}

input[name="go_to_checkout"] {
  border-radius: var(--luo-radius-btn);
}

.cart-item-image {
  border-radius: var(--luo-radius-img);
}

/* ------------------------------------------------------------
   30. SISTEMA DE BOTÕES DA HOME — duas variantes
   Escopo original: só as seções institucionais da home (Best sellers,
   Sobre, Ambientação, Sou Arquiteto — blocos 11, 12, 13, 16). Página
   de produto, carrinho, conta e rodapé continuam com os próprios
   botões (.luo-btn-secondary etc., bloco 23) — não tocados aqui,
   mesmo sendo visualmente parecidos. Contato SAIU dessa lista em
   2026-09-17 — pedido explícito reaproveitou .luo-btn--light
   (Instagram/WhatsApp) e .luo-btn--dark (Enviar mensagem) no redesenho
   da página, ver bloco 36.

   .luo-btn--dark  (Variant 1): repouso escuro, hover claro. Borda 1px
   em TODOS os estados, nunca some.
   .luo-btn--light (Variant 2): o oposto de cor (repouso claro, hover
   escuro) — mas SEM borda em nenhum estado (2026-09-18, pedido
   explícito — antes tinha borda igual ao --dark). Assimetria
   proposital: os 3 usos de hoje (Ambientação, Hero) ficam sobre foto,
   não precisam de borda pra se destacar do fundo. Contato saiu da
   variante light de vez nessa mesma rodada (trocado pra --dark, ver
   bloco 36) — não sobrou nenhum uso de --light sobre fundo branco
   pra justificar manter a borda como exceção.

   Borda nunca engrossa no hover (onde existe) — engordar borda força
   reflow, o botão "pula" de tamanho (mesma regra já usada em
   .luo-btn-secondary, CLAUDE.md §8). Só as cores fazem a transição.

   Largura no conteúdo (inline-flex), nunca plena — diferente de
   .luo-btn-secondary (produto), que é width:100% de propósito.
   Sem seta em nenhum dos quatro usos originais (pedido explícito) —
   quem levava seta no texto (Sobre, Ambientação) teve o caractere
   removido direto no .tpl. Contato (bloco 36) segue a mesma regra.
   ------------------------------------------------------------ */

.luo-btn--dark,
.luo-btn--light,
.luo-btn--contorno-preto,
.luo-btn--contorno-branco {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: auto;
  height: 44px;
  box-sizing: border-box;
  padding: 0 32px;
  border-radius: var(--luo-radius-btn);
  font-family: var(--body-font);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.3px;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .2s ease, color .2s ease, border-color .2s ease;
}

.luo-btn--dark {
  background: var(--luo-ink);
  color: #FFFFFF;
  border: 1px solid var(--luo-ink);
}

.luo-btn--dark:hover {
  background: #FFFFFF;
  color: var(--luo-ink);
  border-color: var(--luo-ink);
}

.luo-btn--light {
  background: #FFFFFF;
  color: var(--luo-ink);
  border: none;
}

.luo-btn--light:hover {
  background: var(--luo-ink);
  color: #FFFFFF;
}

/* Contorno (2026-09-28) — "Estilo 2" do carrossel de imagens (ver
   home-slider.tpl e settings luo_slider_botao_estilo/_cor): fundo
   transparente, borda 1px na cor do texto. NUNCA --luo-buy (regra do
   cliente, cor exclusiva do CTA de compra) — só --luo-ink ou branco,
   como as variantes sólidas. Hover inverte pro sólido correspondente
   (mesmo princípio de --dark/--light: troca de cor, nunca de borda). */
.luo-btn--contorno-preto {
  background: transparent;
  color: var(--luo-ink);
  border: 1px solid var(--luo-ink);
}

.luo-btn--contorno-preto:hover {
  background: var(--luo-ink);
  color: #FFFFFF;
}

.luo-btn--contorno-branco {
  background: transparent;
  color: #FFFFFF;
  border: 1px solid #FFFFFF;
}

.luo-btn--contorno-branco:hover {
  background: #FFFFFF;
  color: var(--luo-ink);
}

/* Contorno fora da caixa (outline-offset), sempre em --luo-ink —
   nos dois estados de repouso o offset cai sobre o fundo da PÁGINA
   (branco ou bege de seção), nunca sobre o próprio botão, então uma
   cor fixa funciona pras duas variantes sem precisar trocar com o
   hover. */
.luo-btn--dark:focus-visible,
.luo-btn--light:focus-visible,
.luo-btn--contorno-preto:focus-visible,
.luo-btn--contorno-branco:focus-visible {
  outline: 2px solid var(--luo-ink);
  outline-offset: 2px;
}

/* Oculta visualmente sem tirar do fluxo de acessibilidade/SEO — só
   uso hoje: o <h1> = page.name nas Páginas com layout próprio (Sobre,
   Trajetória), quando os H2 das seções já cumprem o papel visual e um
   H1 grande duplicaria informação. Técnica padrão (clip, não
   display:none — display:none também tira de leitor de tela). */
.luo-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ------------------------------------------------------------
   30b. BOTÃO COM ANIMAÇÃO DE LETRAS (snipplets/luoliari/luo-btn.tpl)
   2026-09-18 — referência Uiverse btn-53. Soma à classe
   .luo-btn--dark/.luo-btn--light (bloco 30) — NUNCA redeclara cor,
   borda, padding ou altura, só o movimento das duas camadas de
   texto por cima. `overflow:hidden` no botão é o que esconde as
   letras deslocadas em repouso (translateY ±150%, fora da caixa) —
   sem isso elas vazariam visualmente pra fora do botão.

   Camada back é position:absolute (sai do fluxo do flex do botão) —
   só a front (fluxo normal) decide a largura do conteúdo, então o
   botão não muda de tamanho entre os dois estados (mesma letra,
   mesma fonte, só peso diferente — 400 na front, 700 na back, único
   jeito de dar o "peso" do efeito sem ir a 900, que não existe
   hospedado — CLAUDE.md §4 Tipografia).

   `@media (hover: hover)` — único lugar em que a animação dispara.
   Em touch (hover:none), a regra inteira não existe pro navegador:
   estado de repouso é sempre o correto, nunca preso em transição.
   `prefers-reduced-motion: reduce` zera as transições (troca seca de
   estado, sem o `!important` de costume — aqui não tem nenhuma outra
   regra pra vencer, é só uma segunda condição de media query). */
.luo-btn-anim {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.luo-btn-face {
  white-space: nowrap;
  transition: transform .35s ease;
}

.luo-btn-face--front {
  display: block;
}

.luo-btn-face--back {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  transition: none;
}

.luo-btn-letter {
  display: inline-block;
  font-weight: 700;
  transition: transform .35s ease;
  transition-delay: calc(var(--i, 0) * 25ms);
}

/* px fixo, não % — achado testando ao vivo: translateY em % resolve
   contra a altura do PRÓPRIO elemento (a <span> da letra, só a
   altura da linha de texto, ~15px), não a do botão (44px, fixo em
   todos os breakpoints — bloco 30). 150% de ~15px é só ~22px, não o
   bastante pra sair da caixa de 44px com overflow:hidden — a letra
   ficava parcialmente visível em repouso. 48px (a altura do botão +
   folga) garante que a letra saia inteira da caixa nos dois sentidos. */
.luo-btn-letter--top {
  transform: translateY(-48px);
}

.luo-btn-letter--bottom {
  transform: translateY(48px);
}

@media (hover: hover) {
  .luo-btn-anim:hover .luo-btn-face--front {
    transform: translateY(48px);
  }

  .luo-btn-anim:hover .luo-btn-letter {
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .luo-btn-face--front,
  .luo-btn-letter {
    transition: none;
  }
}

/* ------------------------------------------------------------
   31. PÁGINA SOBRE (snipplets/luoliari/page-sobre.tpl)
   Isolada de templates/page.tpl por page.handle == 'sobre' — não
   afeta Sou Arquiteto nem qualquer outra Página nativa, que seguem o
   layout genérico (page-header + page.content num container
   simples), intocado. "Prêmios, exposições e publicações" tem o
   próprio layout também (bloco 32), pelo mesmo mecanismo.

   3 blocos agora (era 4 — trajetória solta + CTA "O acervo" viraram
   um banner só, bloco 3 abaixo). Cada um com .luo-section (container
   + gutter, bloco 3b) MAIS o modificador .luo-sobre-page-section
   logo abaixo, que zera o respiro vertical nativo de .luo-section e
   aplica o padrão pedido pra esta página — nunca editado o
   .luo-section global, só um modificador escopado.

   ESPAÇAMENTO — medido ao vivo ANTES desta mudança (3 blocos com
   .luo-section puro, 64px/128px mobile/desktop cada lado): o vão
   ENTRE blocos era padding-bottom de um + padding-top do outro =
   128px mobile / 256px desktop — exatamente o dobro do pedido. Novo
   padrão, só com padding-top por bloco (nunca os dois lados, senão
   dobra de novo): 48px mobile → 80px desktop, com clamp() pra
   transição fluida (calibrado igual ao --luo-body-size do bloco 2:
   fixo abaixo de ~390px, sobe até travar em 80 por volta de 1024px,
   nunca ultrapassa por causa do clamp mesmo passando do ponto exato).
   O último bloco (banner) herda esse mesmo padding-top E ganha
   padding-bottom igual — é o respiro "antes do rodapé" pedido, com o
   MESMO valor do espaçamento entre blocos (pedido explícito, os dois
   números eram iguais). Resultado: gap entre blocos = 48/80px exatos
   (não mais o dobro), gap até o rodapé = 48/80px.

   Eyebrow→título: 16px em TODOS os blocos (.luo-label escopado
   abaixo, sobrescrevendo só aqui os 10px nativos do bloco 3). Bio
   título→texto: 24px. Banner título→botão: 32px. Citação não tem
   "texto"/"botão" — só eyebrow→citação, mesma regra dos 16px.

   Mobile-first: a coluna do bloco 2 empilha por padrão (grid de 1
   coluna, sem media query) — a foto vem ANTES do texto no DOM, então
   "foto acima do texto" no mobile acontece pela ordem natural, sem
   precisar de "order" (diferente do hero/Sou Arquiteto, que invertem
   visualmente).
   ------------------------------------------------------------ */

.luo-sobre-page-section {
  /* Custom property, não valor solto: o banner (bloco 3 abaixo) reusa
     o MESMO clamp como margin (fora da caixa), não só padding (dentro
     dela) — precisa ser a mesma variável nos dois lugares, senão
     dessincroniza no próximo ajuste. */
  --luo-sobre-gap: clamp(48px, 28px + 5.05vw, 80px);
  padding-top: var(--luo-sobre-gap);
  padding-bottom: 0;
}

.luo-sobre-page-section--last {
  /* :last-of-type foi tentado primeiro e não bateu ao vivo (padding-
     bottom saía 0px) — o `div` da CTA não é garantidamente o último
     `div` do PAI pra essa pseudo-classe (conta por tag, não por
     classe); classe explícita resolve sem depender de quantos outros
     `div` existem no nível acima. */
  padding-bottom: var(--luo-sobre-gap);
}

.luo-sobre-page-section .luo-label {
  margin-bottom: 16px;
}

/* Bloco 1 — citação de abertura, centralizada. */
.luo-sobre-page-quote-inner {
  max-width: 720px;
  margin: 0 auto;
  text-align: center;
}

/* text-transform:uppercase — chegou a virar `none` por um tempo (ver
   comentário em page-sobre.tpl), na suposição de que a caixa alta em
   teste local vinha só da Lemon Milk real instalada no navegador de
   QA. Suposição descartada: caixa alta é regra fixa de marca aqui. */
.luo-sobre-page-quote-text {
  font-family: var(--heading-font);
  font-weight: var(--title-font-weight);
  color: var(--luo-ink);
  font-size: 19px;
  line-height: 1.4;
  margin: 0;
  text-transform: uppercase;
}

@media (min-width: 1024px) {
  .luo-sobre-page-quote-text {
    font-size: 29px;
    line-height: 1.45;
  }
}

/* Bloco 2 — foto + bio (rich text da Página nativa) */
.luo-sobre-page-bio-grid {
  display: grid;
  gap: 32px;
}

.luo-sobre-page-photo,
.luo-sobre-page-photo-wrap .luo-ph {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: var(--luo-radius-img);
}

.luo-sobre-page-bio-title {
  font-size: 21px;
  margin: 0 0 24px;
}

/* Rich text nativo (page.content) — sem classe própria no HTML que a
   Página gera (editor da Nuvemshop solta <p>/<h2>/<ul> puros), então
   miramos pelo container. line-height/cor no padrão de corpo do
   site; espaçamento entre parágrafos como qualquer bloco de texto
   corrido. */
.luo-sobre-page-bio-content {
  font-size: var(--luo-body-size);
  line-height: 1.8;
  color: var(--luo-body);
}

.luo-sobre-page-bio-content p {
  margin: 0 0 16px;
}

.luo-sobre-page-bio-content p:last-child {
  margin-bottom: 0;
}

@media (min-width: 1024px) {
  :root {
    /* Medido ao vivo em 1440px: o header nativo já é
       position:sticky (top:-50px — a barra de anúncios de 50px sai
       ao rolar); sobram 98px fixos no topo depois disso (era 115px
       antes do header perder ~20% de altura em 2026-09-28 — a régua
       reduziu exatamente os mesmos 17px que o header perdeu, 84→67px
       de min-height; conferido ao vivo, não só calculado). +32px de
       respiro pedido = 130px. Reavaliar se a altura do header nativo
       mudar de novo (texto da barra quebrando linha, opção nova no
       admin etc.) — sem forma de calcular isso em CSS puro, é medida
       fixa. */
    --luo-sobre-sticky-top: 130px;
  }

  .luo-sobre-page-bio-grid {
    grid-template-columns: 5fr 7fr;
    gap: 96px;
  }

  /* align-self (não align-items no container): só a coluna da foto
     sai do centralizado nativo — era o que criava o vão em branco no
     topo dela (coluna mais curta que a da bio, centralizada no meio
     da altura da linha do grid). */
  .luo-sobre-page-photo-wrap {
    position: sticky;
    top: var(--luo-sobre-sticky-top);
    align-self: start;
  }

  .luo-sobre-page-bio-title {
    font-size: 31px;
  }

  .luo-sobre-page-bio-content {
    line-height: 1.9;
    max-width: 560px;
  }
}

/* Bloco 3 — banner final, fundo bege (mesmo padrão de
   .luo-serie-destaque, bloco 15: fundo pintado no próprio elemento
   .luo-section — não sangra a viewport, fica dentro do container de
   1280px, igual ao único outro precedente de faixa colorida do
   site). Antes eram dois blocos (trajetória solta + CTA "O acervo");
   virou um só, apontando pra Página "premios-exposicoes-
   publicacoes" — ver .docs/estado-atual.md. */
.luo-sobre-page-cta {
  background: var(--luo-surface);
  /* Branco FORA da caixa bege — diferente de .luo-sobre-page-section
     puro (bio, citação): aqueles não têm cor de fundo própria, então
     o padding-top já PARECE branco (funde com a página). Aqui a
     `background` pinta exatamente até a borda do padding-box, então
     o padding continua sendo só o respiro ENTRE o topo/base da caixa
     bege e o texto de dentro — nunca aparece como espaço em branco.
     Pra ter branco de verdade acima/abaixo do banner, precisa de
     margin (fora da caixa, nunca pintado pelo background), mesmo
     valor do clamp — daí reusar --luo-sobre-gap em vez de outro
     número solto. */
  margin-top: var(--luo-sobre-gap);
  margin-bottom: var(--luo-sobre-gap);
}

.luo-sobre-page-cta-inner {
  max-width: 560px;
  margin: 0 auto;
  text-align: center;
}

/* Variante com foto (settings.luo_sobre_cta_foto — opcional,
   2026-09-18). position:relative + isolation cria um novo contexto
   de empilhamento só pra esta caixa, então z-index:1 na inner basta
   pra ficar acima da foto/véu, sem disputar com nada fora daqui.
   min-height dá peso de "banner" de verdade — sem ele a caixa só
   teria a altura do texto (padding + label/título/botão), a foto
   ficaria uma tira fina. Ainda menor que a Ambientação (16:7 em
   1220px ≈ 534px) e bem menor que o Hero (700px) — hierarquia
   proposital, é um CTA secundário, não uma seção-imagem. */
.luo-sobre-page-cta--photo {
  position: relative;
  background: none;
  border-radius: var(--luo-radius-img);
  overflow: hidden;
  isolation: isolate;
  min-height: 320px;
  display: flex;
  align-items: center;
}

.luo-sobre-page-cta-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* rgba(0,0,0,.55): não é garantia matemática de AA contra QUALQUER
   foto (uma foto muito clara/estourada exigiria véu bem mais forte,
   perto de .8, o que apagaria a foto) — na prática, cobre foto de
   arquitetura/ambiente comum com folga. text-shadow no texto (não
   conta pro cálculo formal de contraste, mas ajuda na prática real)
   é a segunda camada de segurança. Se o Lu escolher uma foto muito
   clara aqui, revisitar a opacidade do véu. */
.luo-sobre-page-cta-veil {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
}

.luo-sobre-page-cta--photo .luo-sobre-page-cta-inner {
  position: relative;
  z-index: 1;
  width: 100%;
}

.luo-sobre-page-cta--photo .luo-label,
.luo-sobre-page-cta--photo .luo-sobre-page-cta-title {
  color: #FFFFFF;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}

@media (min-width: 1024px) {
  .luo-sobre-page-cta--photo {
    min-height: 420px;
  }
}

/* Título reduzido, mas nao mais no nivel de "nome de entidade"
   (var(--font-base) ficou igual ao corpo do texto, sem contraste
   nenhum -- achado ao vivo). Continua bem menor que um H2 de secao,
   mas com peso de titulo de verdade. Calibrado com a MESMA logica
   do --luo-sobre-gap (bloco 31, inicio): pinos nos mesmos dois
   viewports de referencia (390px e 1024px) -- abaixo de 390 fica
   travado no minimo, acima de 1024px trava no maximo, fluido so no
   meio. Segue h2 semantico, so o tamanho visual muda; nao mexe na
   regra global de h1-h6. Reduzido em 2026-09-18 (~20%/~10%, mesma
   rodada do resto da escala): 18px em 390px, trava em 25px a partir
   de 1024px — ainda acima do piso do nome de entidade (15px). */
.luo-sobre-page-cta-title {
  font-size: clamp(18px, 13.7px + 1.1vw, 25px);
  margin: 0 0 32px;
}

/* ------------------------------------------------------------
   32. PÁGINA "PRÊMIOS, EXPOSIÇÕES E PUBLICAÇÕES" (trajetória)
   (snipplets/luoliari/page-trajetoria.tpl). Isolada por
   page.handle == 'premios-exposicoes-publicacoes', mesmo mecanismo
   da Sobre (bloco 31) — não afeta nenhuma outra Página nativa.

   Coluna central estreita (710px) em vez do container de 1280px
   padrão do site — texto corrido em lista, não fica bom esticado.
   Cada seção é 3 divs aninhadas (wrap > .luo-section > col): o wrap
   é quem sangra a viewport inteira pra levar o separador horizontal
   de largura total; .luo-section (dentro dele) fica com a mesma
   largura de sempre só pra herdar o respiro vertical padrão — nunca
   os dois no MESMO elemento aqui, ao contrário do resto do site,
   porque preciso que o fundo/borda do separador escape do container
   e o conteúdo, não.
   ------------------------------------------------------------ */

.luo-trajetoria-section-wrap {
  border-top: 1px solid var(--luo-line);
}

.luo-trajetoria-section-wrap--first {
  border-top: none;
}

.luo-trajetoria-col {
  max-width: 710px;
  margin: 0 auto;
}

.luo-trajetoria-section-title {
  font-size: 22px;
  margin: 0 0 32px;
}

@media (min-width: 1024px) {
  .luo-trajetoria-section-title {
    font-size: 29px;
    margin: 0 0 40px;
  }
}

/* Grupo de um ano — o eyebrow reaproveita .luo-label (caps, cinza,
   tracking positivo), só ganha o respiro de separação entre grupos
   aqui. Primeiro grupo da seção não precisa de respiro extra (o
   margin-bottom do H2 acima já resolve). */
.luo-trajetoria-year {
  margin-top: 32px;
}

.luo-trajetoria-year:first-of-type {
  margin-top: 0;
}

.luo-trajetoria-year-label {
  margin-bottom: 12px;
}

/* Item — linha divisória fina ACIMA de cada um (inclusive o
   primeiro do grupo, logo abaixo do eyebrow do ano — pedido
   explícito "linha acima de cada um", sem exceção pro primeiro).
   Mobile: empilha (coluna direita desce, alinhada à esquerda).
   Desktop: uma linha, coluna direita à direita. */
.luo-trajetoria-item {
  display: flex;
  flex-direction: column;
  gap: 4px;
  border-top: 1px solid var(--luo-line);
  padding: 14px 0;
}

.luo-trajetoria-item-left {
  font-size: 15px;
  line-height: 1.5;
  color: var(--luo-ink);
}

.luo-trajetoria-item-right {
  font-size: 13px;
  line-height: 1.5;
  color: var(--luo-muted);
  text-align: left;
}

@media (min-width: 1024px) {
  .luo-trajetoria-item {
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
    gap: 24px;
    padding: 16px 0;
  }

  .luo-trajetoria-item-left {
    font-size: 16px;
  }

  .luo-trajetoria-item-right {
    text-align: right;
    white-space: nowrap;
  }
}

/* Linha que não bate com título nem item — nunca some (regra do
   pedido), aparece como parágrafo comum no corpo padrão do site. */
.luo-trajetoria-stray {
  font-size: var(--luo-body-size);
  line-height: 1.8;
  color: var(--luo-body);
  margin: 0 0 16px;
}

/* ------------------------------------------------------------
   33. RODAPÉ (snipplets/luoliari/footer.tpl) — versão completa e
   ESCURA (2026-09-18). Fundo --luo-footer-bg, texto branco; repouso
   dos links/legendas por transparência do branco, hover em branco
   puro com o MESMO sublinhado do menu (bloco 4c: 1px, offset 6px,
   text-decoration-color de transparente pra cor do texto). Nada
   colorido — só branco sobre o quase-preto quente.

   4 colunas no desktop (marca + descrição / Institucional / Ajuda /
   Siga-Fale), empilhadas na MESMA ordem no mobile, sem sanfona (grid
   que vira 1 coluna, sem JS). Coluna sem dado não renderiza (o .tpl
   nem abre o <div>) e o grid fecha sozinho.

   .luo-inset (bloco 3b) dá container/gutter — sem respiro vertical
   próprio; o rodapé tem faixas internas (topo, barra final, powered)
   com respiros geridos aqui.

   footer { padding: 40px 0 } nativo (style-async.scss) e footer
   {color,background} nativos (style-colors.scss) valem pra qualquer
   <footer> — zerados/sobrescritos aqui, senão somavam 80px de padding
   e as cores do admin ("Pie de página > Colores") brigavam com o
   design.
   ------------------------------------------------------------ */

.luo-footer {
  background: var(--luo-footer-bg);
  color: var(--luo-footer-link);
  font-size: var(--luo-body-size);
  padding: 0;
}

.luo-footer-top {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1fr;
  gap: 40px;
  padding-top: 72px;
  padding-bottom: 56px;
}

/* Nome da marca — MESMO tracking da logo do header (--luo-ls-logo /
   --luo-ws-logo, bloco 2). nowrap: nunca quebra entre "LU" e "OLIARI". */
.luo-footer-logo {
  font-family: var(--heading-font);
  /* 500, mesmo critério do header — ver comentário lá */
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--luo-ls-logo);
  word-spacing: var(--luo-ws-logo);
  white-space: nowrap;
  /* Reduzido 10% (2026-09-26, pedido do cliente): 16px → 14,4px */
  font-size: 14.4px;
  color: var(--luo-footer-text);
  margin: 0 0 16px;
}

.luo-footer-desc {
  line-height: 1.75;
  color: var(--luo-footer-link);
  max-width: 44ch;
  margin: 0;
}

.luo-footer-col-title {
  display: block;
  font-family: var(--body-font);
  font-size: var(--luo-label);
  letter-spacing: var(--luo-ls-label);
  text-transform: uppercase;
  color: var(--luo-footer-text);
  margin-bottom: 18px;
}

.luo-footer-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.luo-footer-list li {
  margin-bottom: 10px;
}

.luo-footer-list a {
  color: var(--luo-footer-link);
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 6px;
  text-decoration-color: transparent;
  transition: color 0.2s, text-decoration-color 0.2s;
}

.luo-footer-list a:hover,
.luo-footer-list a:focus-visible {
  color: var(--luo-footer-text);
  text-decoration-color: var(--luo-footer-text);
}

.luo-footer-list a:focus-visible,
.luo-footer-powered a:focus-visible {
  outline: 2px solid var(--luo-footer-text);
  outline-offset: 3px;
}

/* Barra final — linha de 1px em cima; CNPJ/copyright à esquerda (menor
   e mais apagado), selo + bandeiras à direita. */
.luo-footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px 24px;
  border-top: 1px solid var(--luo-footer-line);
  padding: 24px 0;
  font-size: 12px;
  color: var(--luo-footer-muted);
}

.luo-footer-dot {
  margin: 0 6px;
}

.luo-footer-brandname {
  text-transform: uppercase;
}

.luo-footer-trust {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 24px;
}

.luo-footer-ssl {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}

.luo-footer-ssl .icon-inline {
  width: 14px;
  height: 14px;
  /* nativo: `footer svg { fill: var(--footer-foreground) }`
     (style-colors.scss) — currentColor acompanha o texto ao lado. */
  fill: currentColor;
}

/* Bandeiras de pagamento (component payment-shipping-logos, nativo)
   sobre fundo escuro: cada bandeira numa "pastilha" branca com
   --luo-radius-input e a logo em ESCALA DE CINZA (pedido antigo, "nada
   colorido") — o filtro fica na <img>, não no wrapper, pra a pastilha
   continuar branca; logo cinza sobre branco mantém o contraste e o
   desenho de cada bandeira (o invert em branco fundia os dois
   círculos da Mastercard num borrão). Tamanho vem da classe nativa
   .footer-payments-shipping-logos (img max-height 20px, margin 3px),
   incluída no wrapper do .tpl. */
.luo-footer-payments {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
}

.luo-footer-payments img {
  box-sizing: content-box;
  background: var(--luo-bg);
  padding: 3px 6px;
  border-radius: var(--luo-radius-input);
  filter: grayscale(1);
  border: 0;
}

/* "Powered by Nuvemshop" — link obrigatório da plataforma, intocado
   (markup vem de {{ new_powered_by_link }}); só a cor do SVG:
   .powered-by-logo svg { fill: var(--footer-foreground) } nativo
   (style-colors.scss) usa a cor de rodapé do admin, que não conhece
   este fundo. */
.luo-footer-powered {
  text-align: center;
  padding: 4px 0 28px;
  font-size: 11px;
  color: var(--luo-footer-muted);
}

.luo-footer .powered-by-logo svg {
  fill: var(--luo-footer-muted);
}

.luo-footer .powered-by-logo a:hover svg {
  fill: var(--luo-footer-text);
}

@media (max-width: 1023px) {
  .luo-footer-top {
    grid-template-columns: 1fr 1fr;
  }

  .luo-footer-brand {
    grid-column: 1 / -1;
  }
}

@media (max-width: 767px) {
  .luo-footer-top {
    grid-template-columns: 1fr;
    gap: 32px;
    padding-top: 56px;
    padding-bottom: 40px;
  }

  .luo-footer-bottom {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* ------------------------------------------------------------
   34. LISTAGENS "COLEÇÕES" E "SÉRIES" (Páginas nativas, handles
   "colecoes"/"series" — snipplets/luoliari/page-colecoes.tpl,
   page-series.tpl, card compartilhado em snipplets/luoliari/
   colecoes-series-card.tpl. Referência: .docs/wireframes/
   Colecoes.pdf — estrutura/proporção/espaçamento; cor, fonte e
   textos de exemplo do PDF ignorados, tokens do projeto valem.

   Grid vertical, NUNCA .luo-rail (bloco 9b): aquele componente é só
   pra faixa horizontal mobile da home — estas páginas rolam de cima
   a baixo em qualquer largura, sempre em grade (1 coluna mobile,
   2 desktop).

   Card reaproveita o desenho do mosaico da home (número no canto,
   imagem com --luo-radius-img, zoom no hover — blocos 26/27 já
   estendidos com os seletores novos) e o nível "nome de entidade"
   (.luo-colecoes-name, bloco 3) pro nome — só o que é exclusivo
   deste card (grid, número, meta, cta) mora aqui.
   ------------------------------------------------------------ */

.luo-cs-listagem-head {
  margin-bottom: 48px;
}

.luo-cs-listagem-title {
  font-size: 26px;
  margin: 10px 0 16px;
}

.luo-cs-listagem-intro {
  max-width: 640px;
  font-size: var(--luo-body-size);
  line-height: 1.7;
  color: var(--luo-body);
}

.luo-cs-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
}

.luo-cs-card {
  position: relative;
  display: block;
  text-decoration: none;
  color: inherit;
}

/* 4:3 — mesma proporção do hero e do wireframe desta listagem (a
   diferente do mosaico da home, que usa 4/3.4 e 4/5 pro card grande;
   aqui os cards são todos do mesmo tamanho, sem card "grande"). */
.luo-cs-card-image {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
}

.luo-cs-card-photo {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.luo-cs-card-name {
  margin: 16px 0 6px;
}

.luo-cs-card-meta {
  display: block;
  font-size: 13px;
  color: var(--luo-muted);
}

/* Sublinhado revelado no hover — mesmo truque do menu (bloco 4c):
   text-decoration-color parte transparente e anima pra --luo-ink,
   nunca a cor do texto (que já é --luo-ink desde o início, sem
   estado de repouso mais claro pedido pro link — só a home mosaic e
   o índice de série usam esse padrão soft→ink; aqui a spec só pediu
   "mesmo sublinhado do menu no hover", não o mesmo esquema de cor).
   <span>, não <a>: o card inteiro já é um link (colecoes-series-
   card.tpl) — um segundo <a> aninhado seria HTML inválido e
   duplicaria o link pro leitor de tela. */
.luo-cs-card-cta {
  display: inline-block;
  margin-top: 12px;
  font-family: var(--body-font);
  font-size: 13px;
  color: var(--luo-ink);
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  text-decoration-color: transparent;
  transition: text-decoration-color .2s;
}

.luo-cs-card:hover .luo-cs-card-cta {
  text-decoration-color: var(--luo-ink);
}

@media (min-width: 1024px) {
  .luo-cs-listagem-head {
    margin-bottom: 64px;
  }

  .luo-cs-listagem-title {
    font-size: 40px;
  }

  .luo-cs-grid {
    grid-template-columns: 1fr 1fr;
    gap: 40px 48px;
  }
}

/* ------------------------------------------------------------
   35. PÁGINA DA COLEÇÃO — hero + índice de séries
   templates/category.tpl, ramo `{% else %}` (is_serie == false) —
   troca o page-header/banner/descrição/filtro/grid nativos por
   snipplets/luoliari/category-colecao-header.tpl (hero, reaproveita
   quase toda classe do hero de série — .luo-serie-hero-*, bloco 8b —
   só a imagem tem wrapper próprio, ver comentário no .tpl) e
   snipplets/luoliari/category-colecao-series-index.tpl (linhas
   abaixo). Grid de produto e filtro NÃO aparecem mais nesta página —
   isolamento: página de série (bloco 8b/8c) continua com os dois,
   intocada.

   Índice em linhas, não cards — referência .docs/wireframes/
   colecao-v2-luoliari.html/-mobile.html, seção "Dentro da coleção".

   Imagem do hero no mobile: wireframe pede borda a borda, SEM radius
   (diferente do desktop, que pede radius — spec explícita, os dois
   breakpoints divergem de propósito aqui). .luo-colecao-hero-image-
   wrap herda radius do bloco 26 (lista compartilhada) — cancelado só
   abaixo de 1024px. Sangria: mesma fórmula do bloco 13 (Ambientação),
   width:100vw + margin negativa a partir do centro.
   ------------------------------------------------------------ */

.luo-colecao-hero-image-wrap {
  width: 100vw;
  left: 50%;
  margin-left: -50vw;
  position: relative;
  border-radius: 0;
}

@media (min-width: 1024px) {
  .luo-colecao-hero-image-wrap {
    width: auto;
    left: auto;
    margin-left: 0;
    border-radius: var(--luo-radius-img);
  }
}

.luo-colecao-idx-wrap {
  margin-top: 8px;
  /* Sem isso, a última seção da página de coleção (índice de séries)
     colava direto no rodapé — não herda padding-bottom de nenhum
     .luo-section (é só .luo-inset, alinhamento horizontal, ver
     comentário no .tpl). Mesmo token de --luo-section-gap usado entre
     as demais seções da home (2026-09-26). */
  padding-bottom: var(--luo-section-gap);
}

.luo-colecao-idx {
  border-top: 1px solid var(--luo-ink);
}

.luo-colecao-idx-row {
  display: grid;
  grid-template-columns: 32px 84px 1fr 20px;
  gap: 14px;
  align-items: center;
  padding: 18px 0;
  border-bottom: 1px solid var(--luo-line);
  text-decoration: none;
  color: inherit;
}

.luo-colecao-idx-num {
  font-family: var(--body-font);
  font-size: 11px;
  letter-spacing: var(--luo-ls-serie);
  color: var(--luo-muted);
}

.luo-colecao-idx-thumb {
  display: block;
  width: 84px;
  height: 66px;
  overflow: hidden;
}

.luo-colecao-idx-thumb-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.luo-colecao-idx-name-wrap {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.luo-colecao-idx-name {
  font-family: var(--heading-font);
  font-weight: 500;
  /* 14,4px = 18px − 20% (2026-09-18, segunda rodada); desktop 19,2px
     = 24px − 20%, no bloco de 1024px abaixo. "N obras" (.luo-colecao-
     idx-meta) não mudou. */
  font-size: 14.4px;
  color: var(--luo-body);
  transition: color .2s;
}

.luo-colecao-idx-meta {
  font-size: 11.5px;
  color: var(--luo-muted);
}

.luo-colecao-idx-meta--desktop {
  display: none;
}

.luo-colecao-idx-arrow {
  text-align: right;
  font-size: 16px;
  color: var(--luo-ink);
  transition: transform .2s;
}

@media (min-width: 1024px) {
  .luo-colecao-idx-row {
    grid-template-columns: 60px 120px 1fr auto 40px;
    gap: 32px;
    padding: 26px 0;
  }

  .luo-colecao-idx-num {
    font-size: 13px;
  }

  .luo-colecao-idx-thumb {
    width: 120px;
    height: 96px;
  }

  .luo-colecao-idx-name {
    font-size: 19.2px;
  }

  .luo-colecao-idx-meta--mobile {
    display: none;
  }

  .luo-colecao-idx-meta--desktop {
    display: block;
    font-size: 13px;
  }

  .luo-colecao-idx-row:hover .luo-colecao-idx-name {
    color: var(--luo-ink);
  }

  .luo-colecao-idx-row:hover .luo-colecao-idx-arrow {
    transform: translateX(4px);
  }
}

/* ------------------------------------------------------------
   36. PÁGINA DE CONTATO (templates/contact.tpl, ramo normal — o
   ramo de cancelamento de pedido, is_order_cancellation, é cópia
   intocada do nativo e não usa nada daqui). Referência: print do
   wireframe aprovado no chat (2026-09-17). Duas colunas — grid, sem
   CSS order: a ordem do DOM (contatos primeiro) já é a ordem visual
   certa nos dois breakpoints.
   ------------------------------------------------------------ */

.luo-contato-grid {
  display: grid;
  gap: 48px;
}

.luo-contato-title {
  font-size: clamp(1.4rem, 0.65rem + 4.5vw, 2.5rem);
  line-height: 1.15;
  margin: 0 0 16px;
}

.luo-contato-intro {
  max-width: 440px;
  font-size: var(--luo-body-size);
  line-height: 1.7;
  color: var(--luo-body);
  margin: 0 0 40px;
}

.luo-contato-blocks {
  border-top: 1px solid var(--luo-line);
}

.luo-contato-block {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 24px 0;
  border-bottom: 1px solid var(--luo-line);
}

.luo-contato-value {
  font-family: var(--heading-font);
  font-size: 20px;
  font-weight: var(--title-font-weight);
  color: var(--luo-ink);
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  text-decoration-color: transparent;
  transition: text-decoration-color .2s;
}

/* Endereço não é link (sem tel:/mailto: correspondente) — mesmo
   tamanho/peso dos outros dois pra manter a hierarquia visual do
   bloco, sem herdar o sublinhado (que só faz sentido em algo
   clicável). */
.luo-contato-value--text {
  text-decoration: none;
}

a.luo-contato-value:hover {
  text-decoration-color: var(--luo-ink);
}

.luo-contato-note {
  font-size: 12.5px;
  color: var(--luo-muted);
}

.luo-contato-social {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 32px;
}

/* Flat até 2026-09-18 (22px em qualquer largura) — ganhou split
   mobile/desktop nesta rodada de redução de escala (~20%/~10%),
   mesma lógica do resto do sistema; override do lado desktop mora
   no @media (min-width:1024px) já existente logo abaixo, junto do
   grid 7fr/5fr, em vez de abrir um novo bloco só pra isso. */
.luo-contato-form-title {
  font-size: 18px;
  margin: 0 0 8px;
}

.luo-contato-form-apoio {
  font-size: 13px;
  color: var(--luo-muted);
  margin: 0 0 32px;
}

.luo-contato-product {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px;
  margin-bottom: 24px;
  background: var(--luo-surface);
  border-radius: var(--luo-radius-input);
}

.luo-contato-product-image {
  width: 44px;
  height: 44px;
  object-fit: cover;
  border-radius: var(--luo-radius-input);
  flex: 0 0 auto;
}

.luo-contato-product-text {
  font-size: 13px;
  color: var(--luo-body);
}

.luo-contato-product-text a {
  color: var(--luo-ink);
  text-decoration: underline;
}

/* Sem verde/vermelho de propósito — regra do projeto é só preto e
   cinza fora do botão de compra (CLAUDE.md §4); sucesso e erro se
   diferenciam pelo texto, não pela cor. */
.luo-contato-alert {
  padding: 16px;
  margin-bottom: 24px;
  border: 1px solid var(--luo-line);
  border-radius: var(--luo-radius-input);
  background: var(--luo-surface);
  color: var(--luo-ink);
  font-size: 13px;
}

.luo-contato-alert--error {
  border-color: var(--luo-ink);
}

.luo-contato-field {
  margin-bottom: 20px;
}

/* Escopado a .luo-contato-field de propósito — .form-label é
   classe nativa genérica (conta, frete, endereço, newsletter),
   nunca estilizar sozinha (CLAUDE.md §8). */
.luo-contato-field .form-label {
  display: block;
  font-family: var(--body-font);
  font-size: 13px;
  color: var(--luo-body);
  margin-bottom: 8px;
}

.luo-contato-field .form-control {
  width: 100%;
  padding: 14px 16px;
  border: 1px solid var(--luo-border);
  border-radius: var(--luo-radius-input);
  font-family: var(--body-font);
  font-size: var(--luo-body-size);
  color: var(--luo-ink);
  background: #FFFFFF;
  transition: border-color .2s;
}

.luo-contato-field .form-control:focus {
  outline: none;
  border-color: var(--luo-ink);
}

.luo-contato-field .form-control-area {
  resize: vertical;
  min-height: 140px;
}

/* .btn/.btn-primary/.btn-big nativos vêm de fora do nosso CSS local
   (não encontrados em style-critical/async.scss — devem vir de uma
   folha base da plataforma fora do repo). Testado ao vivo: altura,
   largura pelo conteúdo, radius, borda e cor do texto de
   .luo-btn--dark (bloco 30) já venciam sozinhos — só
   background-color perdia pro nativo (saía #2F6B4F, a cor de
   --luo-buy — coincidência que sugere .btn-primary usa a mesma
   variável nativa --accent-color que, nesta loja, está configurada
   pra bater com o verde de compra; não confirmado com certeza, só a
   explicação mais provável). !important só nessa propriedade,
   exceção justificada contra nativo — mesmo critério do resto do
   projeto (CLAUDE.md §8). */
.luo-contato-submit {
  width: auto;
  align-self: flex-start;
  background-color: var(--luo-ink) !important;
}

.luo-contato-submit:hover {
  background-color: #FFFFFF !important;
}

@media (min-width: 1024px) {
  .luo-contato-grid {
    grid-template-columns: 7fr 5fr;
    gap: 96px;
    align-items: start;
  }

  .luo-contato-form-title {
    font-size: 20px;
  }
}

/* .luo-contato--solo: quando has_contact_info (contact.tpl) é falso
   — coluna de info teria só o H1, nada mais. Em vez de deixar uma
   coluna em branco do lado do formulário, a grade vira 1 coluna e
   H1 + formulário ficam centralizados, largura de leitura (640px —
   mesmo teto do conteúdo do Hero, bloco 6). Sobrescreve o 7fr/5fr
   acima em qualquer largura: 2 classes (0,2,0) vencem 1 (0,1,0). */
.luo-contato--solo .luo-contato-grid {
  max-width: 640px;
  margin: 0 auto;
}

.luo-contato--solo .luo-contato-col-info {
  text-align: center;
}

@media (min-width: 1024px) {
  .luo-contato--solo .luo-contato-grid {
    grid-template-columns: 1fr;
  }
}

/* ------------------------------------------------------------
   37. PÁGINA "COMO ESCOLHER O TAMANHO" — 2ª rodada (refinamento
   visual) em 2026-09-25. 1ª rodada: motor editorial substituído por
   diagramas SVG + comparador. Nesta rodada: revertida a decisão de
   container próprio (1440px) — volta a usar --luo-container (1280)
   sitewide, alinhado com header/rodapé; revertida a decisão do
   comparador com vão morto acima do sofá — agora a parede é
   preenchida (--luo-surface) com linha de teto, lendo como cômodo,
   não como espaço vazio. Toda a página passou a ser centralizada
   (label/título/texto/diagrama/grid), única exceção os passos 01-03
   (bloco centralizado, texto interno à esquerda — lista numerada
   centralizada fica ilegível).

   TOKENS DE ESPAÇAMENTO (declarados em .luo-tamanho, a única página
   que os usa — não são tokens sitewide): --luo-tamanho-pad (respiro
   vertical por seção), --luo-tamanho-label-gap (label→título),
   --luo-tamanho-title-gap (título→conteúdo principal),
   --luo-tamanho-diagram-gap (diagrama→texto/legenda),
   --luo-tamanho-grid-gap (entre itens de grid pequeno — cards/
   colunas). Todos em clamp() — mesmo valor mobile/desktop, sem
   duplicar em @media. .luo-tamanho-section soma esses tokens por
   cima de .luo-section (que ainda dá o container 1280/gutter/margin-
   auto sitewide — só o padding-top/bottom é sobrescrito aqui, mesma
   especificidade, bloco 37 vem depois na cascata).

   Escala dos diagramas: 1 unidade de viewBox = 1 centímetro, sempre
   — nenhuma multiplicação px/cm em Twig, o próprio viewBox escala.
   Traço: var(--luo-border) (~#C8C8C4 pedido, sem introduzir hex
   novo), vector-effect:non-scaling-stroke em todo traço/quadro pra
   render sempre ~1px/1.5px de verdade, independente da escala do
   viewBox. O quadro (.luo-tamanho-quadro) é a ÚNICA forma em
   var(--luo-ink) — "a única coisa com peso".

   Hero (seção 1): banner full-bleed (fora de .luo-section — não tem
   container, ocupa 100% da viewport), com imagem de fundo opcional
   (luo_tamanho_hero.jpg) + overlay gradiente escuro só o necessário
   pra legibilidade (mais forte no centro vertical, onde o texto
   fica — o texto agora é centralizado na caixa, não ancorado embaixo
   como o Hero da home). Sem foto: fundo branco, texto --luo-ink,
   mesma centralização. img com loading=eager + fetchpriority=high
   (é o LCP da página quando presente).

   Comparador (seção 4): o quadro dinâmico continua sendo uma <div>
   HTML absoluta sobre o SVG parede+sofá (luoliari-home-10.js,
   luoTamanhoInitComparador) — animação de width/height/left/top mais
   confiável entre navegadores que geometria SVG mudada via JS. A
   parede agora é um <rect> preenchido (--luo-surface) com linha de
   teto — mesmo canvas alto o bastante pro maior formato vertical
   (130×200) caber sem estourar, só que agora lê como parede alta,
   não como vazio. .luo-tamanho-title é compartilhada com a 404
   (bloco 37b, abaixo) — H1 idêntico nas duas. .luo-actions (bloco
   37b) só é usada pela 404 — esta página não tem faixa bege.
   ------------------------------------------------------------ */

.luo-tamanho {
  --luo-tamanho-pad: clamp(72px, 8vw, 128px);
  --luo-tamanho-label-gap: 12px;
  --luo-tamanho-title-gap: clamp(32px, 4vw, 56px);
  --luo-tamanho-diagram-gap: 24px;
  --luo-tamanho-grid-gap: clamp(16px, 2vw, 32px);
}

.luo-tamanho-section {
  padding-top: var(--luo-tamanho-pad);
  padding-bottom: var(--luo-tamanho-pad);
}

.luo-tamanho-section .luo-sec-head {
  display: block;
  text-align: center;
  margin-bottom: var(--luo-tamanho-title-gap);
}

.luo-tamanho-section .luo-label {
  margin-bottom: var(--luo-tamanho-label-gap);
}

.luo-tamanho-title,
.luo-404-title {
  font-size: clamp(1.4rem, 0.65rem + 4.5vw, 2.5rem);
  line-height: 1.15;
  margin: 0 0 32px;
}

/* --- traço e quadro, base de TODOS os diagramas SVG da página --- */
.luo-tamanho-linha {
  fill: none;
  stroke: var(--luo-border);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

.luo-tamanho-quadro {
  stroke: var(--luo-ink);
  stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
  fill: var(--luo-ph-2);
}

.luo-tamanho-quadro--tracejado {
  fill: none;
  stroke-dasharray: 5 5;
}

.luo-tamanho-cota-label {
  font-family: var(--body-font);
  font-size: 9px;
  letter-spacing: 0.4px;
  fill: var(--luo-muted);
}

/* --- 1. Hero (full-bleed, fora do container) --- */
/* Sem foto: altura = conteúdo, só padding (sem min-height/height —
   ajuste 2026-09-25 2ª rodada, o min-height/height fixo era o que
   empurrava a seção 2 pra fora da primeira dobra em 1440×900). Com
   foto: banner de altura fixa (precisa da imagem cobrindo a caixa
   inteira), centralizado por flex só nessa variante. */
.luo-tamanho-hero {
  position: relative;
  padding: clamp(48px, 6vw, 80px) 0;
  text-align: center;
  overflow: hidden;
  background: #FFFFFF;
}

.luo-tamanho-hero--foto {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 320px;
}

@media (min-width: 1024px) {
  .luo-tamanho-hero--foto {
    height: clamp(280px, 26vw, 400px);
    min-height: 0;
  }
}

.luo-tamanho-hero-media {
  position: absolute;
  inset: 0;
}

.luo-tamanho-hero-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.luo-tamanho-hero--foto::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(17, 17, 17, .18) 0%, rgba(17, 17, 17, .48) 50%, rgba(17, 17, 17, .18) 100%);
}

/* Bug 2026-09-26: sem imagem, .luo-tamanho-hero não é mais flex (só
   a variante --foto ganhou display:flex nesta rodada) — sem essa
   centralização e sem margin:auto próprio, o bloco de 640px ficava
   colado na borda esquerda do full-bleed. Correção: hero-inner vira
   o MESMO container padrão do resto da página (max-width:
   var(--luo-container), 1280 — igual .luo-section/.luo-inner),
   centralizado por margin:auto, nos dois modos (a variante --foto
   também centraliza via flex — as duas mecânicas não conflitam). */
.luo-tamanho-hero-inner {
  position: relative;
  z-index: 1;
  max-width: var(--luo-container);
  margin: 0 auto;
  padding: 0 var(--luo-gutter);
}

.luo-tamanho-hero .luo-label {
  margin-bottom: var(--luo-tamanho-label-gap);
}

.luo-tamanho-hero .luo-tamanho-title {
  margin-bottom: 18px;
}

.luo-tamanho-hero--foto .luo-label,
.luo-tamanho-hero--foto .luo-tamanho-title,
.luo-tamanho-hero--foto .luo-tamanho-hero-apoio {
  color: #FFFFFF;
}

.luo-tamanho-hero-apoio {
  max-width: 560px;
  margin: 0 auto;
  font-size: var(--luo-body-size);
  color: var(--luo-body);
}

/* --- 2. A regra dos 60-75% --- */
/* Única seção que segue direto o hero: padding-top próprio, reduzido
   (hero já dá até 80px de padding inferior sem foto — a soma dos
   dois precisa ficar em ~96px no desktop pro título desta seção
   entrar na 1ª dobra em 1440×900). Mesma especificidade de
   .luo-tamanho-section (0,1,0), definida depois na cascata — vence. */
.luo-tamanho-regra {
  padding-top: 16px;
}

.luo-tamanho-regra-svg {
  display: block;
  width: 100%;
  max-width: 760px;
  height: auto;
  margin: 0 auto var(--luo-tamanho-diagram-gap);
}

.luo-tamanho-regra-texto {
  max-width: 560px;
  margin: 0 auto;
  font-size: var(--luo-body-size);
  line-height: 1.8;
  color: var(--luo-body);
  text-align: center;
}

.luo-tamanho-regra-texto p {
  margin: 0 0 12px;
}

.luo-tamanho-regra-exemplos {
  font-size: 12px;
  color: var(--luo-muted);
  margin: 0;
}

/* --- 3. Qual é o seu caso? --- */
.luo-tamanho-casos-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--luo-tamanho-grid-gap);
}

@media (min-width: 1024px) {
  .luo-tamanho-casos-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* Mesmo estilo das colunas de "Formato" (seção 5): linha fina em
   cima, sem caixa/borda ao redor, conteúdo centralizado, ícone no
   mesmo tamanho (max-width 80px) nas duas seções. */
.luo-tamanho-caso-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding-top: 20px;
  background: none;
  border: none;
  border-top: 1px solid var(--luo-border);
  text-align: center;
  cursor: pointer;
  transition: border-color .25s ease;
}

.luo-tamanho-caso-card:hover,
.luo-tamanho-caso-card[aria-pressed="true"] {
  border-top-color: var(--luo-ink);
}

.luo-tamanho-caso-icone {
  width: 100%;
  max-width: 80px;
  height: auto;
}

.luo-tamanho-caso-titulo {
  font-family: var(--heading-font);
  font-weight: var(--title-font-weight);
  font-size: 16px;
  color: var(--luo-ink);
}

.luo-tamanho-caso-texto {
  font-size: 13px;
  line-height: 1.6;
  color: var(--luo-body);
}

.luo-tamanho-caso-campo {
  max-width: 360px;
  margin: 32px auto 0;
  padding: 24px;
  border: 1px solid var(--luo-line);
  border-radius: var(--luo-radius-input);
  text-align: center;
}

.luo-tamanho-caso-campo-label {
  display: block;
  font-size: 12px;
  color: var(--luo-muted);
  margin-bottom: 8px;
}

.luo-tamanho-caso-input {
  width: 100%;
  height: 44px;
  padding: 0 16px;
  border: 1px solid var(--luo-border);
  border-radius: var(--luo-radius-input);
  font-size: 14px;
  color: var(--luo-ink);
  background: #FFFFFF;
  text-align: center;
}

.luo-tamanho-caso-input:focus-visible {
  outline: 2px solid var(--luo-ink);
  outline-offset: 2px;
}

.luo-tamanho-caso-resultado {
  margin-top: 16px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--luo-ink);
}

.luo-tamanho-caso-resultado strong {
  font-weight: 600;
}

/* --- 4. O comparador — seção principal --- */
/* Palco com ALTURA limitada (não mais aspect-ratio dirigido pela
   largura — era isso que gerava ~880px de altura e o vazio enorme:
   360/355 aplicado a uma largura de 960px). A largura continua até
   960px, mas a altura é sempre min(540px, 58vh) — critério de
   aceite: palco + régua cabem juntos em 1440×900 e 390×844 sem
   rolar. A escala física (px/cm) é derivada da ALTURA do palco, não
   da largura — ver luoTamanhoInitComparador em luoliari-home-*.js.
   O <svg> ganha um viewBox DINÂMICO (mesma unidade cm nos dois
   eixos, sem distorcer sofá/cota) recalculado a cada atualizar()/
   resize; por isso preserveAspectRatio="none" (o viewBox já vem no
   aspect ratio certo, calculado em JS). */
.luo-tamanho-comparador-cena {
  position: relative;
  width: 100%;
  max-width: 960px;
  height: min(540px, 58vh);
  margin: 0 auto var(--luo-tamanho-diagram-gap);
}

.luo-tamanho-comparador-cena svg {
  display: block;
  width: 100%;
  height: 100%;
}

/* Parede preenchida + linha de teto (pé-direito realista) — o
   espaço acima do sofá lê como cômodo, não como vão morto. */
.luo-tamanho-parede-fundo {
  fill: var(--luo-surface);
}

.luo-tamanho-comparador-quadro {
  position: absolute;
  background: var(--luo-ph-2);
  border: 1.5px solid var(--luo-ink);
  transition: width .35s ease, height .35s ease, left .35s ease, top .35s ease;
}

.luo-tamanho-comparador-quadro img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Medida do formato ativo, junto ao quadro — não usa overflow:hidden
   no pai (removido) pra este rótulo, que fica um pouco acima do
   quadro, não ser cortado. */
.luo-tamanho-comparador-medida {
  position: absolute;
  top: -22px;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  font-size: 11px;
  color: var(--luo-muted);
}

@media (prefers-reduced-motion: reduce) {
  .luo-tamanho-comparador-quadro {
    transition: none;
  }
}

.luo-tamanho-regua {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px;
  max-width: 960px;
  margin: 0 auto 20px;
  padding-bottom: 4px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
}

.luo-tamanho-regua-item {
  flex: 0 0 auto;
  scroll-snap-align: start;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 8px 4px;
  font-size: 13px;
  color: var(--luo-muted);
  white-space: nowrap;
  cursor: pointer;
  transition: color .2s ease, border-color .2s ease;
}

.luo-tamanho-regua-item:hover,
.luo-tamanho-regua-item.is-active {
  color: var(--luo-ink);
}

.luo-tamanho-regua-item.is-active {
  border-bottom-color: var(--luo-ink);
}

.luo-tamanho-orientacao {
  display: flex;
  justify-content: center;
  gap: 4px;
  margin: 0 auto 24px;
}

.luo-tamanho-orientacao-item {
  background: none;
  border: 1px solid var(--luo-border);
  border-radius: var(--luo-radius-input);
  padding: 6px 16px;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--luo-muted);
  cursor: pointer;
  transition: background-color .2s ease, color .2s ease, border-color .2s ease;
}

.luo-tamanho-orientacao-item.is-active {
  background: var(--luo-ink);
  color: #FFFFFF;
  border-color: var(--luo-ink);
}

.luo-tamanho-comparador-info {
  text-align: center;
}

.luo-tamanho-comparador-nome {
  font-family: var(--heading-font);
  font-weight: var(--title-font-weight);
  font-size: 18px;
  color: var(--luo-ink);
  margin: 0 0 4px;
}

.luo-tamanho-comparador-desc {
  max-width: 480px;
  margin: 0 auto 16px;
  font-size: 13px;
  color: var(--luo-body);
}

.luo-tamanho-nota {
  font-size: 11px;
  color: var(--luo-muted);
  margin: 0;
  text-align: center;
}

/* --- 5. Formato --- */
.luo-tamanho-formato-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--luo-tamanho-grid-gap);
  margin: 0 0 var(--luo-tamanho-title-gap);
  justify-items: center;
}

@media (min-width: 1024px) {
  .luo-tamanho-formato-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

.luo-tamanho-formato-col {
  width: 100%;
  max-width: 220px;
  padding-top: 20px;
  border-top: 1px solid var(--luo-border);
  text-align: center;
}

.luo-tamanho-formato-icone {
  width: 100%;
  max-width: 80px;
  height: auto;
  margin: 0 auto 12px;
}

.luo-tamanho-formato-titulo {
  font-family: var(--heading-font);
  font-weight: var(--title-font-weight);
  font-size: 16px;
  color: var(--luo-ink);
  margin: 0 0 6px;
}

.luo-tamanho-formato-texto {
  font-size: 13px;
  line-height: 1.6;
  color: var(--luo-body);
  margin: 0;
}

.luo-tamanho-formato-fecho {
  max-width: 640px;
  margin: 0 auto;
  font-family: var(--heading-font);
  font-weight: var(--title-font-weight);
  font-size: clamp(18px, 15px + 1vw, 22px);
  line-height: 1.5;
  color: var(--luo-ink);
  text-align: center;
}

/* --- 6. Altura — os dois diagramas com o mesmo viewBox (260×220) e
   a mesma linha de piso; rótulo das cotas corrigido (viewBox largo
   o bastante pra não cortar "15–25 cm"/"1,50 m" — a causa real do
   corte era o texto ficando fora da área visível do viewBox). --- */
.luo-tamanho-altura-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 40px;
}

@media (min-width: 1024px) {
  .luo-tamanho-altura-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 80px;
  }
}

.luo-tamanho-altura-item {
  text-align: center;
}

.luo-tamanho-altura-item svg {
  display: block;
  width: 100%;
  max-width: 320px;
  height: auto;
  margin: 0 auto var(--luo-tamanho-diagram-gap);
}

.luo-tamanho-altura-item p {
  max-width: 320px;
  margin: 0 auto;
  font-size: var(--luo-body-size);
  color: var(--luo-body);
}

/* --- 7. Teste na sua parede — EXCEÇÃO à centralização: o bloco
   (lista + ícone) fica centralizado no container, mas o texto
   dentro da lista numerada continua alinhado à esquerda (centralizar
   01/02/03 com texto fica ilegível). --- */
.luo-tamanho-passos-grid {
  display: grid;
  grid-template-columns: 1fr;
  align-items: center;
  gap: 40px;
  max-width: 760px;
  margin: 0 auto;
}

@media (min-width: 1024px) {
  .luo-tamanho-passos-grid {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  }
}

.luo-tamanho-passos-lista {
  display: flex;
  flex-direction: column;
  gap: 24px;
  list-style: none;
  margin: 0;
  padding: 0;
  text-align: left;
}

.luo-tamanho-passos-lista li {
  display: flex;
  gap: 16px;
}

.luo-tamanho-passo-num {
  flex: 0 0 auto;
  font-family: var(--heading-font);
  font-weight: var(--title-font-weight);
  font-size: 24px;
  line-height: 1;
  color: var(--luo-border);
}

.luo-tamanho-passos-lista h3 {
  font-size: 16px;
  margin: 0 0 6px;
}

.luo-tamanho-passos-lista p {
  font-size: 13px;
  line-height: 1.6;
  color: var(--luo-body);
  margin: 0;
}

.luo-tamanho-passos-icone {
  display: block;
  width: 100%;
  max-width: 240px;
  height: auto;
  margin: 0 auto;
}

/* --- 8. CTA final (sem faixa bege — pedido explícito do briefing) --- */
.luo-tamanho-cta-final {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--luo-tamanho-grid-gap);
  text-align: center;
}

.luo-tamanho-cta-frase {
  max-width: 560px;
  font-family: var(--heading-font);
  font-weight: var(--title-font-weight);
  font-size: clamp(20px, 16px + 1.6vw, 28px);
  color: var(--luo-ink);
  margin: 0;
}

.luo-tamanho-link-discreto {
  font-size: 12px;
  color: var(--luo-muted);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.luo-tamanho-link-discreto:hover {
  color: var(--luo-ink);
}

/* .luo-actions permanece — usada pela 404, bloco 37b abaixo. */
.luo-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 32px 20px;
  background: var(--luo-surface);
  border-radius: var(--luo-radius-img);
}

@media (max-width: 639px) {
  .luo-actions .luo-btn--dark,
  .luo-actions .luo-btn--light {
    width: 100%;
    max-width: 320px;
  }
}

/* ------------------------------------------------------------
   37b. PÁGINA 404 (templates/404.tpl — nativo, reescrito em
   2026-09-19). Mesma coluna de leitura e mesmo H1 de página da
   "Como escolher o tamanho"; ações na faixa .luo-actions acima.
   ------------------------------------------------------------ */
.luo-404-col {
  max-width: 710px;
  margin: 0 auto;
}

.luo-404-text {
  font-size: var(--luo-body-size);
  line-height: 1.8;
  color: var(--luo-body);
  margin: 0 0 40px;
}

/* ------------------------------------------------------------
   38. PÁGINA "SOU ARQUITETO" (snipplets/luoliari/page-arquiteto.tpl,
   templates/page.tpl ramo por handle `sou-arquiteto`). Referência:
   .docs/arquiteto-v2-luoliari.html — estrutura e hierarquia;
   fontes, cores exatas, header e rodapé do wireframe ignorados,
   tokens do projeto valem. CONTEÚDO PROVISÓRIO: os textos padrão
   (settings.txt "Página Sou Arquiteto") vêm do wireframe e serão
   substituídos por texto do cliente — ver CLAUDE.md.

   4 blocos, cada um um <section> com .luo-section (container +
   gutter, bloco 3b) mais um modificador desta página que troca só o
   respiro vertical — mesmo raciocínio do bloco 31 (Sobre): o
   .luo-section puro (64/128px de cada lado) dobraria o vão entre
   blocos. Aqui só padding-top por bloco (--luo-arq-gap, mesma clamp()
   do --luo-sobre-gap: 48px mobile → 80px desktop) e o último ganha
   padding-bottom igual, o respiro antes do rodapé. O hero (primeiro
   bloco, logo abaixo do header) usa .luo-section--top (bloco 3c) em
   vez do gap.

   Tudo escopado em .luo-arq-* — nenhuma regra desta página vaza pra
   outra Página estática (o layout só existe dentro do ramo por
   handle em page.tpl). Nada aqui redeclara .luo-btn--dark/-anim
   (blocos 30/30b) — os dois botões da página usam o componente
   luo-btn.tpl como está.
   ------------------------------------------------------------ */

.luo-arq {
  --luo-arq-gap: clamp(48px, 28px + 5.05vw, 80px);
}

.luo-arq-hero {
  padding-bottom: 0;
}

.luo-arq-block {
  padding-top: var(--luo-arq-gap);
  padding-bottom: 0;
}

.luo-arq-block--last {
  padding-bottom: var(--luo-arq-gap);
}

/* Pilha vertical com espaçamento por gap (não por margin em cada
   filho): campo vazio some do DOM (o .tpl nem renderiza o elemento) e
   a pilha fecha sozinha, sem vão onde estaria o título/parágrafo que
   não existe. .luo-label nativo tem margin-bottom:10px (bloco 3) —
   zerado aqui pra o gap ser a única fonte de espaço. */
.luo-arq-stack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
}

.luo-arq-stack--center {
  align-items: center;
  text-align: center;
}

.luo-arq .luo-label {
  margin-bottom: 0;
}

/* Título de seção (H2) — mesma escala do cabeçalho de seção da home
   (.luo-sec-head h2, bloco 3: 19px mobile → --luo-h2 desktop). */
.luo-arq-h2 {
  font-size: 19px;
  line-height: 1.25;
  margin: 0;
}

.luo-arq-lead {
  font-size: var(--luo-body-size);
  line-height: 1.8;
  color: var(--luo-body);
  margin: 0;
  max-width: 480px;
}

/* --- 1. Hero — texto antes da imagem no DOM: mobile empilha com a
   imagem embaixo (pedido), desktop vira duas colunas iguais sem
   precisar de "order". H1 usa a MESMA clamp() de título de página
   das outras Páginas (série/coleção bloco 8b, contato bloco 36,
   tamanho bloco 37). */
.luo-arq-hero-grid {
  display: grid;
  gap: 32px;
}

.luo-arq-hero-text {
  max-width: 560px;
}

.luo-arq-hero-title {
  font-size: clamp(1.4rem, 0.65rem + 4.5vw, 2.5rem);
  line-height: 1.15;
  margin: 0;
}

/* O gap da pilha (16px) somado a esta margem dá os ~26px de respiro
   entre o último texto e o botão — mesmo valor da seção "Sou
   Arquiteto" da home (bloco 12). */
.luo-arq-hero-text .luo-btn-anim,
.luo-arq-cta-inner .luo-btn-anim {
  margin-top: 10px;
}

/* 4:3 — proporção do wireframe. Sem imagem, o .tpl renderiza o
   placeholder tonal (.luo-ph, bloco 3) dentro do mesmo wrapper. */
.luo-arq-hero-media {
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: var(--luo-radius-img);
}

.luo-arq-hero-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.luo-arq-hero-media .luo-ph {
  width: 100%;
  height: 100%;
}

/* --- 2. "O que você encontra aqui" e 3. "Como funciona" — cabeçalho
   (eyebrow + H2) e a grade de itens. Lista semântica (ul/ol) com
   list-style zerado; role="list" no .tpl devolve a semântica de lista
   no Safari/VoiceOver, que a tira quando list-style é none. */
.luo-arq-head {
  margin-bottom: 32px;
}

.luo-arq-cols,
.luo-arq-passos {
  display: grid;
  gap: 32px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.luo-arq-col {
  border-top: 1px solid var(--luo-ink);
  padding-top: 22px;
}

/* Título de coluna/passo = nível "nome de entidade" (bloco 3: caixa
   alta, peso 500, --heading-font, var(--font-base)) — declarado aqui
   em vez de reaproveitar a classe, porque .luo-colecoes-name carrega
   !important no font-size pensado pro card de coleção. */
.luo-arq-item-title {
  font-family: var(--heading-font);
  font-size: var(--font-base);
  font-weight: 500;
  line-height: 1.3;
  text-transform: uppercase;
  color: var(--luo-ink);
  margin: 0 0 10px;
}

.luo-arq-item-title:last-child {
  margin-bottom: 0;
}

.luo-arq-item-text {
  font-size: var(--luo-body-size);
  line-height: 1.8;
  color: var(--luo-body);
  margin: 0;
  max-width: 360px;
}

/* Link de texto (sem ícone de link externo — pedido explícito): mesmo
   estilo de .luo-support-link (bloco 23) — sublinhado permanente,
   repouso --luo-ink-soft, hover --luo-ink. Sublinhado fixo (não só no
   hover) porque a diferença de cor pro texto do parágrafo é sutil
   demais pra ser o único sinal de que é link. */
.luo-arq-link {
  display: inline-block;
  margin-top: 14px;
  font-size: 13px;
  color: var(--luo-ink-soft);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  transition: color .18s ease;
}

.luo-arq-link:hover {
  color: var(--luo-ink);
}

.luo-arq-link:focus-visible {
  outline: 2px solid var(--luo-ink);
  outline-offset: 2px;
}

/* --- 3. "Como funciona" — faixa bege no mesmo tratamento da
   Ambientação (bloco 13): mobile sangra de ponta a ponta, sem radius
   (margem negativa = o próprio --luo-gutter do .luo-section, que a
   caixa devolve como padding pra o texto continuar alinhado com o
   resto da página); desktop (≥1024px) contida na largura do conteúdo,
   com --luo-radius-img. Margem negativa em vez de 100vw: não cria
   rolagem horizontal quando a página tem barra de rolagem. */
.luo-arq-como-box {
  background: var(--luo-surface);
  margin-left: calc(var(--luo-gutter) * -1);
  margin-right: calc(var(--luo-gutter) * -1);
  padding: 48px var(--luo-gutter);
}

.luo-arq-passo {
  display: grid;
  grid-template-columns: 40px 1fr;
  column-gap: 16px;
  align-items: start;
  border-top: 1px solid var(--luo-line);
  padding-top: 22px;
}

/* Número decorativo (aria-hidden no .tpl) — cinza claro, --heading-font
   sem caixa/peso especial. --luo-border em vez de --luo-ph-3: o
   segundo some contra o fundo bege. Coluna de largura fixa pra o
   texto dos três passos começar no mesmo recuo (01/02/03 têm larguras
   diferentes na Lemon Milk — medido: 29,7/38,8/37,2px a 28px de fonte,
   49,9px o maior a 36px; as colunas de 40px/52px acomodam o maior). */
.luo-arq-passo-num {
  font-family: var(--heading-font);
  font-size: 28px;
  font-weight: var(--title-font-weight);
  line-height: 1;
  color: var(--luo-border);
}

.luo-arq-passo-body .luo-arq-item-title {
  margin-top: 4px;
}

/* --- 4. Chamada final — centralizada, sem fundo próprio. */
.luo-arq-cta-inner {
  max-width: 640px;
  margin: 0 auto;
}

/* text-wrap:balance evita a palavra solta na última linha ("e-mail.")
   no mobile; navegador sem suporte ignora a declaração. */
.luo-arq-cta-inner .luo-arq-lead {
  max-width: 480px;
  text-wrap: balance;
}

@media (min-width: 1024px) {
  .luo-arq-hero-grid {
    grid-template-columns: 1fr 1fr;
    gap: 80px;
    align-items: center;
  }

  .luo-arq-lead {
    line-height: 1.85;
  }

  .luo-arq-h2 {
    font-size: var(--luo-h2);
  }

  .luo-arq-head {
    margin-bottom: 48px;
  }

  .luo-arq-cols,
  .luo-arq-passos {
    grid-template-columns: repeat(3, 1fr);
    gap: 40px;
  }

  .luo-arq-como-box {
    margin-left: 0;
    margin-right: 0;
    padding: 80px 64px;
    border-radius: var(--luo-radius-img);
  }

  .luo-arq-passo {
    grid-template-columns: 52px 1fr;
    column-gap: 20px;
  }

  .luo-arq-passo-num {
    font-size: 36px;
  }
}

/* ------------------------------------------------------------
   39. TÍTULO "PRODUTOS SIMILARES" (página de produto)
   Vem do componente nativo `products-section` (snipplets/product/
   product-related.tpl) como <h2 class="products-section-title h3
   section-title mb-4 text-center"> — a classe .h3 nativa dava 24px
   nos DOIS tamanhos (var(--h3)), maior que o H1 do próprio produto no
   mobile (18px). Reduzido pro nível de título de bloco secundário:
   15px mobile / 18px desktop (breakpoint 768px, o -md nativo que já
   rege o H1 e o preço deste template — bloco 21). Escopo
   .js-related-products: só "Produtos similares" — o bloco de produtos
   complementares (.js-complementary-products) e o carrinho usam o mesmo
   componente e não foram pedidos. A tag continua <h2> (saída do
   componente nativo, que não expõe a tag) — semanticamente certo:
   H1 do produto → H2 de seção.
   ------------------------------------------------------------ */

.js-related-products .products-section-title {
  font-size: 15px;
  line-height: 1.3;
}

@media (min-width: 768px) {
  .js-related-products .products-section-title {
    font-size: 18px;
  }
}

/* ------------------------------------------------------------
   40. CATEGORIA UTILITÁRIA (2026-09-26) — categoria principal SEM
   subcategoria (Clássicos, Acrílicos, Souvenir), ramo "is_utilitaria"
   de templates/category.tpl. snipplets/luoliari/category-utilitaria-
   header.tpl (título + descrição) + grid nativo de produtos
   (.luo-serie-grid, já estilizado no bloco 8c — reaproveitado, não
   duplicado aqui).
   ------------------------------------------------------------ */

.luo-cat-util-head {
  max-width: 640px;
}

.luo-cat-util-head .luo-serie-hero-title {
  margin-top: 0;
}

.luo-cat-util-empty {
  padding: 0 0 var(--luo-section-gap);
  color: var(--luo-muted);
  font-size: var(--luo-body-size);
}

/* ------------------------------------------------------------
   41. COMPARTILHAR (página de produto) — snipplets/social/social-
   share.tpl, chamado 2x (mobile: templates/product.tpl; desktop:
   snipplets/product/product-image.tpl). Estilo discreto: rótulo em
   caixa alta + ícones monocromáticos pequenos — nunca disputa
   atenção com o botão de compra. Ícones herdam cor via currentColor
   (mesmo padrão do ícone SSL do rodapé, bloco 33).
   ------------------------------------------------------------ */

.luo-share {
  display: inline-flex;
  align-items: center;
  gap: 14px;
}

.luo-share-label {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: var(--luo-ls-label);
  text-transform: uppercase;
  color: var(--luo-muted);
}


/* ------------------------------------------------------------
   42. PÁGINA LOJA (2026-09-27, refinada 2026-09-28 — referência
   galeria9.com.br/quadros-decorativos.html, adaptada ao sistema do
   projeto). templates/category.tpl inclui snipplets/luoliari/
   page-loja.tpl sempre que is_loja_view for true (/produtos/ sem
   parâmetro, ou ?view=loja em qualquer categoria). Grid reaproveita
   snipplets/grid/product-list.tpl (o MESMO card .item-product do site
   inteiro) — só a contagem de colunas muda pra esta página (42e).
   ------------------------------------------------------------ */

.luo-loja-section {
  margin-bottom: 24px;
}

@media (min-width: 1024px) {
  .luo-loja-section {
    margin-bottom: 32px;
  }
}

/* 42a. Cabeçalho — .luo-loja-head é a classe própria do wrapper (NÃO
   .luo-cat-util-head: aquela também trava max-width:640px no wrapper
   inteiro, que combinado com margin:auto de .luo-inset CENTRALIZA a
   caixa — achado ao vivo, título saía recuado pra x≈430 em vez de
   x=110). Só a descrição (.luo-loja-lead, some a .luo-serie-hero-lead
   nativa) leva os 640px — o <h1> ocupa a largura toda. */
.luo-loja-lead {
  max-width: 640px;
}

/* 42b. Toolbar — DUAS marcações (desktop/mobile, ver page-loja.tpl):
   o status muda de lugar (ao lado do botão de recolher no desktop,
   linha própria abaixo no mobile) e o botão de recolher nem existe no
   mobile (lá é o drawer, não uma sidebar pra recolher). */
.luo-loja-toolbar--desktop {
  display: none;
}

@media (min-width: 1024px) {
  .luo-loja-toolbar--desktop {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
  }
}

.luo-loja-toolbar-left {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
}

.luo-loja-toolbar--mobile {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

@media (min-width: 1024px) {
  .luo-loja-toolbar--mobile {
    display: none;
  }
}

.luo-loja-toolbar-row {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* 42c. Botão "Recolher filtros" / "Mostrar filtros" — só desktop
   (mobile usa o botão "Filtrar", que abre o drawer, já existente).
   Rótulo troca via `aria-expanded` no próprio botão (JS só alterna o
   atributo — texto e ícone são CSS puro, sem manipular textContent). */
.luo-loja-toggle-filtros {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  padding: 0 18px;
  border: 1px solid var(--luo-ink);
  border-radius: var(--luo-radius-btn);
  background: none;
  color: var(--luo-ink);
  font-size: 13px;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.luo-loja-toggle-filtros:hover {
  background: var(--luo-surface);
}

.luo-loja-toggle-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
}

.luo-loja-toggle-icon circle {
  fill: currentColor;
}

.luo-loja-toggle-label--collapsed {
  display: none;
}

.luo-loja-toggle-filtros[aria-expanded="false"] .luo-loja-toggle-label--expanded {
  display: none;
}

.luo-loja-toggle-filtros[aria-expanded="false"] .luo-loja-toggle-label--collapsed {
  display: inline;
}

/* 42d. Linha de status — nome do filtro ativo + contagem, "Limpar
   filtro" só quando não é a raiz /produtos/ (loja_is_produtos_root,
   page-loja.tpl). */
.luo-loja-status {
  margin: 0;
  font-size: var(--luo-body-size);
  color: var(--luo-body);
  white-space: normal;
}

.luo-loja-status b {
  color: var(--luo-ink);
  font-weight: 600;
}

.luo-loja-status-clear {
  color: var(--luo-muted);
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color 0.2s ease;
}

.luo-loja-status-clear:hover {
  color: var(--luo-ink);
}

/* 42e. Select de ordenação — component('sort-by', {label:false}) já é
   um <select> nativo de verdade (confirmado ao vivo, sonda temporária
   na rodada anterior). Rótulo "Ordenar por" é nosso, texto simples ao
   lado (o label nativo do componente é escondido via label:false).
   Largura travada — o `.form-select` nativo é width:100% por padrão,
   e sem essa trava ele esticava pra ocupar a linha toda. */
.luo-loja-sort {
  display: flex;
  align-items: center;
  gap: 8px;
}

.luo-loja-sort-label {
  font-size: 13px;
  color: var(--luo-muted);
  white-space: nowrap;
}

.luo-loja-sort .form-group {
  margin: 0;
}

.luo-loja-sort select {
  -webkit-appearance: none;
  appearance: none;
  width: 200px;
  max-width: 100%;
  height: 40px;
  padding: 0 36px 0 14px;
  border: 1px solid var(--luo-border);
  border-radius: var(--luo-radius-input);
  background-color: var(--luo-bg);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%238A8A84' d='M4 6l4 4 4-4z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 10px;
  font-size: 13px;
  color: var(--luo-ink);
  cursor: pointer;
}

.luo-loja-sort select:focus {
  outline: none;
  border-color: var(--luo-ink);
}

@media (max-width: 1023px) {
  .luo-loja-sort select {
    width: 160px;
  }
}

/* 42f. Drawer mobile — snipplets/modal.tpl genérico (mesmo componente
   do menu hambúrguer e do filtro nativo de busca), zero CSS/JS novo
   pra abrir/fechar. Só o conteúdo (a árvore de filtro) precisa de
   respiro dentro do painel. */
#nav-loja-filtro .modal-body {
  padding-top: 8px;
}

/* 42g. Layout — sidebar (~240px, sticky) + conteúdo. Empilhado até
   1023px (a sidebar nem renderiza visível — o filtro mobile é o
   drawer, ver 42f); 2 colunas de grid a partir de 1024px, ou 4 quando
   a sidebar está recolhida (.is-collapsed, JS initLojaFiltros). */
.luo-loja-sidebar {
  display: none;
}

@media (min-width: 1024px) {
  .luo-loja-layout {
    display: grid;
    grid-template-columns: 240px 1fr;
    gap: 48px;
    align-items: start;
  }

  .luo-loja-layout.is-collapsed {
    grid-template-columns: 1fr;
  }

  .luo-loja-sidebar {
    display: block;
    position: sticky;
    /* Header nativo é sticky (top:-50px, a barra de anúncios de 50px
       sai ao rolar) e sobram 98px fixos (era 115px antes do header
       perder ~20% de altura em 2026-09-28 — ver --luo-sobre-sticky-top,
       bloco 32, mesmo cálculo), aqui com um respiro menor (24px) por
       ser uma barra de trabalho, não uma foto decorativa. */
    top: 122px;
  }

  .luo-loja-layout.is-collapsed .luo-loja-sidebar {
    display: none;
  }
}

/* 42h. Grid de obras — reaproveita snipplets/grid/product-list.tpl
   (mesmo .item-product do site inteiro). O `.container` nativo (max-
   width própria + padding que cancela a margem negativa do
   `.row-grid`) atrapalha dentro da coluna estreita da Loja — zerados
   os dois lados (container E row) juntos, nunca só um, senão o outro
   sobra sozinho e estoura a lateral. `.col-grid` (padding ENTRE
   cards, não a borda externa) continua intocado — é o que abre o
   respiro entre as obras. */
.luo-loja-grid > .container {
  max-width: none;
  padding-left: 0;
  padding-right: 0;
}

.luo-loja-grid .row-grid {
  margin-left: 0;
  margin-right: 0;
}

/* Proporção da imagem do card (2026-09-27): já é 4:5 de propósito —
   `.js-item-image-padding{padding-bottom:125% !important}` (bloco 17)
   é global, site inteiro, desde 2026-09-18. Medido ao vivo aqui antes
   de mexer em qualquer coisa: 1440px e 390px já davam ratio 1.2500 nos
   dois. Nada pra corrigir na Loja especificamente — nenhuma regra
   própria dela toca `.item-image`/`.js-item-image-padding`.

   Respiro vertical ENTRE linhas — aumentado ~50% (2026-09-27), SÓ
   AQUI. O grid usa `flex-wrap` (Bootstrap), não `row-gap` de verdade:
   o respiro entre uma linha e a próxima vem inteiro do
   `margin-bottom:10px` nativo de `.item` (style-critical.scss, mesmo
   wrapper de QUALQUER grid do tema — inclusive `.luo-serie-grid`, ver
   bloco 8c, que usa o mesmíssimo `.js-product-table`/`.item`).
   Confirmado ao vivo medindo o vão real (não a margem) entre o fim do
   texto de uma linha e o topo da imagem da próxima: 10px, batendo
   exato com o valor nativo. Escopado a `.luo-loja-grid .item` (0,2,0
   vence o nativo `.item`, 0,1,0, sem !important) — a página de série
   e qualquer outro grid do site continuam com 10px, intocados, como
   pedido nesta rodada. */
.luo-loja-grid {
  --luo-loja-row-gap: 15px;
}

.luo-loja-grid .item {
  margin-bottom: var(--luo-loja-row-gap);
}

/* Nativo entrega col-6 (2 colunas) <768px e col-md-3 (4 colunas)
   ≥768px — pedido aqui é 2 colunas até 1023px e 3 a partir de
   1024px (4 quando a sidebar está recolhida), então o intervalo
   768-1023 precisa puxar de volta pra 2 antes do desktop assumir 3.
   `!important` não é necessário: as classes nativas não usam, e um
   seletor de descendente com uma classe (`.luo-loja-grid .col-md-3`)
   já empata em especificidade e vence por vir depois no arquivo. */
@media (min-width: 768px) and (max-width: 1023px) {
  .luo-loja-grid .col-md-3 {
    flex: 0 0 50%;
    max-width: 50%;
  }
}

@media (min-width: 1024px) {
  .luo-loja-grid .col-md-3 {
    flex: 0 0 33.3333%;
    max-width: 33.3333%;
  }

  .luo-loja-layout.is-collapsed .luo-loja-grid .col-md-3 {
    flex: 0 0 25%;
    max-width: 25%;
  }
}

/* 42i. Blocos da sidebar — "Busque por" / "Filtre sua busca", título
   em LUO Display (herdado do <h2> nativo, sem precisar de font-family
   explícito) + linha fina abaixo. */
.luo-loja-filtro-block {
  margin-bottom: 32px;
}

.luo-loja-filtro-block:last-child {
  margin-bottom: 0;
}

.luo-loja-filtro-block-title {
  font-size: 18px;
  margin: 0 0 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--luo-line);
}

@media (min-width: 1024px) {
  .luo-loja-filtro-block-title {
    font-size: 20px;
  }
}

/* 42j. Árvore "Busque por" — texto puro, SEM contagem (removida a
   pedido). Item de nível 1 (Todas as obras/Clássicos/Coleções/
   utilitárias) em caixa alta; série (nível 2, recuada) em sentence
   case. Ativo continua na MESMA cor --luo-ink de todo mundo — só o
   peso e um sublinhado fino diferenciam (pedido explícito: "não
   cinza claro, a referência usa preto"). */
.luo-loja-filtro-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.luo-loja-filtro-colecoes {
  margin-top: 4px;
}

.luo-loja-filtro-link,
.luo-loja-filtro-link:visited {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 0;
  font-size: 13px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--luo-ink);
  text-decoration: none;
}

@media (min-width: 1024px) {
  .luo-loja-filtro-link {
    font-size: 14px;
  }
}

.luo-loja-filtro-link.is-active {
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 4px;
}

.luo-loja-filtro-link--serie {
  text-transform: none;
  letter-spacing: normal;
  font-size: 13px;
  padding: 8px 0;
}

.luo-loja-filtro-divider {
  border: none;
  border-top: 1px solid var(--luo-line);
  margin: 8px 0 14px;
}

.luo-loja-filtro-sublist {
  list-style: none;
  margin: 0 0 4px 16px;
  padding: 0;
}

/* 42k. <details>/<summary> nativos — grupo abre/fecha sem JS, `open`
   calculado no servidor (page-loja.tpl/loja-filtro-tree.tpl). O nome
   é um <a> DENTRO do <summary> (clique nele filtra, nunca alterna —
   elemento interativo aninhado escapa do toggle nativo do
   <summary>); o ícone `#chevron` (mesmo símbolo de snipplets/grid/
   categories.tpl) é quem responde pelo abrir/fechar, girando 90°. */
.luo-loja-filtro-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  cursor: pointer;
  list-style: none;
}

.luo-loja-filtro-summary::-webkit-details-marker {
  display: none;
}

.luo-loja-filtro-summary .luo-loja-filtro-link {
  flex: 1;
  min-width: 0;
}

.luo-loja-filtro-chevron {
  width: 7px;
  height: 14px;
  flex-shrink: 0;
  fill: var(--luo-ink);
  transition: transform 0.2s ease;
}

.luo-loja-filtro-group[open] > .luo-loja-filtro-summary .luo-loja-filtro-chevron {
  transform: rotate(90deg);
}

/* 42l. "Filtre sua busca" — filtros nativos de produto (Tamanho/
   Acabamento/Moldura/Preço, o que o Victor ativar em Loja online →
   Filtros). Mesmas classes funcionais do filtro nativo do site
   inteiro (js-filter-checkbox/js-apply-filter/js-remove-filter,
   snipplets/grid/filters.tpl) — só a apresentação é nossa. */
.luo-loja-filtro-cat-label {
  flex: 1;
  padding: 10px 0;
  font-size: 13px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--luo-ink);
}

.luo-loja-nativos-body {
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
}

.luo-loja-checkbox {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 0;
  cursor: pointer;
  font-size: 13px;
  color: var(--luo-body);
}

/* Input nativo continua no DOM (é ele que o JS de plataforma lê pra
   saber o estado) — só escondido visualmente, nunca display:none
   (perderia o foco/leitor de tela). */
.luo-loja-checkbox-input {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

.luo-loja-checkbox-box {
  position: relative;
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  border: 1px solid var(--luo-border);
  border-radius: 2px;
}

.luo-loja-checkbox-input:checked + .luo-loja-checkbox-box {
  border-color: var(--luo-ink);
  background: var(--luo-ink);
}

.luo-loja-checkbox-input:checked + .luo-loja-checkbox-box::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 6px;
  height: 6px;
  background: var(--luo-bg);
}

.luo-loja-checkbox-input:focus-visible + .luo-loja-checkbox-box {
  outline: 2px solid var(--luo-ink);
  outline-offset: 2px;
}

.luo-loja-filtro-count {
  color: var(--luo-faint);
  font-size: 12px;
}

