/*
 * Estilo do site, escrito à mão, sem framework e sem nada vindo de fora.
 *
 * A paleta não está aqui. Ela é impressa pelo layout dentro de um bloco
 * :root, a partir da tabela settings, e este arquivo apenas consome as
 * variáveis. Trocar a cor de uma igreja é editar campo no painel.
 *
 * Escrito primeiro para a tela estreita. As media queries só acrescentam, e
 * nenhuma delas desfaz o que veio antes.
 *
 * CONTRASTE, medido e não presumido. Os números abaixo são razão WCAG 2.1
 * calculada sobre as cores padrão do sistema de design:
 *
 *   branco sobre navy #0A1C33 .......... 17,12:1   AAA
 *   branco sobre marca #16406E ......... 10,54:1   AAA
 *   dourado sobre navy ................. 7,61:1    AAA
 *   navy sobre dourado (botão) ......... 7,61:1    AAA
 *   texto #12253C sobre branco ......... 15,49:1   AAA
 *   texto sobre suave #F4F6F9 .......... 14,31:1   AAA
 *   marca sobre branco (links) ......... 10,54:1   AAA
 *
 * O topo com foto tem régua própria, e ela é AA medida NA ZONA DO TEXTO, e
 * não AAA na foto inteira. O escurecimento ali é composto em camadas, e a
 * tabela dos números de cada zona está junto das camadas, em .topo--foto.
 * O pior caso continua sendo o mesmo: fotografia inteiramente branca.
 *
 *   dourado sobre branco ............... 2,25:1    REPROVA
 *
 * A última linha é a razão de o dourado nunca aparecer como texto sobre fundo
 * claro neste arquivo. Ele entra como fundo de botão com texto navy por cima,
 * e como texto apenas sobre as faixas escuras. Onde serve de enfeite em fundo
 * claro, vem sempre acompanhado de mudança de cor do texto, para não ser o
 * único sinal de estado.
 */

/* ---------------------------------------------------------------- fontes */

/*
 * Poppins e Inter, licença OFL, subset latin, servidas do próprio domínio.
 * Nenhuma requisição sai daqui para fora: não há Google Fonts, não há CDN.
 * As licenças acompanham os arquivos em assets/fonts/OFL-Poppins.txt e
 * OFL-Inter.txt, como a OFL exige.
 *
 * Só os pesos que este arquivo usa foram embutidos. Poppins em 600 e 700
 * para títulos e marca. Inter em 400 para corpo, 600 para rótulos e botões,
 * e 700 porque o <strong> dentro do conteúdo das páginas institucionais
 * precisa de um negrito de verdade, e não de um engordado pelo navegador.
 */

@font-face{
  font-family: "Poppins";
  src: url("../fonts/poppins-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

@font-face{
  font-family: "Poppins";
  src: url("../fonts/poppins-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face{
  font-family: "Inter";
  src: url("../fonts/inter-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face{
  font-family: "Inter";
  src: url("../fonts/inter-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

@font-face{
  font-family: "Inter";
  src: url("../fonts/inter-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* --------------------------------------------------------------- fichas */

:root{
  --fonte-titulo: "Poppins", system-ui, -apple-system, "Segoe UI", sans-serif;
  --fonte-texto: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;

  --raio: 18px;
  --raio-pequeno: 10px;
  --espaco: 1.25rem;
  --largura-maxima: 72rem;
  --largura-texto: 42rem;

  /* Cinza levíssimo para a alternância de seções. É valor de sistema de
     design, não de igreja, por isso mora aqui e não no banco. */
  --cor-suave: #F4F6F9;
  --cor-borda: rgba(18, 37, 60, .12);

  --sombra-baixa: 0 1px 2px rgba(10, 28, 51, .05), 0 4px 12px rgba(10, 28, 51, .06);
  --sombra-alta: 0 2px 6px rgba(10, 28, 51, .08), 0 16px 36px rgba(10, 28, 51, .14);

  --transicao: 180ms cubic-bezier(.2, .6, .3, 1);

  /* Escala tipográfica fluida. Cada passo tem piso e teto, para o texto não
     ficar minúsculo no celular nem gigante no monitor. */
  --t-hero: clamp(2.5rem, 4.2vw + 1.2rem, 4.5rem);
  --t-secao: clamp(1.75rem, 1.6vw + 1.25rem, 2.625rem);
  --t-cartao: clamp(1.125rem, .5vw + 1rem, 1.375rem);
  --t-apoio: clamp(1.0625rem, .5vw + .9rem, 1.25rem);
  --t-meta: .8125rem;
}

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

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

body{
  margin: 0;
  background: var(--cor-fundo);
  color: var(--cor-texto);
  font-family: var(--fonte-texto);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4{
  font-family: var(--fonte-titulo);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -.015em;
  margin: 0 0 .5em;
  text-wrap: balance;
}

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

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

a{ color: var(--cor-marca); }

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

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

.envoltorio{
  width: 100%;
  max-width: var(--largura-maxima);
  margin-inline: auto;
  padding-inline: var(--espaco);
}

.pular{
  position: absolute;
  left: -9999px;
  background: var(--cor-marca);
  color: #fff;
  padding: .75rem 1rem;
  z-index: 60;
}
.pular:focus{ left: 0; top: 0; }

/* --------------------------------------------------------------- botões */

.botao{
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  min-height: 48px;
  padding: .75rem 1.5rem;
  border-radius: 999px;
  border: 2px solid transparent;
  font-family: var(--fonte-texto);
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: transform var(--transicao), box-shadow var(--transicao),
              background-color var(--transicao), border-color var(--transicao),
              color var(--transicao);
}

/* Dourado com texto navy: 7,61:1. É o único uso do dourado em superfície
   grande, e é o que dá a ele função em vez de enfeite. */
.botao--primario{
  background: var(--cor-acento);
  color: var(--cor-base);
  box-shadow: var(--sombra-baixa);
}

.botao--primario:hover,
.botao--primario:focus-visible{
  transform: translateY(-2px);
  box-shadow: var(--sombra-alta);
}

/* Contorno claro, para usar sobre as faixas escuras. */
.botao--contorno{
  background: transparent;
  color: #fff;
  border-color: rgba(255, 255, 255, .55);
}

.botao--contorno:hover,
.botao--contorno:focus-visible{
  background: rgba(255, 255, 255, .12);
  border-color: #fff;
  transform: translateY(-2px);
}

/* ------------------------------------------------------------ cabeçalho */

.cabecalho{
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--cor-fundo);
  border-bottom: 1px solid var(--cor-borda);
  transition: background-color var(--transicao), box-shadow var(--transicao),
              border-color var(--transicao);
}

.cabecalho__interno{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: .875rem;
}

.marca{
  display: inline-flex;
  align-items: center;
  gap: .625rem;
  text-decoration: none;
  color: var(--cor-base);
  font-family: var(--fonte-titulo);
  font-weight: 700;
  font-size: 1.0625rem;
  letter-spacing: -.02em;
  line-height: 1.2;
  transition: color var(--transicao);
}

.marca__logo{ max-height: 2.75rem; width: auto; }

/* Duas logos, e o CSS escolhe qual aparece.
 *
 * O padrão é o cabeçalho SÓLIDO, de fundo claro, e ele vale em três
 * situações: a página interna, o topo da home depois de rolar, e qualquer
 * página para quem tem o JavaScript bloqueado. Nele entra a logo para fundo
 * claro. A de fundo escuro só aparece no cabeçalho transparente sobre a foto
 * do topo, e a regra dela está mais abaixo, junto do resto desse estado.
 *
 * Escolher por display, e não por opacidade, é o que impede as duas de
 * ocuparem espaço ao mesmo tempo e empurrarem o menu. */
.cabecalho--duas-marcas .marca__logo--escuro{ display: none; }
.cabecalho--duas-marcas .marca__logo--claro{ display: block; }

/* Só existe a logo de fundo escuro. O cabeçalho sólido então não clareia:
 * ele fica com a cor da marca, e a logo única continua legível. É a escolha
 * oposta à óbvia, e é de propósito: clarear o fundo e deixar a logo escura
 * ilegível seria trocar um problema visível por um invisível. */
.cabecalho--marca-unica{
  background: var(--cor-marca);
  border-bottom-color: transparent;
}

.cabecalho--marca-unica .marca,
.cabecalho--marca-unica .navegacao__lista a,
.cabecalho--marca-unica .menu-alternar{ color: #fff; }

.cabecalho--marca-unica .menu-alternar{ border-color: rgba(255, 255, 255, .4); }

.cabecalho--marca-unica .navegacao__lista a:hover,
.cabecalho--marca-unica .navegacao__lista a:focus-visible{ border-bottom-color: #fff; }

/* O botão de ação tem fundo próprio e texto escuro, e continua assim: ele é
 * uma superfície clara dentro do cabeçalho escuro, não texto sobre ele. */
.cabecalho--marca-unica .navegacao__acao a{ color: var(--cor-base); }

.menu-alternar{
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: transparent;
  border: 1px solid var(--cor-borda);
  border-radius: var(--raio-pequeno);
  color: inherit;
  cursor: pointer;
  transition: border-color var(--transicao), background-color var(--transicao);
}

.menu-alternar__barras,
.menu-alternar__barras::before,
.menu-alternar__barras::after{
  display: block;
  width: 20px;
  height: 2px;
  background: currentColor;
  border-radius: 2px;
  transition: transform var(--transicao), opacity var(--transicao);
}

.menu-alternar__barras{ position: relative; }
.menu-alternar__barras::before,
.menu-alternar__barras::after{ content: ""; position: absolute; left: 0; }
.menu-alternar__barras::before{ top: -6px; }
.menu-alternar__barras::after{ top: 6px; }

.menu-alternar[aria-expanded="true"] .menu-alternar__barras{ background: transparent; }
.menu-alternar[aria-expanded="true"] .menu-alternar__barras::before{ transform: translateY(6px) rotate(45deg); }
.menu-alternar[aria-expanded="true"] .menu-alternar__barras::after{ transform: translateY(-6px) rotate(-45deg); }

.navegacao__lista{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .25rem 1.25rem;
  font-size: .9375rem;
}

.navegacao__lista a{
  color: var(--cor-texto);
  text-decoration: none;
  font-weight: 500;
  padding-block: .375rem;
  display: inline-block;
  border-bottom: 2px solid transparent;
  transition: color var(--transicao), border-color var(--transicao);
}

.navegacao__lista a:hover,
.navegacao__lista a:focus-visible{
  color: var(--cor-marca);
  border-bottom-color: var(--cor-acento);
}

.navegacao__lista [aria-current="page"]{
  color: var(--cor-marca);
  border-bottom-color: var(--cor-acento);
}

/* O último item do menu é ação, não navegação, e por isso vira botão. */
.navegacao__acao a{
  background: var(--cor-acento);
  color: var(--cor-base) !important;
  border: 0;
  border-radius: 999px;
  padding: .5rem 1.125rem;
  font-weight: 600;
}

.navegacao__acao a:hover,
.navegacao__acao a:focus-visible{
  filter: brightness(1.07);
  border-bottom-color: transparent;
}

/* ---------------------------------------------------------------- topo */

.topo{
  position: relative;
  isolation: isolate;
  color: #fff;
  padding-block: 4.5rem 3.5rem;
  background-color: var(--cor-base);

  /*
   * A ALTURA VEM DA JANELA, e nao da soma dos espacamentos.
   *
   * Ela vinha do conteudo: padding em rem mais o que a igreja escreveu. Isso
   * deu certo por acaso numa altura de tela, 768, onde a soma calhava de
   * encher a primeira dobra. Em 1080 e em 1440 a mesma soma enche uma fracao
   * cada vez menor, e o topo encolhe proporcionalmente sem ninguem ter mudado
   * nada. Altura de dobra e propriedade da JANELA.
   *
   * 100, e a dobra inteira. A versao anterior usava 92, deixando a proxima
   * secao espiar por baixo como convite a rolar. Vista em producao, a fresta
   * leu como sobra, e nao como convite: um pedaco de faixa cortado no pe da
   * tela parece descuido de alinhamento. O convite passou a ser explicito, no
   * indicador de rolagem la embaixo, que diz a mesma coisa sem custar altura.
   *
   * O cabecalho NAO e descontado, e isso tambem e decisao. Com script ele e
   * fixo e flutua por cima, entao nao ocupa altura nenhuma: os 100svh sao
   * exatamente a dobra. Sem script ele entra no fluxo e empurra o topo para
   * baixo, e o pe do topo fica a altura do cabecalho abaixo da dobra: o que se
   * ve continua sendo so topo, e o unico preco e o indicador de rolagem ficar
   * logo abaixo. E o caminho degradado, e ali um convite a rolar sobra, porque
   * o proprio corte ja denuncia continuacao.
   *
   * Descontar exigiria repetir a altura do cabecalho aqui, e altura repetida
   * diverge no dia em que uma das duas muda. E a mesma regra que tirou a
   * ancora paralela da protecao: mesma geometria, nunca contas paralelas.
   *
   * min-height, e nao height, porque o conteudo E o piso: conteudo maior que a
   * janela faz o topo crescer com ele, e nada esmaga nem transborda. Um piso
   * escrito em rem faria o oposto: num celular deitado, de 360 de altura, um
   * piso de 32rem daria um topo maior que a tela inteira.
   *
   * svh, e NUNCA dvh. O dvh acompanha a barra do navegador do celular que
   * aparece e some, e a pagina inteira saltaria a cada rolagem. O svh e o
   * viewport pequeno, o da barra visivel, e por definicao nao muda: e
   * exatamente o problema para o qual ele foi criado. O vh vem antes como
   * recuo para quem nao conhece svh, e navegador que nao conhece ignora a
   * linha seguinte.
   */
  min-height: 100vh;
  min-height: 100svh;

  /*
   * E o conteudo se distribui dentro dela: o bloco de texto se centra no
   * espaco que sobra e a faixa de horarios fica ancorada na base. Sem isto o
   * espaco extra iria todo para baixo do conteudo, e numa tela de 1440 o topo
   * seria um texto no alto com um vazio de 800 pixels embaixo.
   */
  display: flex;
  flex-direction: column;

  /*
   * O recorte é LOAD BEARING, e não arrumação: a proteção do texto transborda
   * o bloco em 15rem para cada lado, e em 1024 a borda direita dela cai em
   * 1152, além da tela. Sem ele, a home ganha barra de rolagem horizontal.
   */
  overflow: hidden;
}

/*
 * Sem foto, um gradiente navy com um sopro da cor da marca no canto. Nunca um
 * bloco chapado.
 */
.topo::before{
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  background:
    radial-gradient(ellipse 90% 70% at 15% 0%, color-mix(in srgb, var(--cor-marca) 85%, transparent) 0%, transparent 65%),
    linear-gradient(160deg, var(--cor-base) 0%, color-mix(in srgb, var(--cor-base) 80%, #000) 100%);
}

/*
 * Com foto, a imagem entra por baixo e o escurecimento por cima, EM CAMADAS.
 *
 * A HISTÓRIA, porque ela explica o desenho
 * -----------------------------------------
 * O primeiro véu era uniforme, 0,80 na foto inteira: cumpria a régua e apagava
 * a fotografia. O segundo foi um scrim lateral linear, com borda reta que a
 * vista encontra e um sopro parelho de 12% que impedia qualquer pedaço da foto
 * de aparecer limpo. O terceiro trocou o véu lateral por uma elipse com curva
 * de suavização, e acertou a FORMA e errou o LUGAR.
 *
 * O erro do terceiro é a razão deste quarto. A elipse era posicionada por uma
 * conta paralela ao layout, --scrim-x, que refazia à mão onde a coluna de
 * texto estaria. A conta supunha a coluna encostada na borda esquerda do
 * envoltório. Ela não está: .topo__interno tem max-width menor que o
 * envoltório e herda o margin-inline auto dele, então o bloco fica CENTRADO, e
 * o centro dele é 50% da tela em qualquer largura. O desvio medido foi de
 * 208px em 1440 e de 112px em 1024: sobrava véu na margem esquerda, onde não
 * há texto, e faltava atrás do fim do título, onde há.
 *
 * A CORREÇÃO É PELA CONSTRUÇÃO, e não por recalibragem. A proteção deixou de
 * ser camada do topo e passou a ser pseudo-elemento DO PRÓPRIO BLOCO DE TEXTO,
 * recuado simetricamente para os quatro lados. O centro dela é o centro do
 * bloco porque é o mesmo retângulo, e não porque duas contas concordam. Mudar
 * a largura, a posição ou o alinhamento da coluna leva a proteção junto, sem
 * ninguém lembrar de ajustar nada, que era exatamente o que faltava.
 *
 * AS CAMADAS, e por que cada uma está onde está
 * ----------------------------------------------
 *   proteção  a elipse do texto, no pseudo-elemento do bloco. Acompanha o
 *             bloco por construção.
 *   piso      a faixa de baixo, no topo, largura toda. Ela é a emenda com a
 *             seção navy que vem logo abaixo, e é a única defesa da faixa de
 *             horários, que agora fica ancorada na base do topo.
 *   teto      só a altura do cabeçalho, no topo, largura toda. O menu e a logo
 *             são brancos e atravessam de ponta a ponta.
 *
 * O PISO PASSOU A TER ALTURA PRÓPRIA, e o teto já tinha. Enquanto ele era uma
 * fração da altura do topo, a altura do topo era do conteúdo, e as duas
 * andavam juntas. Com a altura vindo da janela, uma fração cresce junto com o
 * monitor: os 40% que davam 304 pixels numa tela de 768 dariam 530 numa de
 * 1440, e o escurecimento subiria pela fotografia justamente na tela em que há
 * mais fotografia para mostrar. Isso desfaria a meta desta série de mudanças,
 * que é a foto aparecer.
 *
 * Em pixels, a faixa cobre o mesmo tanto em qualquer altura de tela, e a
 * medição confere que ela cobre a faixa de horários com folga nas quatro
 * alturas de referência.
 */

.topo--foto::before{
  background-image:
    /* 1. piso: a faixa dos horários, e a costura com a seção navy de baixo */
    linear-gradient(to top,
      color-mix(in srgb, var(--cor-base) 84%, transparent) 0%,
      color-mix(in srgb, var(--cor-base) 76%, transparent) 61%,
      color-mix(in srgb, var(--cor-base) 32%, transparent) 80%,
      color-mix(in srgb, var(--cor-base) 9%, transparent) 93%,
      transparent 100%),

    /* 2. teto: só a altura do cabeçalho, que é branco sobre a foto */
    linear-gradient(to bottom,
      color-mix(in srgb, var(--cor-base) 84%, transparent) 0%,
      transparent 100%),

    var(--hero-imagem);

  /* As duas camadas de escurecimento têm altura própria, em rem, e a foto
     cobre o resto. Escurecer proporcionalmente à tela desfaria o desenho. */
  background-size: 100% 18rem, 100% 9rem, cover;
  background-position: bottom center, top center, center;
  background-repeat: no-repeat, no-repeat, no-repeat;
}

.topo__interno{
  max-width: 46rem;

  /* Ocupa a altura que sobrou, para ter espaco livre a distribuir. */
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
}

/*
 * O bloco de texto: titulo, apoio e botoes.
 *
 * As margens automaticas em cima e embaixo tomam para si todo o espaco livre e
 * o dividem em partes iguais, o que centra este bloco no que sobra depois da
 * faixa de horarios. Nao havendo faixa, ele se centra no topo inteiro. Um
 * unico mecanismo cobre os dois casos, sem consulta a estado nenhum.
 */
.topo__conteudo{
  position: relative;
  margin-block: auto;

  /*
   * O quanto a proteção transborda o bloco, e o que decide a forma da elipse.
   *
   * Lateral em rem porque a coluna de texto tem largura em rem: em
   * porcentagem, a elipse cresceria junto com o monitor e voltaria a escurecer
   * a foto inteira num ultralargo. Vertical em porcentagem DA ALTURA DO BLOCO,
   * de propósito: assim a proporção entre o texto e a elipse fica a mesma com
   * um título de uma linha e com um de quatro, e a proteção não afina sozinha
   * quando a igreja escreve mais.
   */
  --protecao-lateral: 15rem;
  --protecao-vertical: 65%;
}

/*
 * A PROTEÇÃO, ancorada no bloco de texto por ser filha dele.
 *
 * O recuo é simétrico nos quatro lados, então o centro deste retângulo é o
 * centro do bloco, sempre. O gradiente é centrado em 50% 50% DELE, e os raios
 * são 50% da própria largura e da própria altura. Não há uma única referência
 * a posição de tela aqui dentro: nada para divergir do layout.
 *
 * As nove paradas aproximam uma curva de suavização, com platô no miolo e
 * queda acelerada depois. Uma reta de duas paradas deixa uma faixa de largura
 * constante que o olho enxerga como banda.
 *
 * A RÉGUA: AA medido NA ZONA DO TEXTO, contra o pior caso de uma fotografia
 * inteiramente branca por baixo. A varredura tem TRÊS eixos: largura de tela,
 * ALTURA DE JANELA e altura do bloco de texto. O segundo entrou quando a
 * altura do topo passou a vir da janela: antes ela vinha do conteúdo e não
 * influía, agora é ela que decide onde o texto para dentro do topo.
 *
 * O pior caso de todos os cruzamentos é sempre o mesmo, janela de 768 com
 * bloco de 200, que é a tela mais baixa com a igreja que escreveu menos:
 *
 *   largura  ponto                        alfa   fundo    razão   exigido
 *   1440     título, os dois extremos     0,62   #687381  4,82:1  3,00
 *   1440     apoio, começo da linha       0,70   #536070  5,41:1  4,50
 *   1440     horários: dia                0,77   #435162  5,12:1  4,50
 *   1440     menu e logo                  0,63   #65707E  5,03:1  4,50
 *   1024     título, os dois extremos     0,62   #687381  4,82:1  3,00
 *   1024     apoio, começo da linha       0,70   #536070  5,41:1  4,50
 *   todas    indicador de rolagem         0,82   #354457  8,15:1  4,50
 *   1024     horários: dia                0,78   #414F61  5,28:1  4,50
 *    768     título, os dois extremos     0,61   #6A7583  4,68:1  3,00  <- pior
 *    768     apoio, começo da linha       0,70   #556171  5,33:1  4,50
 *    768     horários: dia                0,78   #3F4D5F  5,39:1  4,50
 *    390     título, os dois extremos     0,73   #4D5A6B  7,02:1  3,00
 *    390     apoio, os dois extremos      0,76   #465365  6,50:1  4,50
 *    390     horários: dia                0,78   #3F4D5F  5,39:1  4,50
 *
 * A faixa de horários mudou de defensor nesta rodada. Ela morava dentro do
 * bloco de texto e a elipse a cobria; ancorada na base do topo, numa tela alta
 * ela fica a centenas de pixels do bloco, e quem a protege é o PISO sozinho. É
 * por isso que o piso ganhou altura própria calibrada para cobri-la, e é por
 * isso que os números dela subiram: 4,86 no pior caso da rodada anterior,
 * 5,12 agora.
 *
 * E o véu SAI de onde não há texto. Véu médio sobre a área inteira do topo,
 * que é a medida que compara as versões de verdade, na janela de referência de
 * 768: 0,62 -> 0,60 em 1440, 0,74 -> 0,72 em 1024, 0,82 -> 0,80 em 768 e 0,82
 * -> 0,82 em 390. Igual ou mais livre nas quatro.
 *
 * E a promessa das camadas de altura fixa: tela mais alta mostra MAIS foto, e
 * não mais véu. Do mesmo topo em janela de 768 para janela de 1440, o véu
 * médio cai de 0,60 para 0,37 em 1440 de largura, de 0,72 para 0,45 em 1024,
 * de 0,80 para 0,63 em 768 e de 0,82 para 0,67 em 390. Fossem frações da
 * altura, esses números não se moveriam.
 *
 * A TABELA ACIMA NÃO MUDOU quando a fração da altura foi de 92 para 100, e
 * isso não é sorte: cada camada está ancorada no que ela protege. A elipse é
 * filha do bloco de texto e anda com ele; o piso e o teto são faixas de altura
 * própria, coladas na base e no alto. Como nada é medido a partir da altura do
 * topo, mudar a altura do topo não move número nenhum. Era exatamente o que
 * essa ancoragem existia para comprar.
 *
 * Os números acima são recalculados por tests/hero_scrim_test.php a partir
 * destas mesmas paradas e das mesmas regras de layout. Mudou parada aqui, o
 * teste refaz a conta.
 *
 * A sombra de texto mais abaixo é reforço, e nunca a defesa: os números passam
 * sem ela.
 */
.topo--foto .topo__conteudo::before{
  content: "";
  position: absolute;
  inset-block: calc(var(--protecao-vertical) * -1);
  inset-inline: calc(var(--protecao-lateral) * -1);
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(ellipse 50% 50% at 50% 50%,
    color-mix(in srgb, var(--cor-base) 78%, transparent) 0%,
    color-mix(in srgb, var(--cor-base) 77%, transparent) 36%,
    color-mix(in srgb, var(--cor-base) 74%, transparent) 52%,
    color-mix(in srgb, var(--cor-base) 68%, transparent) 63%,
    color-mix(in srgb, var(--cor-base) 55%, transparent) 73%,
    color-mix(in srgb, var(--cor-base) 38%, transparent) 82%,
    color-mix(in srgb, var(--cor-base) 21%, transparent) 90%,
    color-mix(in srgb, var(--cor-base) 8%, transparent) 96%,
    transparent 100%);
}

/*
 * O INDICADOR DE ROLAGEM: o convite que a fresta dos 92% fazia.
 *
 * Ele APONTA, e nao navega. Um link precisaria de destino, e o destino aqui e
 * condicional: programacao, vitrine e eventos somem quando nao ha conteudo, e
 * numa instalacao recem-feita nao existe secao nenhuma depois do topo. Um link
 * para lugar nenhum e pior que nenhum link. Com pointer-events desligado e
 * aria-hidden, ele nao rouba clique, nao entra na ordem de tabulacao e nao
 * anuncia nada a quem usa leitor de tela, que ja sabe rolar sem seta.
 *
 * QUANDO O CONTEUDO VENCE A JANELA, ele nao aparece na chegada, e isso e por
 * construcao: ele fica ancorado na BASE DO TOPO, entao topo mais alto que a
 * tela o empurra para baixo da dobra. Quem chega ve o topo cortado, que ja
 * denuncia continuacao sozinho, e a seta so entra em cena quando o topo
 * termina, que e onde ela de fato aponta para outra coisa.
 *
 * As duas alternativas foram descartadas por motivo. Uma condicao de verdade,
 * "o topo e mais alto que a janela", nao existe em CSS: container query exige
 * container-type size, que aplica contencao de tamanho e faria o topo ignorar
 * o proprio conteudo, matando a regra de o conteudo ser o piso. E JavaScript
 * faria dele requisito, quando a regra da casa e que script e melhoria: um
 * indicador que some para quem bloqueia script e pior que nenhum.
 *
 * A cor e a do texto de apoio, e o contraste dela e medido no ponto em que ela
 * fica, como todo o resto do topo.
 */
.topo__rolagem{
  position: absolute;
  left: 50%;
  bottom: 1.75rem;
  z-index: 1;
  width: .875rem;
  height: .875rem;
  border-right: 2px solid rgba(255, 255, 255, .88);
  border-bottom: 2px solid rgba(255, 255, 255, .88);

  /* translate e transform sao propriedades independentes: a centragem e a
     flutuacao vivem numa, a rotacao na outra, e nenhuma sobrescreve a outra. */
  translate: -50% 0;
  transform: rotate(45deg);
  pointer-events: none;
}

/*
 * A animacao vive DENTRO da preferencia por movimento, e nao fora dela com uma
 * regra de desligar. Sem preferencia declarada, o padrao e o indicador
 * estatico: quem nao pediu movimento nao recebe movimento.
 */
@media (prefers-reduced-motion: no-preference){
  .topo__rolagem{ animation: topo-rolagem 2.4s ease-in-out infinite; }
}

@keyframes topo-rolagem{
  0%, 100%{ translate: -50% 0; }
  50%{ translate: -50% .4375rem; }
}

.topo__titulo{
  font-size: var(--t-hero);
  margin-bottom: .3em;
  letter-spacing: -.03em;
}

/*
 * Reforço, e nunca a defesa. Os números medidos da proteção já passam AA sem
 * ela; esta sombra cobre o caso que a média não enxerga, o detalhe claro da
 * foto bem atrás de uma letra. Só com foto: no gradiente sem foto não há o
 * que reforçar, e sombra ali só sujaria o texto.
 */
.topo--foto .topo__titulo,
.topo--foto .topo__texto,
.topo--foto .topo__horarios{
  text-shadow: 0 1px 3px color-mix(in srgb, var(--cor-base) 45%, transparent);
}

.topo__texto{
  font-size: var(--t-apoio);
  max-width: 34rem;
  color: rgba(255, 255, 255, .88);
  margin-bottom: 2rem;
}

.topo__acoes{
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
  margin-bottom: 0;
}

/* Resumo de horários: a primeira pergunta de quem chega. */
.topo__horarios{
  display: flex;
  flex-wrap: wrap;
  gap: .75rem 2rem;

  /* O vão mínimo até os botões, para telas em que não sobra espaço livre. */
  margin-top: 2.5rem;
  padding-top: 1.75rem;
  border-top: 1px solid rgba(255, 255, 255, .18);
}

.topo__horario{
  display: flex;
  flex-direction: column;
  gap: .125rem;
}

.topo__horario-dia{
  font-size: var(--t-meta);
  text-transform: uppercase;
  letter-spacing: .09em;
  font-weight: 600;
  /* Dourado sobre o véu do hero reprova como texto. Aqui vai branco
     esmaecido, que dá 12,55:1, e o dourado fica para o botão. */
  color: rgba(255, 255, 255, .72);
}

.topo__horario-hora{
  font-family: var(--fonte-titulo);
  font-weight: 600;
  font-size: 1.25rem;
  line-height: 1.2;
}

.topo__horario-nome{
  font-size: .875rem;
  color: rgba(255, 255, 255, .82);
}

/*
 * "+ 2 horários": o resto do dia, sem repetir a agenda no topo.
 *
 * A régua, medida no lugar em que ele fica, que é dentro da faixa de horários,
 * sobre o piso do escurecimento, com a foto mais clara possível por baixo:
 * branco a 0,88 dá 6,71:1 no ponto mais claro que o texto alcança, e 7,90:1 na
 * base da faixa. Passa AA com folga nos dois.
 *
 * O SUBLINHADO É DELIBERADO, e não enfeite. Este é o único link dentro da
 * faixa de horários, cercado de texto que não é link, e sobre uma fotografia
 * que muda de igreja para igreja. Cor sozinha não é afordância: quem não
 * distingue a cor precisa da forma.
 */
.topo__horario-mais{
  margin-top: .1875rem;
  font-size: .8125rem;
  color: rgba(255, 255, 255, .88);
  text-decoration: underline;
  text-underline-offset: .1875rem;
  text-decoration-thickness: 1px;
  transition: color var(--transicao);
}

.topo__horario-mais:hover,
.topo__horario-mais:focus-visible{ color: #fff; }

/* --------------------------------------------------------- programação */

/*
 * Faixa navy contígua ao topo: os dois juntos formam o bloco de chegada.
 * Sem margem, sem borda e sem respiro entre eles, de propósito.
 */
.programacao{
  /*
   * A primeira declaração é reserva, e não enfeite. O navegador que não
   * conhecer color-mix descarta a segunda linha e fica com esta. Sem ela,
   * a faixa perderia o fundo e sobraria texto branco sobre o corpo branco,
   * que é 1:1 de contraste, ou seja, invisível.
   */
  background: var(--cor-base);
  background: color-mix(in srgb, var(--cor-base) 92%, #000);
  color: #fff;
  padding-block: 3rem;
}

.programacao .secao__titulo{ color: #fff; }
.programacao .secao__apoio{ color: rgba(255, 255, 255, .78); }

.programacao__dias{
  display: grid;
  gap: 1rem;
}

/*
 * Cada dia é um cartão de altura igual, com os itens ancorados no topo. É o
 * que evita o buraco visual quando um dia tem quatro itens e o vizinho tem um.
 */
.programacao__dia{
  display: flex;
  flex-direction: column;
  background: rgba(255, 255, 255, .06);
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: var(--raio);
  padding: 1.25rem;
}

.programacao__nome-dia{
  font-family: var(--fonte-texto);
  font-size: var(--t-meta);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--cor-acento);
  margin-bottom: 1rem;
  padding-bottom: .75rem;
  border-bottom: 1px solid rgba(255, 255, 255, .12);
}

.programacao__itens{
  display: flex;
  flex-direction: column;
  gap: 1rem;
  align-content: start;
}

/* Hierarquia corrigida: o nome do culto vem primeiro e maior, o horário é
   apoio, e público e local são metadado discreto. */
.programacao__item{ display: flex; flex-direction: column; gap: .125rem; }

.programacao__evento-nome{
  font-family: var(--fonte-titulo);
  font-weight: 600;
  font-size: 1.0625rem;
  line-height: 1.25;
}

.programacao__hora{
  font-size: .9375rem;
  font-weight: 600;
  color: rgba(255, 255, 255, .88);
  font-variant-numeric: tabular-nums;
}

.programacao__meta{
  font-size: var(--t-meta);
  color: rgba(255, 255, 255, .62);
}

.programacao__meta span + span::before{ content: " · "; }

/* ---------------------------------------------------------------- seções */

.secao{ padding-block: clamp(3rem, 6vw, 5rem); }
.secao--clara{ background: var(--cor-fundo); }
.secao--suave{ background: var(--cor-suave); }

.secao__cabecalho{ max-width: var(--largura-texto); margin-bottom: 2rem; }

.secao__titulo{
  font-size: var(--t-secao);
  color: var(--cor-base);
  margin-bottom: .35em;
}

.secao__apoio{
  font-size: var(--t-apoio);
  color: color-mix(in srgb, var(--cor-texto) 78%, transparent);
  margin-bottom: 0;
}

.secao__mais{ margin-top: 2rem; }

.secao__mais a{
  font-weight: 600;
  text-decoration: none;
  border-bottom: 2px solid var(--cor-acento);
  padding-bottom: 2px;
  transition: color var(--transicao);
}

.secao__mais a:hover{ color: var(--cor-base); }

.vazio{
  color: color-mix(in srgb, var(--cor-texto) 65%, transparent);
  font-style: italic;
}

/* -------------------------------------------------------------- cartões */

.grade{ display: grid; gap: 1.25rem; }

.cartao{
  display: flex;
  flex-direction: column;
  background: var(--cor-fundo);
  border: 1px solid var(--cor-borda);
  border-radius: var(--raio);
  overflow: hidden;
  box-shadow: var(--sombra-baixa);
  transition: transform var(--transicao), box-shadow var(--transicao),
              border-color var(--transicao);
}

.cartao:hover{
  transform: translateY(-3px);
  box-shadow: var(--sombra-alta);
  border-color: color-mix(in srgb, var(--cor-marca) 35%, transparent);
}

/*
 * A imagem do cartão tem TETO de altura, além da proporção.
 *
 * Só com aspect-ratio, um cartão largo dá uma imagem alta na mesma medida, e
 * numa grade de duas colunas em monitor grande o cartão de evento virava um
 * pôster: a foto empurrava título, data e resumo para baixo da dobra, e a
 * lista de eventos deixava de ser lista.
 *
 * A proporção continua mandando enquanto ela couber no teto; passando dali, o
 * teto vence e o object-fit corta pelo centro, que é o corte que preserva o
 * assunto da foto na maioria dos casos.
 */
.cartao__figura{
  margin: 0;
  aspect-ratio: 16 / 9;
  max-height: 11rem;
  background: var(--cor-suave);
  overflow: hidden;
}

.cartao__figura img{ width: 100%; height: 100%; object-fit: cover; object-position: center; }

/*
 * A arte inteira, sem corte nenhum: a variante da home.
 *
 * O teto de 11rem acima resolveu o cartaz na lista longa de /eventos, e
 * continua resolvendo. Na home ele fazia outra coisa: a arte de evento é
 * desenhada em 16 por 9, e o teto cortava justamente a arte que a igreja
 * mandou desenhar nessa proporção. Sem o teto, a caixa É 16 por 9, e a arte
 * de 16 por 9 preenche exatamente, sem sobra e sem falta.
 *
 * O object-fit vira contain, e é decisão, não descuido. Com cover, a arte que
 * NÃO é 16 por 9 (o convite vertical de 1080 por 1350, que é o que sai de
 * celular) voltaria a ser cortada, e a promessa "sem corte" valeria só para
 * quem já acertou a proporção. Com contain, a arte fora de proporção sobra
 * nas laterais, sobre o mesmo cinza que a figura vazia já mostra: perde-se
 * um pouco de preenchimento, e não se perde metade do cartaz.
 */
.cartao__figura--inteira{ max-height: none; }
.cartao__figura--inteira img{ object-fit: contain; }

.cartao__corpo{
  display: flex;
  flex-direction: column;
  gap: .375rem;
  padding: 1.125rem 1.25rem 1.25rem;
  flex: 1 1 auto;
}

.cartao__titulo{
  font-size: var(--t-cartao);
  margin-bottom: 0;
}

.cartao__titulo a{ color: var(--cor-base); text-decoration: none; }
.cartao__titulo a:hover{ color: var(--cor-marca); }

.cartao__meta{
  font-size: var(--t-meta);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--cor-marca);
}

.cartao__texto{
  color: color-mix(in srgb, var(--cor-texto) 80%, transparent);
  margin-bottom: 0;
}

.cartao__rodape{ margin-top: auto; padding-top: .875rem; }

/*
 * Reequilíbrio da home: com a arte inteira, a imagem passou a ser o peso do
 * cartão, e o corpo encolhe para os quatro continuarem lendo como uma grade
 * 2 por 2, e não como quatro cartazes empilhados.
 */
.eventos__lista--dupla .cartao__corpo{ padding: 1rem 1.125rem 1.125rem; gap: .3125rem; }

/* Faixa de cor própria do ministério, a sub-marca da especificação. */
.cartao--acento{ border-top: 4px solid var(--acento, var(--cor-marca)); }

/* ------------------------------------------------------------ destaques */

/*
 * A vitrine da home: banners largos que giram.
 *
 * O SERVIDOR ENTREGA UMA PILHA. Sem JavaScript, .carrossel__faixas é uma lista
 * comum, empilhada, com todos os banners visíveis. Nada aqui esconde nada
 * antes de o script rodar: é ele que põe .carrossel--pronto, e só as regras que
 * dependem dessa classe transformam a pilha em carrossel.
 *
 * Escrever ao contrário, escondendo por padrão e mostrando com script, é o
 * erro que apaga a seção inteira para quem tem o script bloqueado.
 */

.carrossel{ position: relative; }

.carrossel__faixas{
  display: grid;
  gap: 1.25rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

/*
 * O CARTAZ NÃO CARREGA COR FIXA DA CASA, e é isto que corrige a linha navy que
 * apareceu na borda superior dele em produção.
 *
 * A origem era esta regra: o fundo do cartão era var(--cor-base), o navy da
 * casa. Ele vem do desenho antigo, quando a vitrine era um cartão escuro sobre
 * seção clara e esse fundo servia de moldura e de forro das barras laterais da
 * arte fora de proporção.
 *
 * Numa seção que agora é toda derivada da paleta do banner, ele é corpo
 * estranho. E ele aparece porque o cartaz é uma pilha de caixas com cantos
 * arredondados: a arte tem aspect-ratio 16 por 9, que resolve em altura
 * FRACIONÁRIA, e o palco que a segura não tinha fundo próprio. Onde a caixa da
 * arte não cobre a caixa do cartão até o último subpixel, o navy aparece. A
 * borda de luz de um décimo e o arredondamento empilham essa diferença na
 * aresta de cima, e é lá que a linha se vê.
 *
 * A CORREÇÃO É POR CONSTRUÇÃO, e não por acerto de um pixel: o cartão deixa de
 * ter fundo, e quem passa a forrar a arte é o PALCO, com a cor da própria
 * sala. Sobrando subpixel, ele é da cor do fundo atrás dele, e não há linha
 * nenhuma para ver. Arte fora de 16 por 9 deixa de ter barras navy e passa a
 * flutuar na sala, que é o que um cartaz num cinema faz.
 *
 * O que FICA na moldura são os dois neutros: o contorno de luz branco e a
 * sombra escura de assentamento. Nenhum dos dois é cor, os dois são luz e
 * sombra, e é por isso que eles atravessam qualquer paleta.
 */
.faixa{
  position: relative;
  border-radius: var(--raio);
  overflow: hidden;
  box-shadow: var(--sombra-baixa);
  background: transparent;
}

/*
 * A arte, inteira e sem corte, na largura do contêiner.
 *
 * A caixa é 16 por 9 e o object-fit é contain, que é a única combinação em que
 * a promessa "sem corte" vale também para a arte que NÃO veio em 16 por 9. O
 * que sobra nas laterais fica sobre a mesma cor escura do esmaecimento do pé,
 * então a peça continua lendo como uma superfície só.
 *
 * O PALCO e a ARTE são caixas separadas de propósito: o palco recebe o
 * deslocamento do parallax e a arte recebe o Ken Burns. Na mesma caixa, uma
 * transformação sobrescreveria a outra, e não há como somar duas declarações
 * de transform no mesmo elemento.
 */
.faixa__palco{
  position: relative;
  overflow: hidden;
  translate: var(--parallax-x, 0) var(--parallax-y, 0);

  /*
   * O forro da arte é a cor da SALA, e não uma cor da casa. Ele cobre duas
   * coisas: o subpixel que sobra da altura fracionária de 16 por 9, que era a
   * linha navy da borda de cima, e as barras laterais da arte que não veio em
   * 16 por 9. Nos dois casos o que aparece é o fundo do palco, então não
   * aparece nada.
   */
  background-color: var(--palco-fundo, transparent);
}

.faixa__arte{
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: contain;
}

/*
 * A ARTE FICA INTOCADA, e esta é a segunda reversão do texto sobre ela.
 *
 * A primeira versão não escrevia nada por cima; a segunda escreveu, com uma
 * máscara de piso de 0,74 para o texto ter chão; esta terceira tira o texto de
 * cima outra vez, e leva a máscara junto. O motivo veio do navegador de
 * verdade: as artes das igrejas são CARTAZES COMPLETOS, com título, data e
 * selo já desenhados, e o texto em HTML colidia com eles. Escurecer 74% do pé
 * do cartaz para caber o nosso texto apagava o selo de data que a igreja
 * mandou desenhar.
 *
 * E o argumento definitivo não é estético: O PRODUTO NUNCA VAI CONTROLAR A
 * ARTE DO CLIENTE. Qualquer desenho que dependa de saber o que há dentro da
 * imagem é um desenho que quebra na próxima igreja. Cartaz de um lado, painel
 * do outro: as duas superfícies são independentes, e nenhuma precisa saber da
 * outra.
 *
 * Sobre a arte sobram duas camadas, e nenhuma delas escurece para proteger
 * texto, porque não há texto ali:
 *
 *   vinheta   fechamento estético das bordas, recuado e leve
 *   grão      a textura de filme
 *
 * A VINHETA FOI RECUADA nesta rodada. Ela começava em 45% do raio e chegava a
 * 0,22 na borda; um selo de data no canto do cartaz perdia quase um quarto do
 * brilho. Agora ela só começa em 62% e para em 0,16, que é o bastante para
 * fechar a peça e pouco o bastante para o canto continuar legível. A conta é a
 * mesma régua de sempre, e está no teste.
 */
.faixa__palco::after{
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 80% 80% at 50% 50%,
    transparent 62%,
    rgba(0, 0, 0, .07) 84%,
    rgba(0, 0, 0, .16) 100%);
}

/*
 * O GRÃO DE FILME, desenhado pelo próprio navegador.
 *
 * É um SVG de ruído embutido no endereço, sem requisição e sem arquivo: ele
 * pesa algumas centenas de bytes dentro desta folha, e não pode atrasar paint
 * nenhum porque não existe fora dela. Uma oitava só e frequência alta bastam
 * para virar textura; mais oitavas custam pintura e não mudam o resultado.
 *
 * A opacidade é 0,05. Em tela AMOLED, onde o preto é preto de verdade, isso
 * pode ler como sujeira: se ler, o valor desce para 0,03, e é a única decisão
 * deste pacote que depende de olhar numa tela específica.
 */
.faixa--com-arte .faixa__grao{
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: .05;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='r'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='1'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23r)'/%3E%3C/svg%3E");
  background-repeat: repeat;
}

/*
 * O PAINEL, que é a superfície da cor extraída da arte.
 *
 * Ele é o MESMO desenho nas duas orientações: em tela larga fica ao lado do
 * cartaz, em tela estreita fica abaixo dele. Tudo que muda entre as duas é a
 * direção da grade, e é por isso que quase nada aqui está dentro de media
 * query: uma segunda cópia do painel para o celular seria uma segunda peça a
 * manter, e as duas divergiriam na primeira correção.
 *
 * A COR VEM DO SCRIPT, numa variável, e a reserva é o tom claro do próprio
 * sistema visual. A reserva é CLARA de propósito: assim o texto é navy nos
 * dois casos, e não existe um segundo estado, com texto branco, a manter e a
 * medir. Sem script, sem canvas ou com a arte quebrada, o painel fica com o
 * tom do sistema e a faixa continua inteira.
 *
 * OS NÚMEROS, medidos NO PAINEL, nos extremos que o clamp deixa passar. O
 * clamp é saturação 0,45 e mistura com branco 0,55, e é o piso de branco que
 * garante todos eles: nenhuma arte, por mais escura ou mais saturada, produz
 * painel que o navy não vença.
 *
 *   arte de origem                painel     razão     exigido
 *   preta, o mais escuro          #8C8C8C    5,09:1    4,50    <- o pior
 *   azul saturada                 #9191C4    5,75:1    4,50
 *   vermelha saturada             #CD9A9A    7,08:1    4,50
 *   verde saturada                #B9EDB9   12,94:1    4,50
 *   sem cor extraída, a reserva   #F4F6F9   15,81:1    4,50
 *   branca, o mais claro          #FFFFFF   17,12:1    4,50
 *
 * E o custo do que restou sobre a arte: um selo branco no canto do cartaz, o
 * ponto que motivou esta rodada, sai de #FFFFFF para #D6D6D6 por causa da
 * vinheta recuada. Era #C7C7C7 com a vinheta anterior, e seria irreconhecível
 * sob a máscara de piso que saiu.
 *
 * Os números acima são recalculados por tests/carrossel_test.php a partir dos
 * mesmos dois números do clamp. Mudou o clamp, o teste refaz a conta.
 */
.faixa__camadas{
  position: relative;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: .625rem;
  padding: 1.5rem 1.5rem 1.75rem;
  background-color: var(--faixa-cor, var(--cor-suave));
  color: var(--cor-base);
}

/*
 * O texto do painel é navy CHEIO, e os três em branco cheio da rodada anterior
 * saíram junto com a sobreposição: eles existiam porque o fundo era a arte.
 * Aqui o fundo é nosso, com piso de clareza garantido pelo clamp do script, e
 * o navy fecha AA sobre qualquer cor que o clamp deixe passar.
 */
.faixa__chapeu{
  font-size: var(--t-meta);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--cor-base);
  margin-bottom: 0;
}

.faixa--com-arte .faixa__titulo,
.faixa--com-arte .faixa__meta{ color: var(--cor-base); }

/*
 * No banner de gradiente o fundo é a paleta escura da igreja, e ali o texto
 * continua branco, como sempre foi. É a única peça da vitrine com dois
 * estados de cor, e ela os tem porque o fundo dela é outro.
 */
.faixa--gradiente .faixa__chapeu,
.faixa--gradiente .faixa__meta{ color: rgba(255, 255, 255, .72); }

.faixa--gradiente .faixa__texto{ color: rgba(255, 255, 255, .82); }

.faixa__acao .botao{ min-height: 44px; padding: .625rem 1.375rem; }

@media (min-width: 900px){
  /*
   * CARTAZ E PAINEL, lado a lado. Duas áreas, e nenhuma por cima da outra.
   *
   * A proporção é 2 para 1: o cartaz é o assunto e precisa da largura para a
   * arte 16 por 9 não virar uma tira; o painel precisa do bastante para o
   * título respirar em duas ou três linhas, e um terço dá isso sem virar uma
   * coluna de jornal.
   *
   * O PAINEL FICA À DIREITA, e a decisão é de leitura: quem chega olha
   * primeiro a arte, que é o que chama, e depois lê a legenda dela. Invertido,
   * o texto disputaria a primeira olhada com a peça que ele explica.
   *
   * O grão continua sobre o cartaz, e só sobre ele: ele é textura de
   * fotografia, e sobre uma superfície de cor chapada leria como defeito.
   */
  .faixa--com-arte{
    display: grid;
    grid-template-columns: 2fr 1fr;
    align-items: stretch;
  }

  .faixa--com-arte .faixa__palco,
  .faixa--com-arte .faixa__grao{ grid-area: 1 / 1; }

  .faixa--com-arte .faixa__camadas{
    grid-area: 1 / 2;
    padding: 2rem 2.25rem;
  }

  .faixa--com-arte .faixa__titulo{ font-size: var(--t-cartao); }
}

@media (min-width: 1200px){
  .faixa--com-arte .faixa__titulo{ font-size: var(--t-secao); }
}

/* --------------------------------------------- banner sem arte nenhuma */

/*
 * O aviso avulso que ninguém ilustrou não vira caixa vazia: vira um bloco de
 * gradiente na paleta da igreja, com o texto centrado. Sobre a paleta padrão o
 * gradiente vai de #0A1C33 a #16406E, e o branco dá de 17,12:1 a 10,54:1; o
 * texto de apoio, em branco 82%, dá de 11,74:1 a 7,68:1. Passa AA em toda a
 * extensão do gradiente, e não só nas pontas.
 */
.faixa--gradiente{
  display: grid;
  place-items: center;
  min-height: 15rem;
  padding: 3rem 1.5rem;
  text-align: center;
  background:
    radial-gradient(ellipse 80% 120% at 15% 0%, color-mix(in srgb, var(--cor-marca) 90%, transparent) 0%, transparent 70%),
    linear-gradient(140deg, var(--cor-base) 0%, color-mix(in srgb, var(--cor-base) 78%, #000) 100%);
}

.faixa__corpo{
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .625rem;
  max-width: var(--largura-texto);
}

.faixa__meta{
  font-size: var(--t-meta);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: #fff;
  margin-bottom: 0;
}

.faixa__titulo{
  font-size: var(--t-secao);
  margin-bottom: 0;
  color: #fff;
}

.faixa__texto{
  color: rgba(255, 255, 255, .82);
  margin-bottom: 0;
}

.faixa--gradiente .faixa__acao{ margin: .75rem 0 0; }

/*
 * Fora da tela para quem enxerga, presente para quem não enxerga.
 *
 * O título do banner com arte usou isto por uma versão, enquanto não havia
 * texto sobre a arte. Agora ele é visível, e esta continua sendo a ferramenta
 * da casa para quando um rótulo precisar existir só para leitor de tela.
 */
.oculto-visual{
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --------------------------------------------- daqui, só com JavaScript */

/*
 * Tudo abaixo depende de .carrossel--pronto, que o script põe depois de
 * construir as setas e os indicadores. Antes disso, a pilha acima é o que se
 * vê, e ela é um estado completo, não um estado degradado.
 */
.carrossel--pronto{ overflow: hidden; }

/*
 * A TROCA E POR SOBREPOSICAO, e nao mais por deslize lateral.
 *
 * As faixas passam a ocupar a MESMA celula de grade, uma em cima da outra, e a
 * troca e um crossfade. O empilhamento vive atras de .carrossel--pronto, que e
 * classe posta pelo script: sem script a pilha continua sendo pilha de
 * verdade, uma faixa embaixo da outra, e e ela o estado completo.
 *
 * Empilhar em grade, e nao em posicao absoluta, e o que evita salto de
 * layout: a altura da grade e a da faixa mais alta, e ela nao muda na troca.
 */
.carrossel--pronto .carrossel__faixas{
  display: grid;
  gap: 0;
}

/*
 * O padrao, que vale inclusive com movimento reduzido: um crossfade curto de
 * opacidade. Quem pediu menos movimento nao pediu corte seco nem conteudo
 * pulando; pediu que nada se desloque nem escale.
 *
 * A visibilidade troca no FIM do desaparecimento, e nao junto: sem o atraso, a
 * faixa que sai some antes de esmaecer, e o crossfade nao acontece.
 */
.carrossel--pronto .faixa{
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  transition: opacity 300ms linear, visibility 0s linear 300ms;
}

.carrossel--pronto .faixa--ativa{
  opacity: 1;
  visibility: visible;
  transition: opacity 300ms linear, visibility 0s linear 0s;
  z-index: 1;
}

/*
 * A BARRA DE PROGRESSO no indicador ativo.
 *
 * O ponto ativo deixa de ser um traco parado e passa a ser um traco que se
 * enche na duracao do slide. Ele e a unica peca de movimento deste pacote que
 * continua viva com movimento reduzido, e de proposito: ela nao e enfeite, e a
 * informacao de quanto falta, e quem pediu menos movimento nao pediu menos
 * informacao.
 *
 * A pausa e por animation-play-state, e nao por remover a animacao: assim o
 * traco para onde esta e continua de onde parou, que e o que "pausa" quer
 * dizer. Remover reiniciaria do zero a cada saida do ponteiro.
 */
.carrossel__ponto[aria-current="true"]::after{
  content: "";
  position: absolute;
  inset: 50% auto auto calc(50% - 13px);
  translate: 0 -50%;
  transform-origin: left center;
  width: 26px;
  height: 3px;
  border-radius: 999px;
  background: var(--cor-marca);
  pointer-events: none;
  scale: 0 1;
  animation: carrossel-progresso var(--carrossel-duracao, 7000ms) linear forwards;
}

.carrossel--pausado .carrossel__ponto[aria-current="true"]::after{
  animation-play-state: paused;
}

@keyframes carrossel-progresso{
  from{ scale: 0 1; }
  to{ scale: 1 1; }
}

.carrossel__controles{
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin-top: 1.25rem;
}

.carrossel__seta{
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--cor-borda);
  background: var(--cor-fundo);
  color: var(--cor-base);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  transition: background-color var(--transicao), border-color var(--transicao);
}

.carrossel__seta:hover{
  background: var(--cor-suave);
  border-color: color-mix(in srgb, var(--cor-marca) 40%, transparent);
}

.carrossel__pontos{ display: flex; align-items: center; gap: .5rem; }

/*
 * O ponto tem alvo de 44 por 44, que é o mínimo de toque, e a marca visível
 * dentro dele é menor. Encolher o alvo junto com a marca deixaria o indicador
 * quase impossível de acertar com o dedo.
 */
.carrossel__ponto{
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  position: relative;
}

.carrossel__ponto::before{
  content: "";
  position: absolute;
  inset: 50% auto auto 50%;
  transform: translate(-50%, -50%);
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--cor-base) 28%, transparent);
  transition: background-color var(--transicao), width var(--transicao);
}

.carrossel__ponto[aria-current="true"]::before{
  background: var(--cor-marca);
  width: 26px;
  border-radius: 999px;
}

/* Um banner só: sem seta, sem indicador, sem giro. O script nem chega a
   construir os controles, e a regra abaixo é a rede de segurança. */
.carrossel--unica .carrossel__controles{ display: none; }

/*
 * DAQUI PARA BAIXO, SO COM MOVIMENTO PERMITIDO.
 *
 * Tudo que este bloco acrescenta e movimento: Ken Burns, o crossfade longo com
 * escala, a entrada tipografica em camadas, o deslize do fundo reativo e o
 * drift do celular. Com "reduzir movimento" pedido pelo sistema, nada disto
 * existe, e o que fica e a vitrine inteira funcionando: troca por crossfade de
 * 300 milissegundos, setas, indicadores, teclado e a barra de progresso.
 *
 * A forma e sempre esta no projeto: animar DENTRO de no-preference, e nao
 * animar sempre e desligar em reduce. A diferenca e o padrao de quem nao
 * declarou preferencia nenhuma.
 */
@media (prefers-reduced-motion: no-preference){
  /* O crossfade longo, com a escala entrando junto. */
  .carrossel--pronto .faixa{
    scale: 1.02;
    transition: opacity 900ms ease, scale 900ms ease, visibility 0s linear 900ms;
  }

  .carrossel--pronto .faixa--ativa{
    scale: 1;
    transition: opacity 900ms ease, scale 900ms ease, visibility 0s linear 0s;
  }

  /*
   * KEN BURNS: a arte entra em 1,08 e assenta em 1,00 ao longo de oito
   * segundos. A animacao esta na faixa ATIVA, entao ela reinicia sozinha
   * quando a classe e reposta, sem script por quadro e sem relogio proprio.
   *
   * A origem do movimento alterna por posicao, para duas faixas seguidas nao
   * fazerem o mesmo caminho: a impar sai do alto a esquerda, a par do baixo a
   * direita.
   */
  .carrossel--pronto .faixa--ativa .faixa__arte{
    animation: carrossel-ken-burns 8s cubic-bezier(.25, .1, .25, 1) forwards;
    will-change: transform;
  }

  .carrossel--pronto .faixa:nth-child(odd).faixa--ativa .faixa__arte{ transform-origin: 30% 40%; }
  .carrossel--pronto .faixa:nth-child(even).faixa--ativa .faixa__arte{ transform-origin: 70% 60%; }

  /* No celular a arte assenta mais rapido, porque o slide tambem e mais curto. */
  @media (max-width: 899px){
    .carrossel--pronto .faixa--ativa .faixa__arte{ animation-duration: 6s; }
  }

  /*
   * A ENTRADA TIPOGRAFICA, uma vez por troca e nunca em laco. Cada camada sobe
   * catorze pixels e aparece em meio segundo, com cento e vinte milissegundos
   * entre uma e outra. O atraso sai da posicao do elemento, e nao de script.
   */
  .carrossel--pronto .faixa--ativa .faixa__camadas > *{
    animation: carrossel-entrada 500ms ease-out backwards;
  }

  .carrossel--pronto .faixa--ativa .faixa__camadas > *:nth-child(1){ animation-delay: 120ms; }
  .carrossel--pronto .faixa--ativa .faixa__camadas > *:nth-child(2){ animation-delay: 240ms; }
  .carrossel--pronto .faixa--ativa .faixa__camadas > *:nth-child(3){ animation-delay: 360ms; }
  .carrossel--pronto .faixa--ativa .faixa__camadas > *:nth-child(4){ animation-delay: 480ms; }

  /*
   * O DRIFT DO CELULAR, que substitui o parallax de ponteiro onde nao ha
   * ponteiro. Ele vive no palco, como o parallax, e e animacao do CSS: o
   * navegador a suspende sozinho em aba oculta, sem ninguem precisar avisar.
   */
  @media (hover: none){
    .carrossel--pronto .faixa--ativa .faixa__palco{
      animation: carrossel-drift 10s ease-in-out infinite alternate;
    }
  }

  /* A cor do painel entra em fade quando a extracao termina, na mesma duracao
     do crossfade: ela chega depois do load, e aparecer de estalo seria um
     susto no meio da leitura. */
  .faixa__camadas{ transition: background-color 900ms ease; }

  /*
   * E o palco acompanha o crossfade: a sala muda de cor no mesmo tempo em que
   * o cartaz troca, e nao um instante antes nem depois. Com movimento
   * reduzido, a cor nova simplesmente aparece: quem pediu menos movimento nao
   * pediu menos cor.
   */
  .secao--palco,
  .secao--palco::before{ transition: background-color 900ms ease, background 900ms ease; }
}

@keyframes carrossel-ken-burns{
  from{ transform: scale(1.08); }
  to{ transform: scale(1); }
}

@keyframes carrossel-entrada{
  from{ opacity: 0; translate: 0 14px; }
  to{ opacity: 1; translate: 0 0; }
}

@keyframes carrossel-drift{
  from{ translate: 0 0; }
  to{ translate: 8px 0; }
}

/*
 * O PALCO ESCURO REATIVO: a sala de cinema do cartaz.
 *
 * ISTO REVERTE, POR DECISÃO DO DONO, a remoção do fundo reativo da rodada
 * passada. Naquela rodada a cor foi tirada da seção porque, esmaecida atrás de
 * um cartão sobre fundo branco, ela dava duas versões da mesma cor na mesma
 * faixa e nenhuma delas ajudava. O que o navegador mostrou depois foi outra
 * coisa: com a vitrine funcionando, a seção em branco chapado APAGA o
 * conjunto. Um cartaz precisa de sala escura.
 *
 * O fundo deixa de ser claro fixo e passa a ser um tom PROFUNDO derivado da
 * mesma cor que o painel usa.
 *
 * E ELE PRESERVA O MATIZ DA ARTE. A primeira versão do palco misturava 78% do
 * navy da casa com a cor extraída, e o resultado era profundo e CINZENTO:
 * misturar tira o matiz. Laranja com navy dá ardósia, vermelho com navy dá
 * vinho apagado, e toda arte terminava na mesma família de azul acinzentado.
 * Profundidade sem matiz não é a cor da arte, é cinza.
 *
 * A conta migrou para o script, em HSL, e é lá que ela mora inteira: matiz da
 * arte intocado, saturação com piso e teto, luminosidade fixa e grave. O CSS
 * recebe duas cores prontas e não faz conta nenhuma sobre elas.
 *
 * O QUE FICOU AQUI é a definição de "sem cor", e ela continua num lugar só: a
 * reserva de --palco-cor é o navy da base, e o facho cai para o fundo, que cai
 * para o navy. Uma cadeia, uma decisão. O script remove as duas propriedades
 * juntas, e nunca escreve valor de reserva nenhum.
 *
 * ARTE ACROMÁTICA, o cartaz quase branco ou quase cinza, não tem matiz a
 * preservar: girar o matiz de um cinza produz cor inventada. Abaixo do limiar
 * de saturação de origem, o script não escreve nada, e o palco cai para o navy
 * da casa pela mesma cadeia do "sem cor".
 *
 * O FACHO é mais claro que o fundo, e é ele que desenha a luz de palco atrás
 * do conjunto cartaz e painel.
 *
 * SEM filter: blur, e isso é a lição do desfoque de 28 pixels que saiu duas
 * rodadas atrás: filtro em área grande custa uma passada de pintura fora da
 * tela, do tamanho da seção, a cada quadro em que algo ali muda. A suavidade
 * aqui vem de ONZE PARADAS de gradiente radial, que o navegador resolve na
 * mesma passada em que pinta o fundo. O custo é uma pintura de gradiente por
 * elemento, sem buffer intermediário e sem filtro.
 *
 * OS NÚMEROS, varrendo os matizes no teto de saturação, que é o pior caso: o
 * texto do palco é claro, então o perigo é o matiz de maior luminância, e ele
 * é o amarelo. Medido no FACHO, que é o ponto mais claro da seção:
 *
 *   matiz              facho              texto claro   exigido
 *   amarelo, 60        rgb(114, 114, 29)  5,07:1        4,50    <- o pior
 *   verde-lima, 90     rgb(71, 114, 29)   5,69:1        4,50
 *   ciano, 180         rgb(29, 114, 114)  5,67:1        4,50
 *   verde, 120         rgb(29, 114, 29)   6,04:1        4,50
 *   laranja, 30        rgb(114, 71, 29)   7,97:1        4,50
 *   azul, 210          rgb(29, 71, 114)   9,56:1        4,50
 *   magenta, 300       rgb(114, 29, 114)  9,84:1        4,50
 *   vermelho, 0        rgb(114, 29, 29)  11,00:1        4,50
 *   sem matiz, ou sem cor: o navy da casa               17,12:1
 *
 * A LUMINOSIDADE DO FACHO É O NÚMERO QUE A RÉGUA FIXOU. Começou em 0,33, e ali
 * o amarelo dava 3,82:1, abaixo de AA. Desceu até 0,28. O teto desceu, e não a
 * régua.
 *
 * Os números são recalculados por tests/carrossel_test.php a partir dos mesmos
 * limites do script. Mudou o clamp lá, o teste refaz a conta.
 */
.secao--palco{
  position: relative;
  isolation: isolate;

  /*
   * A cadeia de reserva, e é ela que define "sem cor" num lugar só: sem a cor
   * do palco, o navy da casa; sem a do facho, o próprio fundo, que já caiu
   * para o navy. O script escreve as duas ou remove as duas.
   */
  --palco-fundo: var(--palco-cor, var(--cor-base));
  --palco-facho: var(--palco-facho-cor, var(--palco-fundo));

  background-color: var(--palco-fundo);
  color: #fff;
}

/*
 * A EMENDA COM AS VIZINHAS É CORTE FRANCO, e não transição suave.
 *
 * Acima do palco vem a programação, que já é navy: as duas se encontram sem
 * costura nenhuma, porque são a mesma família de tom. Abaixo vem a lista de
 * eventos, que é clara, e ali a mudança é uma linha limpa. Uma transição
 * suave partindo de uma cor VARIÁVEL seria um degradê diferente a cada slide,
 * impossível de calibrar e impossível de medir: escuro que desbota para branco
 * sem ninguém saber em que tom, o que é a definição de emenda suja.
 */
.secao--palco .secao__titulo,
.secao--palco .secao__apoio{ color: #fff; }

.secao--palco::before{
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(ellipse 72% 62% at 50% 56%,
    var(--palco-facho) 0%,
    var(--palco-facho) 16%,
    color-mix(in srgb, var(--palco-facho) 72%, transparent) 38%,
    color-mix(in srgb, var(--palco-facho) 42%, transparent) 56%,
    color-mix(in srgb, var(--palco-facho) 20%, transparent) 72%,
    color-mix(in srgb, var(--palco-facho) 7%, transparent) 87%,
    transparent 100%);
  background-color: transparent;
}

/*
 * O CARTAZ SOBRE O PALCO: a sombra clara do sistema some numa superfície
 * escura, e sem ela o cartão flutua sem peso. Aqui ele ganha uma sombra
 * profunda, que é o que separa o objeto iluminado do fundo, e uma borda de luz
 * de um décimo, que dá a ele um contorno sem virar moldura.
 */
.secao--palco .faixa{
  box-shadow: 0 18px 48px rgba(0, 0, 0, .45);
  border: 1px solid rgba(255, 255, 255, .10);
}

/*
 * SETAS E INDICADORES foram desenhados para fundo claro: círculo branco, borda
 * cinza e seta navy. Sobre o palco escuro eles viravam dois pontos brilhantes
 * disputando atenção com o cartaz, e o traço de progresso, que era da cor da
 * marca, sumia no escuro.
 *
 * Aqui eles passam a ser desenhados em luz: contorno claro e seta branca, com
 * o preenchimento aparecendo só no toque do ponteiro. Os números, sobre o
 * facho, que é o fundo mais claro possível:
 *
 *   a seta, branca                          5,07:1   exigido 4,50
 *   o contorno da seta, branco a 72%        3,50:1   exigido 3,00 (não textual)
 *   o traço de progresso, branco            5,07:1   exigido 3,00 (não textual)
 *
 * Os três melhoraram com o clamp novo, e não por acaso: o pior facho deste
 * clamp é mais escuro que o da mistura com navy, porque a luminosidade agora é
 * fixa e grave em vez de sair de uma média com a cor clara do painel.
 */
.secao--palco .carrossel__seta{
  background: transparent;
  border-color: rgba(255, 255, 255, .72);
  color: #fff;
}

.secao--palco .carrossel__seta:hover{
  background: rgba(255, 255, 255, .16);
  border-color: #fff;
}

.secao--palco .carrossel__ponto::before{ background: rgba(255, 255, 255, .45); }

.secao--palco .carrossel__ponto[aria-current="true"]::before{ background: #fff; }

.secao--palco .carrossel__ponto[aria-current="true"]::after{ background: #fff; }

/* -------------------------------------------------------------- eventos */

.eventos__lista{ display: grid; gap: 1.25rem; }

.evento__data{
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-width: 3.5rem;
  padding: .5rem .625rem;
  border-radius: var(--raio-pequeno);
  background: var(--cor-marca);
  color: #fff;
  line-height: 1.05;
}

.evento__dia{ font-family: var(--fonte-titulo); font-size: 1.375rem; font-weight: 700; }
.evento__mes{ font-size: .6875rem; text-transform: uppercase; letter-spacing: .06em; }

.evento__cabecalho{ display: flex; align-items: flex-start; gap: .875rem; }

.evento--passado{ opacity: .78; }

/* ------------------------------------------------------------------ contato */

/*
 * O bloco de contato: a página /contato inteira, e o fim das páginas
 * institucionais que ligarem o interruptor. Uma folha de estilo só para os
 * dois, porque é o mesmo bloco.
 *
 * Duas colunas quando há espaço, com o mapa ocupando a maior: endereço e
 * telefone se leem em poucas linhas, e o mapa precisa de área para servir de
 * mapa. Sem mapa, os dados ocupam a largura toda em vez de deixarem um vazio
 * do lado direito.
 */
.contato{ display: grid; gap: 1.75rem; }

.contato__dados{ display: grid; gap: 1.5rem; align-content: start; }

.contato__rotulo{
  font-size: var(--t-meta);
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--cor-marca);
  margin-bottom: .5rem;
}

.contato__endereco{ font-style: normal; line-height: 1.6; margin: 0; }

.contato__lista,
.contato__redes{ list-style: none; padding: 0; margin: 0; display: grid; gap: .625rem; }

.contato__lista li{ display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem; }

.contato__tipo{
  font-size: var(--t-meta);
  color: color-mix(in srgb, var(--cor-texto) 65%, transparent);
  min-width: 5.5rem;
}

.contato__redes{ grid-auto-flow: column; justify-content: start; gap: 1.25rem; }

/*
 * O quadro do mapa. A proporção evita o pulo de layout enquanto ele carrega, e
 * a moldura arredondada o costura ao resto da página em vez de deixá-lo como
 * um retângulo estranho colado no fim.
 */
.contato__mapa{
  aspect-ratio: 4 / 3;
  border-radius: var(--raio);
  overflow: hidden;
  border: 1px solid var(--cor-borda);
  background: var(--cor-suave);
}

.contato__mapa iframe{ width: 100%; height: 100%; border: 0; display: block; }

/* O bloco no fim de uma página institucional, separado do texto. */
.artigo__contato{
  margin-top: 3rem;
  padding-top: 2rem;
  border-top: 1px solid var(--cor-borda);
}

.artigo__contato-titulo{ font-size: var(--t-cartao); margin-bottom: 1.5rem; color: var(--cor-base); }

/* ------------------------------------------------------------------ agenda */

/*
 * A pagina /programacao. A faixa da home mostra a mesma informacao em forma
 * compacta; aqui ela e lida com calma, entao o horario ganha coluna propria e
 * o local e o publico saem de metadado miudo para linha legivel.
 */
.agenda{ display: grid; gap: 2.5rem; }

.agenda__nome-dia{
  font-size: var(--t-cartao);
  color: var(--cor-base);
  padding-bottom: .5rem;
  margin-bottom: 1rem;
  border-bottom: 2px solid var(--cor-acento);
}

.agenda__itens{ display: grid; gap: .75rem; }

.agenda__item{
  display: grid;
  gap: .25rem 1.25rem;
  padding: 1rem 1.25rem;
  background: var(--cor-fundo);
  border: 1px solid color-mix(in srgb, var(--cor-texto) 12%, transparent);
  border-radius: var(--raio);
  transition: border-color var(--transicao), transform var(--transicao);
}

.agenda__item:hover{
  border-color: color-mix(in srgb, var(--cor-marca) 35%, transparent);
  transform: translateY(-1px);
}

/*
 * O horario e o que a pessoa procura primeiro, entao ele vem antes na leitura
 * e em coluna fixa na tela larga. Na estreita ele volta para cima do nome, em
 * vez de espremer as duas colunas.
 */
.agenda__hora{
  font-family: var(--fonte-titulo);
  font-weight: 600;
  color: var(--cor-marca);
  margin-bottom: 0;
  font-variant-numeric: tabular-nums;
}

.agenda__nome{ font-size: 1.0625rem; margin-bottom: .125rem; color: var(--cor-base); }

.agenda__meta{
  font-size: var(--t-meta);
  color: color-mix(in srgb, var(--cor-texto) 70%, transparent);
  margin-bottom: 0;
}

.agenda__meta span + span::before{ content: " · "; }

@media (min-width: 40rem){
  .agenda__item{ grid-template-columns: 8.5rem 1fr; align-items: baseline; }
}

/* -------------------------------------------------------------- artigo */

.artigo{ padding-block: clamp(2.5rem, 5vw, 4rem); }

.artigo__cabecalho{ margin-bottom: 2rem; }

.artigo__titulo{ font-size: var(--t-secao); color: var(--cor-base); }

.artigo__apoio{
  font-size: var(--t-apoio);
  color: color-mix(in srgb, var(--cor-texto) 78%, transparent);
}

.artigo__voltar{ display: inline-block; margin-bottom: 1.5rem; font-size: .9375rem; }

/*
 * A imagem do evento, na página dele.
 *
 * Aqui ela usava .cartao__figura com um aspect-ratio de 21 por 9 escrito no
 * atributo style, e herdava junto o teto de 11rem que existe para o cartão da
 * lista. O resultado era a arte cortada duas vezes: primeiro para 21 por 9,
 * depois para caber em 176 pixels de altura. Na página do próprio evento,
 * onde a arte é o assunto, isso é exatamente o oposto do que se quer.
 *
 * Esta figura não impõe proporção nenhuma: a altura sai da largura pela
 * proporção natural do arquivo, e não há caixa para estourar nem para cortar.
 * O teto de largura é a coluna de leitura, a mesma da prosa, para a página
 * inteira ficar em um alinhamento só.
 */
.artigo__figura{
  margin: 0 0 2rem;
  max-width: var(--largura-texto);
  border-radius: var(--raio);
  overflow: hidden;
  background: var(--cor-suave);
}

.artigo__figura img{ display: block; width: 100%; height: auto; }

/* Conteúdo vindo do painel. Só aqui o HTML do banco é impresso cru, e por
   isso só aqui as tags precisam de estilo próprio. */
.prosa{ max-width: var(--largura-texto); }
.prosa h2{ font-size: 1.5rem; color: var(--cor-base); margin-top: 2rem; }
.prosa h3{ font-size: 1.25rem; color: var(--cor-base); margin-top: 1.5rem; }
.prosa p{ margin-bottom: 1.15em; }
.prosa strong{ font-weight: 700; }
.prosa ul, .prosa ol{ margin: 0 0 1.15em 1.25rem; }
.prosa ul{ list-style: disc; }
.prosa ol{ list-style: decimal; }
.prosa li{ margin-bottom: .35em; }
.prosa a{ color: var(--cor-marca); }
.prosa blockquote{
  margin: 1.5rem 0;
  padding: .25rem 0 .25rem 1.25rem;
  border-left: 4px solid var(--cor-acento);
  color: color-mix(in srgb, var(--cor-texto) 82%, transparent);
}

/* ------------------------------------------------------------------ 404 */

.erro{
  padding-block: clamp(3.5rem, 9vw, 7rem);
  text-align: center;
}

.erro__codigo{
  font-family: var(--fonte-titulo);
  font-size: clamp(3.5rem, 12vw, 6rem);
  font-weight: 700;
  line-height: 1;
  color: var(--cor-marca);
  opacity: .22;
  margin-bottom: .25rem;
}

.erro__titulo{ font-size: var(--t-secao); color: var(--cor-base); }

.erro__texto{
  font-size: var(--t-apoio);
  max-width: 34rem;
  margin-inline: auto;
  color: color-mix(in srgb, var(--cor-texto) 80%, transparent);
  margin-bottom: 2rem;
}

.erro__acoes{ display: flex; flex-wrap: wrap; gap: .75rem; justify-content: center; }

.erro .botao--contorno{
  color: var(--cor-marca);
  border-color: color-mix(in srgb, var(--cor-marca) 45%, transparent);
}

.erro .botao--contorno:hover{
  background: color-mix(in srgb, var(--cor-marca) 8%, transparent);
  border-color: var(--cor-marca);
}

/* ------------------------------------------------------------------ rodapé */

.rodape{
  background: var(--cor-base);
  color: #fff;
  padding-block: 3rem 1.5rem;
}

.rodape__interno{ display: grid; gap: 2rem; }

.rodape__titulo{
  font-family: var(--fonte-texto);
  font-size: var(--t-meta);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--cor-acento);
  margin-bottom: .75rem;
}

.rodape__nome{
  font-family: var(--fonte-titulo);
  font-weight: 700;
  font-size: 1.1875rem;
  margin-bottom: .25em;
}

.rodape__frase,
.rodape__nota,
.rodape__endereco{
  color: rgba(255, 255, 255, .8);
  font-style: normal;
  margin-bottom: 0;
}

.rodape__frase{ margin-bottom: .5em; }

.rodape__contatos{ display: grid; gap: .375rem; color: rgba(255, 255, 255, .8); }
.rodape__contatos a{ color: rgba(255, 255, 255, .88); text-decoration: none; }
.rodape__contatos a:hover{ color: var(--cor-acento); text-decoration: underline; }

.rodape__assinatura{
  max-width: var(--largura-maxima);
  margin: 2.5rem auto 0;
  padding: 1.25rem var(--espaco) 0;
  border-top: 1px solid rgba(255, 255, 255, .15);
  font-size: var(--t-meta);
  color: rgba(255, 255, 255, .6);
  margin-bottom: 0;
}

/* --------------------------------------------- transmissao ao vivo */

/*
 * O SELO "AO VIVO", e a seção que ele aponta.
 *
 * O VERMELHO É #E02424, e ele foi escolhido pela régua, e não pelo gosto: é o
 * vermelho mais vivo que ainda fecha AA com texto branco por cima, em 4,72:1.
 * Vermelhos mais vivos que ele reprovam: o #FF0000 puro dá 4,00:1, abaixo do
 * piso. Vermelhos mais escuros fechariam com folga e deixariam de parecer
 * "ao vivo", que é a única coisa que este selo precisa comunicar de longe.
 *
 * O ANEL É O MESMO PAR NEUTRO DO BOTÃO DE WHATSAPP, e pelo mesmo teorema:
 * dois fios opacos, branco e preto, cujo produto das razões contra QUALQUER
 * fundo é sempre 21, então a maior das duas nunca fica abaixo da raiz de 21,
 * que é 4,58:1. Ele existe porque o selo mora em superfícies que o produto não
 * escolhe: o cabeçalho claro, o cabeçalho na cor da marca, o cabeçalho
 * transparente sobre a foto do topo, e a seção da home, cujo fundo a igreja
 * edita. Contra o cabeçalho na cor da marca padrão, o vermelho sozinho dá
 * 2,23:1, e é esse número que obriga o anel a existir.
 *
 * UM ESTADO SÓ, em todas as superfícies. A alternativa seria medir cada uma e
 * escolher, e superfície editável não se mede: ela muda depois que a medição
 * foi feita.
 */
.selo-vivo{
  display: inline-flex;
  align-items: center;
  gap: .4375rem;

  /* Encosta na marca e empurra o menu para a direita. Sem isto, o
     space-between do cabeçalho o jogaria para o meio da barra. */
  margin-inline-end: auto;

  padding: .3125rem .625rem;
  border-radius: 999px;

  background: #E02424;
  color: #fff;

  font-family: var(--fonte-texto);
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .08em;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;

  box-shadow: 0 0 0 1px #fff, 0 0 0 2px #000;
}

.selo-vivo__ponto{
  width: .4375rem;
  height: .4375rem;
  border-radius: 50%;
  background: #fff;
}

/*
 * A pulsação vive DENTRO da preferência por movimento, como todo movimento
 * deste projeto. Sem a preferência declarada, o ponto fica aceso e parado:
 * quem não pediu movimento não recebe movimento, e o selo continua dizendo a
 * mesma coisa.
 */
@media (prefers-reduced-motion: no-preference){
  .selo-vivo__ponto{ animation: selo-vivo-pulso 1.6s ease-in-out infinite; }
}

@keyframes selo-vivo-pulso{
  0%, 100%{ opacity: 1; scale: 1; }
  50%{ opacity: .45; scale: .72; }
}

/*
 * Dentro do título da seção ele é etiqueta, e não link: quem já está na seção
 * não precisa de um link para ela. O tamanho acompanha o título, e o anel
 * continua, porque o fundo da seção é a cor que a igreja escolheu.
 */
.selo-vivo--secao{
  margin-inline-end: .625rem;
  vertical-align: middle;
}

.ao-vivo__quadro{
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--raio);
  overflow: hidden;
  box-shadow: var(--sombra-alta);
  background: var(--cor-base);
}

.ao-vivo__quadro iframe{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.ao-vivo__acao{ margin-top: 1.5rem; margin-bottom: 0; }

/* ------------------------------------ botao flutuante de WhatsApp */

/*
 * O BOTÃO FLUTUANTE DE WHATSAPP.
 *
 * O verde é #25D366, o da marca, e ele NÃO se recolore. É logomarca, e não cor
 * do sistema de design: recolorir para fechar a régua daria um botão que
 * ninguém reconhece, que é o oposto do que ele existe para fazer. Decisão do
 * dono, registrada aqui porque é justamente onde alguém iria "consertar".
 *
 * A consequência medida, e assumida: o glifo branco sobre o verde dá 1,98:1, e
 * o verde sobre página clara dá os mesmos 1,98:1. Nenhum dos dois é o que
 * carrega o significado: quem carrega é o aria-label, e quem carrega a borda é
 * o anel, medido logo abaixo. Este par também não entra em App\Helpers\Palette
 * de propósito: aquela auditoria mede a paleta que a igreja escolhe, e nem o
 * verde nem o branco daqui saem de settings.
 *
 * O ANEL É NEUTRO, E A REGRA VENCE A TABELA. São dois fios opacos, branco e
 * preto, e a garantia não é uma lista de fundos conferidos: para branco e
 * preto opacos, o produto das duas razões contra QUALQUER fundo é sempre
 * exatamente 21, então a maior das duas nunca fica abaixo da raiz de 21, que
 * é 4,58:1. Seja qual for a superfície por trás, um dos dois fios se destaca
 * dela, e os dois se destacam um do outro em 21:1.
 *
 * Medido nos fundos que o produto tem hoje:
 *
 *   preto sobre página clara .................... 21,00:1
 *   branco sobre o rodapé navy .................. 17,12:1
 *   branco sobre o facho mais claro do palco ..... 5,07:1
 *   preto sobre o facho mais claro do palco ...... 4,14:1
 *
 * O facho do palco é o pior fundo que o produto tem, porque é a superfície
 * mais clara que ainda não é branca, e mesmo lá os DOIS fios passam de 3:1.
 *
 * O afastamento soma a área segura do aparelho, para o botão não cair sob a
 * barra do iPhone nem sob o canto arredondado da tela.
 *
 * O z-index é 40, e a escolha é deliberada: o cabeçalho é 50 e o menu móvel
 * mora dentro dele, então o menu aberto cobre o botão, e nunca o contrário. O
 * atalho "ir para o conteúdo" fica acima dos dois, em 60, porque atalho de
 * teclado coberto é atalho que não existe.
 */
.whatsapp{
  position: fixed;
  z-index: 40;
  right: calc(1.25rem + env(safe-area-inset-right, 0px));
  bottom: calc(1.25rem + env(safe-area-inset-bottom, 0px));

  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 60px;
  border-radius: 50%;

  background: #25D366;
  color: #fff;
  text-decoration: none;

  /* Os dois fios neutros, e a sombra de assentamento. */
  box-shadow:
    0 0 0 1px #fff,
    0 0 0 2px #000,
    0 8px 20px rgba(0, 0, 0, .30);
}

.whatsapp__glifo{ width: 30px; height: 30px; }

/*
 * O crescimento no toque e no foco vive dentro da preferência por movimento,
 * como todo movimento deste projeto. Sem a preferência o botão não cresce, e
 * continua inteiro: o que muda de estado no foco é o anel, que não é animação.
 */
@media (prefers-reduced-motion: no-preference){
  .whatsapp{ transition: transform var(--transicao); }

  .whatsapp:hover,
  .whatsapp:focus-visible{ transform: scale(1.08); }
}

/*
 * O FOCO REPETE A MESMA REGRA POR FORA DO DOURADO.
 *
 * O anel de foco da casa é dourado, e sobre página clara ele dá 2,25:1, que
 * não fecha os 3:1 de elemento de interface. Em vez de trocar o dourado, que é
 * a identidade do foco no site inteiro, o par neutro se repete do lado de fora
 * dele: o fio preto que encosta na página é o mesmo de sempre, com a mesma
 * garantia de 4,58:1 contra qualquer fundo, e o dourado fica entre dois
 * brancos, onde ele é reconhecível.
 *
 * Os fios de 7 e 8 pixels ficam por baixo dos de 1 e 2 na pilha de sombras, e
 * o contorno dourado, que vai de 4 a 7, é pintado por cima de todos. O que se
 * vê, de dentro para fora: verde, branco, preto, branco, dourado, preto.
 */
.whatsapp:focus-visible{
  outline: 3px solid var(--cor-acento);
  outline-offset: 4px;
  box-shadow:
    0 0 0 1px #fff,
    0 0 0 2px #000,
    0 0 0 7px #fff,
    0 0 0 8px #000,
    0 8px 20px rgba(0, 0, 0, .30);
}

/* ------------------------------------------------- larguras mais folgadas */

/* Telefone deitado e tablet em pé. Referência: 600 e 768. */
@media (min-width: 600px){
  /*
   * Daqui para cima o botão sobe para o canto inferior da arte, sobre o
   * esmaecimento do pé. No celular ele fica abaixo dela, porque em 390 pixels
   * um botão sobreposto cobre parte útil do cartaz.
   */
  .faixa--com-arte .faixa__acao{
    position: absolute;
    inset: auto 0 0 auto;
    z-index: 1;
    padding: 1.5rem;
    background: none;
  }

  .grade--dois{ grid-template-columns: repeat(2, 1fr); }
  .eventos__lista{ grid-template-columns: repeat(2, 1fr); }
  .programacao__dias{ grid-template-columns: repeat(2, 1fr); }
  .rodape__interno{ grid-template-columns: repeat(2, 1fr); }
  .topo__horarios{ gap: 1rem 2.5rem; }
}

/* Tablet deitado e notebook. Referência: 1024. */
@media (min-width: 900px){
  :root{ --espaco: 2rem; }

  .topo{ padding-block: 7rem 4.5rem; }
  .programacao{ padding-block: 4rem; }

  .grade--tres{ grid-template-columns: repeat(3, 1fr); }

  /* Dados à esquerda, mapa à direita, e o mapa fica com a parte maior. */
  .contato:has(.contato__mapa){ grid-template-columns: 1fr 1.35fr; gap: 2.5rem; }
  .programacao__dias{ grid-template-columns: repeat(3, 1fr); }
  .rodape__interno{ grid-template-columns: 1.4fr 1fr 1fr 1fr; }
}

/* Monitor. Referência: 1440. */
@media (min-width: 1200px){
  .topo{ padding-block: 8.5rem 5.5rem; }

  /*
   * Três colunas na lista longa de /eventos. Sobrando um ou dois na última
   * fila, lê-se como o fim de uma lista, que é o que é.
   */
  .eventos__lista{ grid-template-columns: repeat(3, 1fr); gap: 1.5rem 1.75rem; }

  /*
   * A home fica em DUAS, e é decisão, não esquecimento. Ela mostra no máximo
   * quatro eventos: em três colunas isso dá 3 e depois 1 sozinho, e um cartão
   * só na segunda fila não lê como fim de lista, lê como buraco. Em duas
   * colunas os mesmos quatro fecham um bloco 2x2 inteiro.
   */
  .eventos__lista--dupla{ grid-template-columns: repeat(2, 1fr); gap: 1.5rem 2rem; }
}

/* ----------------------------------------------- comportamento com JS */

/*
 * Tudo daqui para baixo depende da classe .js, que um script de uma linha
 * coloca no <html>. Sem JavaScript, nada disso vale: o menu fica aberto, o
 * cabeçalho fica sólido e as seções ficam visíveis. Essa é a razão de as
 * regras estarem trancadas atrás de .js em vez de valerem por padrão.
 */

@media (max-width: 899px){
  .js .menu-alternar{ display: inline-flex; }

  .js .navegacao{
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    background: var(--cor-fundo);
    border-bottom: 1px solid var(--cor-borda);
    box-shadow: var(--sombra-alta);
    padding: .5rem var(--espaco) 1.25rem;
    display: none;
  }

  .js .navegacao[data-aberto="sim"]{ display: block; }

  .js .navegacao__lista{ flex-direction: column; align-items: stretch; gap: 0; }

  .js .navegacao__lista li{ border-bottom: 1px solid var(--cor-borda); }
  .js .navegacao__lista li:last-child{ border-bottom: 0; }

  .js .navegacao__lista a{ padding-block: .875rem; font-size: 1rem; }

  .js .navegacao__acao{ padding-top: .875rem; }
  .js .navegacao__acao a{ text-align: center; padding-block: .75rem; }
}

/* Cabeçalho transparente sobre o topo, sólido depois de rolar. Só com JS,
   porque sem ele não há quem avise que a rolagem aconteceu. */
.js .tem-topo .cabecalho{ position: fixed; left: 0; right: 0; }

.js .tem-topo .cabecalho:not(.cabecalho--fixado){
  background: transparent;
  border-bottom-color: transparent;
}

.js .tem-topo .cabecalho:not(.cabecalho--fixado) .marca,
.js .tem-topo .cabecalho:not(.cabecalho--fixado) .navegacao__lista a,
.js .tem-topo .cabecalho:not(.cabecalho--fixado) .menu-alternar{
  color: #fff;
}

.js .tem-topo .cabecalho:not(.cabecalho--fixado) .menu-alternar{
  border-color: rgba(255, 255, 255, .4);
}

.js .tem-topo .cabecalho:not(.cabecalho--fixado) .navegacao__acao a{
  color: var(--cor-base) !important;
}

/* Sobre a foto do topo, com o cabeçalho transparente, quem aparece é a logo
 * de fundo escuro. Esta regra é mais específica que a do estado sólido, lá em
 * cima, e por isso ganha dela sem precisar de !important. */
.js .tem-topo .cabecalho--duas-marcas:not(.cabecalho--fixado) .marca__logo--escuro{ display: block; }
.js .tem-topo .cabecalho--duas-marcas:not(.cabecalho--fixado) .marca__logo--claro{ display: none; }

/* E o cabeçalho de marca única volta a ser transparente sobre a foto: ali o
 * fundo escuro que ele carrega no estado sólido só atrapalharia. */
.js .tem-topo .cabecalho--marca-unica:not(.cabecalho--fixado){ background: transparent; }

.js .cabecalho--fixado{ box-shadow: var(--sombra-baixa); }

/* O menu aberto no celular precisa de fundo próprio mesmo com o cabeçalho
   transparente, senão o texto escuro cairia sobre a foto do topo. */
@media (max-width: 899px){
  .js .tem-topo .cabecalho:not(.cabecalho--fixado) .navegacao[data-aberto="sim"]{
    background: var(--cor-fundo);
  }

  .js .tem-topo .cabecalho:not(.cabecalho--fixado) .navegacao[data-aberto="sim"] a{
    color: var(--cor-texto);
  }

  /* O cabeçalho de marca única é escuro, e o texto do menu nele é branco. No
   * celular, porém, o menu não fica sobre o cabeçalho: ele abre num painel
   * abaixo dele, que tem fundo claro próprio. Sem esta regra o branco cairia
   * sobre o claro e o menu inteiro sumiria, que é o mesmo tipo de erro que
   * esta tarefa veio consertar, uma casa adiante.
   *
   * A escolha é a mesma já feita para o cabeçalho transparente, logo acima:
   * o painel é uma superfície clara, e dentro dele o texto é o do site. */
  .cabecalho--marca-unica .navegacao[data-aberto="sim"] a{
    color: var(--cor-texto);
  }
}

/* ------------------------------------------------------ micro-interações */

/*
 * Revelação ao entrar na viewport. Trancada duas vezes: só com JS, e só para
 * quem não pediu menos movimento ao sistema. Quem cair fora de qualquer uma
 * das duas condições vê tudo, imediatamente, sem animação nenhuma.
 */
@media (prefers-reduced-motion: no-preference){
  .js [data-revelar]{
    opacity: 0;
    transform: translateY(14px);
    transition: opacity 240ms ease-out, transform 240ms ease-out;
  }

  .js [data-revelar].revelado{ opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior: auto; }
  *{ animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
