/* ═══════════════════════════════════════════════
   Dizis TV — Design System & Styles
   Mobile-first, dark theme, glassmorphism
   ═══════════════════════════════════════════════ */

/* ─── CSS Variables ─── */
:root {
  /* Diz ao navegador que a página já é escura: sem isto os controles de
     formulário saem na cor clara de fábrica e o modo escuro forçado do
     Chrome inverte tudo por cima. */
  color-scheme: dark;

  /* Vermelho, preto e branco — o preto agora é NEUTRO, não mais o quente da
     landing. Sobre preto quente a arte das novelas (pele, madeira, luz de
     Istambul) puxava tudo para o sépia; o cinza neutro deixa a capa ser a
     única cor forte da tela, que é o que o desenho de streaming pede.

     Sem gradiente em lugar nenhum além dos degradês de leitura sobre arte:
     gradiente é superfície a mais para o navegador pintar, e o alvo aqui
     inclui TV Android antiga. */
  --bg-primary: #0a0a0a;
  --bg-secondary: #141414;
  --bg-tertiary: #1f1f1f;
  --bg-card: #141414;
  --bg-card-hover: #262626;
  /* "glass" ficou só no nome: sem blur (ver a nota sobre backdrop-filter mais
     abaixo), o que sobra é fundo sólido. Renomear tocaria em 30 lugares. */
  --bg-glass: #0f0f0f;
  --bg-glass-strong: #0a0a0a;

  --accent-primary: #e50914;   /* o vermelho de streaming, cheio e sem laranja */
  --accent-secondary: #b20710;
  --accent-glow: rgba(229, 9, 20, 0.3);

  --text-primary: #f5f5f5;
  --text-secondary: #a8a8a8;
  --text-tertiary: #6e6e6e;
  --text-accent: #e50914;

  --border-subtle: rgba(255, 255, 255, 0.08);
  --border-accent: rgba(229, 9, 20, 0.4);

  --danger: #f87171;
  --success: #4ade80;
  --warning: #fbbf24;

  /* Spacing */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --header-height: 56px;

  /* Radius */
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 20px;
  --radius-full: 9999px;

  /* Shadows */
  --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.3);
  --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.4);
  --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.5);
  --shadow-glow: 0 0 20px var(--accent-glow);

  /* Transitions */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --duration-fast: 150ms;
  --duration-normal: 250ms;
  --duration-slow: 400ms;

  /* Typography */
  --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-display: 'Outfit', 'Inter', sans-serif;
  /* Só para o título do herói e a marca: Anton é uma fonte de cartaz, ilegível
     em texto corrido e perfeita numa palavra só. É a mesma da landing. */
  --font-cartaz: 'Anton', 'Outfit', 'Inter', sans-serif;
}

/* ─── Reset & Base ─── */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  -webkit-tap-highlight-color: transparent;
}

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

body {
  font-family: var(--font-body);
  background: var(--bg-primary);
  color: var(--text-primary);
  line-height: 1.5;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  min-height: 100vh;
  min-height: 100dvh;
}

#app {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  position: relative;
}

/* Remove default focus outline, add custom */
:focus {
  outline: none;
}

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

input, button, textarea {
  font-family: inherit;
  font-size: inherit;
  border: none;
  background: none;
  color: inherit;
}

/* ═══════════════════════════════════════
   SPLASH SCREEN
   ═══════════════════════════════════════ */
.splash-screen {
  position: fixed;
  top: 0; right: 0; bottom: 0; left: 0;
  z-index: 9999;
  background: var(--bg-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.5s var(--ease-out), visibility 0.5s;
}

.splash-screen.fade-out {
  opacity: 0;
  visibility: hidden;
}

.splash-content {
  text-align: center;
  animation: splashIn 0.8s var(--ease-spring);
}

.splash-logo {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-bottom: 12px;
}

.logo-icon {
  font-size: 3rem;
  filter: drop-shadow(0 0 20px rgba(229, 9, 20, 0.5));
  animation: crownFloat 2s ease-in-out infinite;
}

/* A marca em tamanho de capa (login, splash e tela de bloqueio) — a mesma do
   header, só maior. Era um PNG quadrado; virou texto para a marca poder mudar
   sem redesenhar arte, e para não borrar na TV. */
.wordmark--grande {
  display: block;
  font-size: 2.6rem;
  text-shadow: 0 8px 28px rgba(0, 0, 0, 0.55);
}

.splash-logo .wordmark--grande {
  animation: crownFloat 2s ease-in-out infinite;
}

@media (max-width: 360px) {
  .wordmark--grande { font-size: 2.1rem; }
}

.logo-text {
  font-family: var(--font-display);
  font-size: 2.2rem;
  font-weight: 800;
  color: var(--accent-primary);
  letter-spacing: -0.5px;
}

.splash-tagline {
  color: var(--text-secondary);
  font-size: 0.95rem;
  margin-bottom: 32px;
  font-weight: 300;
  letter-spacing: 1px;
}

.splash-loader {
  width: 120px;
  height: 3px;
  background: var(--bg-tertiary);
  border-radius: var(--radius-full);
  margin: 0 auto;
  overflow: hidden;
}

.loader-bar {
  height: 100%;
  width: 40%;
  background: var(--accent-primary);
  border-radius: var(--radius-full);
  animation: loaderSlide 1.2s ease-in-out infinite;
}

@keyframes splashIn {
  from { opacity: 0; transform: scale(0.9) translateY(20px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}

@keyframes crownFloat {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50% { transform: translateY(-6px) rotate(3deg); }
}

@keyframes loaderSlide {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(350%); }
}

/* ═══════════════════════════════════════
   LOGIN SCREEN (código de 4 dígitos)
   ═══════════════════════════════════════ */
.login-screen {
  position: fixed;
  top: 0; right: 0; bottom: 0; left: 0;
  z-index: 10000;
  background: var(--bg-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  padding-top: calc(24px + var(--safe-top));
  padding-bottom: calc(24px + var(--safe-bottom));
  transition: opacity 0.5s var(--ease-out), visibility 0.5s;
}

/* Ancorado no rodapé em vez de entrar no fluxo: .login-screen é um flex
   centralizado, e um irmão de .login-content viraria uma segunda coluna e
   tiraria o formulário do centro. */
.login-footer {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(14px + var(--safe-bottom));
  text-align: center;
  font-size: 0.78rem;
}

.login-footer a {
  color: var(--text-secondary);
  opacity: 0.65;
  text-decoration: none;
  padding: 8px 12px; /* alvo de toque confortável apesar da fonte pequena */
}

.login-footer a:hover,
.login-footer a:focus-visible {
  opacity: 1;
  text-decoration: underline;
}

.login-screen.fade-out {
  opacity: 0;
  visibility: hidden;
}

.login-content {
  width: 100%;
  max-width: 360px;
  text-align: center;
  animation: splashIn 0.8s var(--ease-spring);
}

.login-logo {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-bottom: 12px;
}

.login-tagline {
  color: var(--text-secondary);
  font-size: 1.05rem;
  margin-bottom: 32px;
  font-weight: 400;
}

.login-form {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
}

/* Campo do e-mail. Era uma fileira de quatro quadrados de dígito; agora é um
   campo só, alto e largo, porque quem digita aqui tem 60+ e faz isso com o
   polegar — e porque endereço de e-mail não cabe em fonte de cartaz. */
.login-email {
  width: 100%;
  height: 62px;
  padding: 0 18px;
  text-align: center;
  font-size: 1.1rem;
  color: var(--text-primary);
  background: var(--bg-tertiary);
  border: 2px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  transition: border-color var(--duration-normal) var(--ease-out), box-shadow var(--duration-normal) var(--ease-out);
}

.login-email::placeholder {
  color: var(--text-tertiary);
}

.login-email:focus {
  border-color: var(--accent-primary);
  box-shadow: 0 0 0 4px var(--accent-glow);
}

.login-error {
  color: var(--danger);
  font-size: 0.95rem;
  font-weight: 500;
}

.login-submit {
  font-size: 1.1rem;
  padding: 18px 24px;
}

.login-trial {
  margin-top: 12px;
  padding: 14px 24px;
  font-size: 0.95rem;
  background: #25d366;
  color: #fff;
  text-decoration: none;
}

.login-trial:hover {
  background: #2fe075;
}

/* Botão de verdade, não link sublinhado: boa parte do público tem 60+ e texto
   sublinhado no meio da tela não se lê como "aperte aqui" — fica parecendo
   aviso. Vem junto com .btn .btn-ghost .btn-lg .btn-block no HTML; aqui só o
   espaçamento e o contraste, que o cinza padrão do ghost não entrega. */
.login-support {
  margin-top: 12px;
  color: var(--text-primary);
  border-color: var(--text-tertiary);
}

.login-support:hover,
.login-support:focus-visible {
  color: var(--text-primary);
  border-color: var(--accent-primary);
}

/* Separa o secundário do bloco de ações principais logo acima. */
.login-support--afastado {
  margin-top: 24px;
}

/* ═══════════════════════════════════════
   TRIAL EXPIRADO (bloqueio de acesso)
   ═══════════════════════════════════════ */
.trial-expired-overlay {
  position: fixed;
  top: 0; right: 0; bottom: 0; left: 0;
  z-index: 10000;
  background: var(--bg-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  padding-top: calc(24px + var(--safe-top));
  padding-bottom: calc(24px + var(--safe-bottom));
}

.trial-expired-overlay.hidden {
  display: none;
}

.trial-expired-card {
  width: 100%;
  max-width: 360px;
  text-align: center;
  animation: splashIn 0.8s var(--ease-spring);
}

.trial-expired-title {
  font-family: var(--font-display);
  font-size: 1.4rem;
  font-weight: 800;
  color: var(--text-primary);
  margin-top: 20px;
  margin-bottom: 12px;
}

.trial-expired-text {
  color: var(--text-secondary);
  font-size: 0.95rem;
  line-height: 1.6;
  margin-bottom: 28px;
}

/* ═══════════════════════════════════════
   HEADER
   ═══════════════════════════════════════ */
.app-header {
  position: sticky;
  top: 0;
  z-index: 100;
  /* Altura mínima, não fixa, e com quebra: agora são DUAS ações no topo
     (Assinar e Entrar) e num celular de 375px elas não cabem ao lado da
     busca. Sem isto o `min-width: 0` da busca a esmagava para 99px — e o
     texto "Buscar novela..." precisa de 121px, então ela aparecia cortada.
     Com `wrap` a busca desce sozinha para a linha de baixo quando o espaço
     acaba, e volta para o lado quando sobra. Uma marcação só para celular,
     tablet, computador e TV — sem regra de largura para manter. */
  min-height: var(--header-height);
  padding: 8px 12px;
  /* SOMA, não substitui. Escrito como `padding-top: var(--safe-top)` esta
     linha apagava a folga do atalho acima e sobrava zero: os botões
     encostavam na barra do navegador, com 5px em cima e 12px embaixo.
     O recuo da ilha/notch continua sendo respeitado, agora somado à folga.
     8px e não 6: com 6 o celular ficava mais apertado que o computador,
     porque lá a altura mínima ainda sobrava espaço para distribuir. */
  padding-top: calc(var(--safe-top) + 8px);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  /* Com `wrap`, quem manda na posição vertical das LINHAS é align-content, e
     o padrão (`normal`) as encosta no topo quando sobra altura. Sem isto o
     `align-items: center` centraliza dentro da linha, mas a linha inteira
     fica alta demais. */
  align-content: center;
  gap: 8px 10px;
  background: var(--bg-glass-strong);
  border-bottom: 1px solid var(--border-subtle);
}

/* A partir daqui (menu de topo visível — mesmo corte de #menu-topo) o header
   vira GRID de 3 colunas: marca | menu | resto. As colunas 1 e 3 são a MESMA
   largura (1fr cada) DE PROPÓSITO — é o que faz a coluna 2 cair no centro
   verdadeiro do header, e não só "encostada perto da marca", que foi o
   resultado errado da primeira versão (flex comum, sem 3ª coluna do mesmo
   tamanho pra equilibrar). Sem o menu (celular), o flex de cima já resolve:
   marca de um lado, #header-direita do outro, sem precisar de grid nenhum. */
@media (min-width: 561px) {
  .app-header {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    /* Mais respiro nas bordas — no celular 12px é o máximo que sobra, mas
       aqui grudava tudo na borda igual não é (pedido do dono, referência
       SuperFlixAPI: marca e ícones da direita ficam recuados, não colados). */
    padding-left: 28px;
    padding-right: 28px;
  }

  .wordmark {
    justify-self: start;
  }

  .menu-topo {
    justify-self: center;
  }

  .header-direita {
    justify-self: end;
  }
}

/* SEM MENU (visitante — #app.modo-visitante, ver app.js), o grid vira 2
 * colunas, não 3.
 *
 * Achado em 14/09/2026: com `1fr auto 1fr` e a coluna do meio vazia
 * (#menu-topo com `display: none` pra quem ainda não é cliente), essa
 * coluna "auto" mesmo assim reservava uns 330px sozinha — um
 * comportamento do algoritmo de grid que independe de ter conteúdo, e
 * medido ao vivo (Chrome DevTools: `grid-template-columns` computado
 * continuava `307px 330px 307px` mesmo REMOVENDO o elemento do DOM).
 * Resultado: #header-direita (busca/Assinar/Entrar) ficava perto do
 * centro do header, não no canto — foi assim que a cliente reportou:
 * "aquelas três opções centralizadas" num screenshot da página de venda.
 *
 * Cortar pra 2 colunas quando não existe menu resolve de vez: sem coluna
 * do meio pra "roubar" espaço, #header-direita cai na borda direita de
 * verdade.
 */
@media (min-width: 561px) {
  #app.modo-visitante .app-header {
    grid-template-columns: 1fr auto;
  }
}

/* A busca sai do header pra quem ainda não assina (pedido do dono,
 * 14/09/2026) — a página de venda foca só em Assinar/Entrar. */
#app.modo-visitante #btn-buscar-topo {
  display: none;
}

.header-direita {
  display: flex;
  align-items: center;
  gap: 8px 10px;
}

/* Busca: só ícone no celular (de sempre — não cabe o texto do lado de
   Assinar/Entrar em 375px); pílula com "PESQUISAR" escrito a partir do
   tablet/computador, referência SuperFlixAPI. Herda hover/active de
   .icon-btn (a bolha vermelha), só troca o formato e o tamanho.
   Seletor composto (.icon-btn.pill-busca) DE PROPÓSITO: mesma
   especificidade que .icon-btn sozinho perderia pra ele por causa da ordem
   no arquivo — combinar as duas classes garante a prioridade sem depender
   de onde a regra mora no arquivo. */
.pill-busca span {
  display: none;
}

@media (min-width: 561px) {
  .icon-btn.pill-busca {
    width: auto;
    height: 40px;
    gap: 8px;
    padding: 0 18px 0 14px;
    border-radius: var(--radius-full);
    border: 1px solid var(--border-subtle);
    background: var(--bg-tertiary);
  }

  .pill-busca span {
    display: inline;
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.4px;
    text-transform: uppercase;
  }
}

.header-left {
  display: flex;
  align-items: center;
  gap: 10px;
}

.header-logo {
  font-size: 1.5rem;
  line-height: 1;
}

.header-title {
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--accent-primary);
}

/* A marca é texto, não imagem: uma palavra em Anton pesa zero byte a mais que
   a fonte que o herói já carrega, escala sozinha em qualquer tela e não fica
   borrada na TV — a wordmark.png ficava. */
.wordmark {
  font-family: var(--font-cartaz);
  font-size: 1.35rem;
  line-height: 1;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  /* DIZIS em branco e TV em vermelho — as cores da marca desde a versão
     anterior. A reescrita tinha invertido as duas. */
  color: var(--text-primary);
  white-space: nowrap;
  flex-shrink: 0;
}

.wordmark-tv {
  color: var(--accent-primary);
}

@media (max-width: 380px) {
  .wordmark { font-size: 1.15rem; }
}

.header-right {
  display: flex;
  align-items: center;
  gap: 4px;
}

/* ─── Trial countdown / plan-expiry bar ───
   Fica FORA do .app-header, como uma faixa própria de largura total —
   dentro do header não sobra espaço ao lado do botão de suporte em telas
   de celular comuns (~390px), o que empurrava o CTA pra fora da viewport
   (body tem overflow-x: hidden, então ficava inacessível). */
.trial-bar {
  position: sticky;
  top: var(--header-height);
  z-index: 90;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 8px 16px;
  background: var(--bg-glass-strong);
  border-bottom: 1px solid var(--border-subtle);
}

.trial-bar.hidden {
  display: none;
}

.trial-countdown {
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-secondary);
  white-space: nowrap;
}

.trial-buy-btn {
  display: flex;
  align-items: center;
  /* 32px estava abaixo do mínimo confortável para dedo (44px). 44 no header
     inteiro empurraria a busca; 40 com o padding lateral maior resolve o
     erro de toque sem reformar o topo. */
  height: 40px;
  padding: 0 16px;
  border-radius: var(--radius-full);
  background: var(--accent-primary);
  color: #fff;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: filter var(--duration-fast) ease;
}

.trial-buy-btn:hover,
.trial-buy-btn:active {
  filter: brightness(1.1);
}

/* "Entrar" ao lado de "Assinar": mesma forma e mesma altura, peso visual
   menor. Contorno em vez de preenchido — quem já é cliente procura o botão
   e acha; quem não é, tem o cheio puxando o olho. */
.trial-buy-btn-ghost {
  background: transparent;
  color: var(--text-primary);
  border: 1px solid var(--border-subtle);
}

.trial-buy-btn-ghost:hover,
.trial-buy-btn-ghost:active {
  background: var(--bg-tertiary);
  filter: none;
}

/* ─── Aviso de vencimento (planos pagos) ─── */
.plan-expiry-text {
  color: var(--warning);
}

.plan-expiry-text--urgent {
  color: var(--danger);
}

/* ─── Support Button (WhatsApp) ─── */
.support-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 36px;
  padding: 0 14px;
  border-radius: var(--radius-full);
  background: rgba(37, 211, 102, 0.15);
  color: #25d366;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: all var(--duration-fast) ease;
}

.support-btn:hover,
.support-btn:active {
  background: rgba(37, 211, 102, 0.28);
  color: #2fe075;
}

/* ─── Icon Button ─── */
.icon-btn {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-secondary);
  cursor: pointer;
  transition: all var(--duration-fast) ease;
  position: relative;
  overflow: hidden;
}

.icon-btn::before {
  content: '';
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  border-radius: inherit;
  background: rgba(229, 9, 20, 0.12);
  opacity: 0;
  transition: opacity var(--duration-fast) ease;
}

.icon-btn:hover,
.icon-btn:active {
  color: var(--text-primary);
}

.icon-btn:hover::before,
.icon-btn:active::before {
  opacity: 1;
}

.icon-btn:active {
  transform: scale(0.92);
}

/* ═══════════════════════════════════════
   MENU DE TOPO (tablet/computador) — pedido do dono, 10/09/2026, referência
   SuperFlixAPI: pílula com Home/Séries/Minisséries no header, em vez
   das pílulas de categoria abaixo do banner. Só aparece pra quem já é
   cliente (app.js liga/desliga o `hidden` junto com a barra de baixo) e some
   no celular — lá quem cobre os MESMOS três destinos é #barra-inferior,
   ao alcance do polegar; os dois juntos duplicariam a navegação.
   ═══════════════════════════════════════ */
.menu-topo {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 4px;
  border-radius: var(--radius-full);
  background: var(--bg-tertiary);
  border: 1px solid var(--border-subtle);
}

.menu-topo.hidden {
  display: none;
}

@media (max-width: 560px) {
  .menu-topo {
    display: none !important;
  }
}

.menu-topo-item {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 36px;
  padding: 6px 14px;
  border-radius: var(--radius-full);
  color: var(--text-tertiary);
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
  transition: all var(--duration-fast) ease;
  white-space: nowrap;
}

.menu-topo-item svg {
  flex-shrink: 0;
}

.menu-topo-item:hover {
  color: var(--text-primary);
}

.menu-topo-item.active {
  color: #fff;
  background: var(--accent-primary);
  box-shadow: var(--shadow-glow);
}

/* Só o ícone sobra quando o espaço aperta (tablet estreito) — o nome some
   antes de a pílula quebrar linha ou quebrar dentro do header. */
@media (max-width: 900px) {
  .menu-topo-item span {
    display: none;
  }
  .menu-topo-item {
    padding: 8px;
  }
}

/* ═══════════════════════════════════════
   SEARCH (ícone no header abre #busca-overlay em tela cheia — a busca deixou
   de ser um campo sempre aberto no cabeçalho em 10/09/2026)
   ═══════════════════════════════════════ */

/* Quem empurrava as ações para a direita era o campo de busca, que ficava no
   header o tempo todo. Sem ele, quem empurra é a marca (celular) ou o ícone
   de busca (tablet/computador, ver a regra logo abaixo) — tudo que vem
   depois encosta na borda direita, tendo um botão ou três (visitante vê
   Assinar + Entrar; assinante só vê os ícones). */
@media (max-width: 560px) {
  .wordmark {
    margin-right: auto;
  }
}

.busca-overlay .modal {
  max-width: 480px;
}

.busca-input-wrap {
  margin-bottom: 16px;
}

.busca-ir {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-full);
  background: var(--accent-primary);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: transform var(--duration-fast) ease;
}

.busca-ir:hover {
  transform: scale(1.06);
}

.busca-filtros-label {
  display: block;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--text-tertiary);
  margin-bottom: 10px;
}

.busca-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.busca-chip {
  min-height: 40px;
  padding: 8px 16px;
  border-radius: var(--radius-full);
  border: 1px solid var(--border-subtle);
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
  transition: all var(--duration-fast) ease;
}

.busca-chip.active {
  color: #fff;
  background: var(--accent-primary);
  border-color: transparent;
}

.busca-chip:disabled {
  cursor: not-allowed;
  opacity: 0.45;
}

.search-input-wrap {
  display: flex;
  align-items: center;
  min-height: 44px;
  gap: 10px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-full);
  padding: 8px 14px;
  transition: border-color var(--duration-fast) ease;
}

.search-input-wrap:focus-within {
  border-color: var(--border-accent);
  box-shadow: 0 0 0 3px rgba(229, 9, 20, 0.1);
}

.search-icon {
  color: var(--text-tertiary);
  flex-shrink: 0;
}

.search-input-wrap input {
  flex: 1;
  /* 16px, e não 0.9rem: abaixo disso o Safari do iPhone dá zoom sozinho ao
     focar o campo e a página fica torta. Era o que `user-scalable=no`
     escondia — tirado ele, a altura certa da fonte é que resolve. */
  font-size: 16px;
  color: var(--text-primary);
  min-width: 0;
}

.search-input-wrap input::placeholder {
  color: var(--text-tertiary);
}

.search-clear {
  cursor: pointer;
  color: var(--text-tertiary);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2px;
  transition: color var(--duration-fast) ease;
}

.search-clear:hover {
  color: var(--text-primary);
}

/* ═══════════════════════════════════════
   MAIN CONTENT
   ═══════════════════════════════════════ */
.main-content {
  flex: 1;
  padding: 0 0 calc(24px + var(--safe-bottom));
  overflow-y: auto;
}

/* ─── Empty State ─── */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 60px 32px;
  min-height: calc(100vh - var(--header-height) - 40px);
  min-height: calc(100dvh - var(--header-height) - 40px);
  animation: fadeInUp 0.6s var(--ease-out);
}

.empty-state.hidden {
  display: none;
}

@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(24px); }
  to { opacity: 1; transform: translateY(0); }
}

.empty-illustration {
  margin-bottom: 28px;
}

.empty-circle {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background: rgba(229, 9, 20, 0.12);
  border: 1px solid var(--border-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent-primary);
  animation: pulse 3s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 var(--accent-glow); }
  50% { transform: scale(1.05); box-shadow: 0 0 30px var(--accent-glow); }
}

.empty-title {
  font-family: var(--font-display);
  font-size: 1.4rem;
  font-weight: 700;
  margin-bottom: 10px;
  color: var(--text-primary);
}

.empty-desc {
  color: var(--text-secondary);
  font-size: 0.9rem;
  max-width: 320px;
  line-height: 1.6;
  margin-bottom: 32px;
}

.empty-actions {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
  max-width: 280px;
}

/* ─── Buttons ─── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-weight: 600;
  /* Metade dos botões do app é <a> (checkout, WhatsApp), e link sublinhado
     dentro de um botão vermelho não vira "mais clicável" — vira ruído, ainda
     mais pra quem tem 60+. Cada .btn que é link zerava isso por conta
     própria, ou esquecia. */
  text-decoration: none;
  border-radius: var(--radius-lg);
  cursor: pointer;
  transition: all var(--duration-normal) var(--ease-out);
  white-space: nowrap;
  position: relative;
  overflow: hidden;
}

.btn:active {
  transform: scale(0.97);
}

.btn-sm {
  padding: 8px 16px;
  font-size: 0.8rem;
}

.btn-md {
  padding: 10px 20px;
  font-size: 0.875rem;
}

.btn-lg {
  padding: 14px 24px;
  font-size: 0.95rem;
}

.btn-block {
  width: 100%;
}

.btn-primary {
  background: var(--accent-primary);
  color: #fff;
  font-weight: 700;
  box-shadow: var(--shadow-glow);
}

.btn-primary:hover {
  box-shadow: 0 0 30px var(--accent-glow);
  transform: translateY(-1px);
}

.btn-primary:active {
  transform: scale(0.97) translateY(0);
}

.btn-ghost {
  background: transparent;
  color: var(--text-secondary);
  border: 1px solid var(--border-subtle);
}

.btn-ghost:hover {
  color: var(--text-primary);
  border-color: var(--border-accent);
  background: rgba(229, 9, 20, 0.12);
}

/* ─── Category Tabs ─── */
.category-tabs {
  padding: 12px 0 4px;
  border-bottom: 1px solid var(--border-subtle);
}

.category-tabs.hidden {
  display: none;
}

.tabs-scroll {
  display: flex;
  gap: 4px;
  overflow-x: auto;
  padding: 0 16px 8px;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.tabs-scroll::-webkit-scrollbar {
  display: none;
}

.tab-btn {
  flex-shrink: 0;
  /* 34px de altura era alvo pequeno demais para dedo, e estes são os
     filtros mais tocados da home. */
  min-height: 44px;
  padding: 10px 18px;
  border-radius: var(--radius-full);
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--text-tertiary);
  cursor: pointer;
  transition: all var(--duration-fast) ease;
  background: transparent;
  border: 1px solid transparent;
}

.tab-btn:hover {
  color: var(--text-secondary);
  background: var(--bg-tertiary);
}

.tab-btn.active {
  color: #fff;
  background: var(--accent-primary);
  border-color: transparent;
  box-shadow: var(--shadow-glow);
  font-weight: 600;
}

/* ─── Channel Grid ─── */
.channel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px;
  padding: 16px;
}

.channel-grid.hidden {
  display: none;
}

.channel-card {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  /* Cantos pequenos: numa fileira de capas o raio grande come o canto da arte
     e some com o rosto de quem está na ponta do pôster. */
  border-radius: 8px;
  overflow: hidden;
  cursor: pointer;
  transition: all var(--duration-normal) var(--ease-out);
  /* `backwards`, NUNCA `both`/`forwards` — achado testando a prévia de hover
     (01/10/2026): uma animação de CSS continua "dona" da propriedade que ela
     anima mesmo depois de terminar, enquanto o fill-mode segurar o quadro
     final — e isso vence qualquer regra normal (`:hover`, `:active`, a
     prévia nova) que tente mudar essa MESMA propriedade depois. Com `both`,
     nenhum `transform` de hover deste cartão jamais pintou, nem o
     `translateY(-2px)` de sempre: o card entrava, a animação "terminava" e
     ficava seguindo o `transform` pra sempre. `backwards` preserva o único
     motivo de existir (mostrar o quadro OPACITY:0 antes da entrada começar,
     essencial com `animationDelay` escalonado por cartão) e devolve a
     propriedade pro resto da folha assim que a entrada termina — o quadro
     final (`scale(1) translateY(0)`, opacity 1) é idêntico ao estado de
     repouso normal, então não muda nada visualmente no card parado. */
  animation: cardIn 0.4s var(--ease-out) backwards;
  position: relative;
}

.channel-card:hover {
  background: var(--bg-card-hover);
  border-color: var(--border-accent);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md), 0 0 20px rgba(229, 9, 20, 0.1);
}

.channel-card:active {
  transform: scale(0.97);
}

@keyframes cardIn {
  from { opacity: 0; transform: scale(0.92) translateY(12px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}

.card-thumb {
  width: 100%;
  aspect-ratio: 3 / 4;
  background: var(--bg-tertiary);
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
}

.card-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.card-thumb-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--text-tertiary);
  font-size: 0.7rem;
  padding: 8px;
  text-align: center;
}

.card-thumb-placeholder svg {
  opacity: 0.4;
}

.card-play-overlay {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  background: rgba(0, 0, 0, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity var(--duration-fast) ease;
}

.channel-card:hover .card-play-overlay {
  opacity: 1;
}

.card-play-icon {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--accent-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  box-shadow: var(--shadow-glow);
}

.card-info {
  padding: 10px 12px 12px;
}

/* Conteúdo de catálogo (novela, filme, série) tem pôster com arte própria:
   o título vai POR CIMA dela, como capa de streaming. Canal ao vivo fica de
   fora — a "arte" dele é um logotipo, e escrever em cima suja os dois. */
.channel-card--poster .card-info {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 24px 10px 10px;
  background: linear-gradient(0deg, rgba(10, 10, 10, 0.96) 0%, rgba(10, 10, 10, 0.75) 45%, rgba(10, 10, 10, 0) 100%);
}

/* A arte é o card: moldura e fundo só apareciam nas beiradas da capa. */
.channel-card--poster {
  border-color: transparent;
}

.channel-card--poster .card-title {
  margin-bottom: 0;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
}

/* Sublinha ("Série", "12 episódios") sai: sobre a arte ela vira ruído, e a
   informação já está na etiqueta do canto. */
/* O gênero estava sendo carregado e jogado fora: os 54 cartões vinham com ele
   preenchido, estilizado, e escondido aqui. A faixa embaixo da capa mede 47px
   para mostrar um título de 16px — o espaço já estava pago. E é a informação
   que ajuda a escolher quando a capa não diz: comédia, drama, época. */
.channel-card--poster .card-group { display: flex; }

.card-title {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-primary);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.3;
  margin-bottom: 4px;
}

.card-group {
  font-size: 0.7rem;
  color: var(--text-tertiary);
  display: flex;
  align-items: center;
  gap: 4px;
}

.card-group-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent-primary);
  opacity: 0.6;
}

/* ─── Prévia flutuante ao passar o mouse (estilo Netflix) ────────────────
   Pedido do dono, 01/10/2026: cartão cresce e revela nota, gênero, sinopse
   e um botão ao passar o mouse, só pra quem tem mouse de verdade
   (`hover:hover` + `pointer:fine`) — toque e controle remoto de TV ficam de
   fora de propósito (TV mantém o próprio `scale(1.08)` em
   `body.tv-nav .channel-card:focus-visible`, mais abaixo).

   REFEITO no mesmo dia: a primeira versão crescia o painel DENTRO do
   próprio cartão, e saiu feia em produção — cobria quase a capa inteira,
   mal sobrava espaço pra sinopse. O motivo técnico de ter ficado tão
   apertada: `.continue-track` rola com `overflow-x: auto`, e a
   especificação do CSS OBRIGA `overflow-y` a virar `auto` também nesse
   caso (só um eixo pode ser `visible`) — qualquer altura extra abaixo do
   cartão seria cortada pela própria pista.

   A solução de verdade (a mesma que a Netflix usa): um cartão À PARTE,
   `position: fixed`, nunca filho da pista — o corte dela nunca se aplica.
   Isso tira o problema de "`.card-thumb` cobre a Home sozinho" porque a
   imagem fica INTEIRA, sem nada por cima: o painel de texto vem DEPOIS
   dela, não em cima. Por ser `position: fixed` (relativo à tela, não ao
   documento), passou a precisar de JavaScript pra saber ONDE desenhar —
   isso mora em `mostrarPrevistaAgora`/`agendarMostrarPrevista`
   (public/app.js): mede o cartão de origem com `getBoundingClientRect()`,
   centraliza por cima dele, e corrige se estourar a borda da tela.

   UM ELEMENTO SÓ (`.preview-flutuante`), reaproveitado por todos os
   cartões — criar um por cartão seria centenas de divs ociosas na Home. */
.preview-flutuante {
  position: fixed;
  z-index: 500;
  display: flex;
  flex-direction: column;
  background: var(--bg-card-hover);
  border-radius: 10px;
  overflow: hidden;
  box-shadow: var(--shadow-lg), 0 0 28px rgba(229, 9, 20, 0.2);
  opacity: 0;
  pointer-events: none;
  /* translateY, nunca scale: scale mudaria a altura MEDIDA pelo JS (que
     corrige a posição vertical antes de revelar), e a medição teria que
     adivinhar o quanto o scale ainda vai encolher. */
  transform: translateY(6px);
  transition: opacity var(--duration-fast) ease, transform var(--duration-fast) var(--ease-out);
}

.preview-flutuante.ativa {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

.preview-flutuante-img {
  width: 100%;
  aspect-ratio: 3 / 4;
  background: var(--bg-tertiary);
  overflow: hidden;
}

.preview-flutuante-img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.preview-flutuante-info {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px 12px 12px;
  cursor: pointer;
}

.preview-flutuante-title {
  font-size: 0.86rem;
  font-weight: 700;
  color: var(--text-primary);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.preview-flutuante-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.76rem;
  color: var(--text-secondary);
  font-weight: 600;
}

.preview-flutuante-rating {
  color: var(--warning);
}

.preview-flutuante-dot {
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--text-tertiary);
  flex-shrink: 0;
}

.preview-flutuante-genres {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}

.genre-chip {
  padding: 3px 9px;
  border-radius: var(--radius-full);
  font-size: 0.68rem;
  font-weight: 500;
  color: var(--text-secondary);
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid var(--border-subtle);
  white-space: nowrap;
}

.preview-flutuante-synopsis {
  font-size: 0.76rem;
  line-height: 1.4;
  color: var(--text-secondary);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.preview-flutuante-btn {
  margin-top: 2px;
}

.preview-flutuante-btn svg {
  flex-shrink: 0;
}

/* ─── Category Upsell Grid (quadrados: desbloqueado pula pra categoria,
       bloqueado leva ao checkout) ─── */
/* Régua horizontal em vez de grade. Com grid, telas estreitas quebravam os
   quadrados em duas linhas desalinhadas — e a última linha ficava com um
   quadrado solto. Arrastando de lado, cabe qualquer quantidade de categorias
   em qualquer largura. */
.category-section {
  padding: 14px 0 0;
}

.category-section.hidden {
  display: none;
}

.grid-aviso {
  margin: -6px 0 14px;
  padding: 10px 14px;
  border-left: 3px solid var(--gold, #d9a73c);
  background: rgba(217, 167, 60, .08);
  border-radius: 0 6px 6px 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-secondary, #b5a9a3);
}

.category-section-title,
.continue-row-title {
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--text-primary);
  padding: 0 16px;
  margin-bottom: 10px;
}

/* Recentes/Atualizados — reaproveita a pílula de .tab-btn (mesma linguagem
   visual dos filtros de categoria) só que só com duas opções lado a lado. */
.sort-toggle {
  display: flex;
  gap: 8px;
  padding: 0 16px;
  margin-bottom: 14px;
}

.sort-toggle.hidden {
  display: none;
}

.sort-toggle .tab-btn {
  flex: 1;
  text-align: center;
}

/* A régua do "Continue assistindo" já vive dentro da grade, que tem padding
   próprio — senão o título entraria 32px pra dentro. */
.continue-row-title { padding: 0; }

.category-upsell-grid {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  /* O padding lateral entra aqui, e não no pai: assim o primeiro e o último
     quadrado encostam na borda da tela ao rolar, em vez de parar antes. */
  padding: 0 16px 4px;
  scroll-snap-type: x proximity;
  /* Sem isto o snap alinha o primeiro quadrado à borda do contêiner e engole o
     padding-left: a régua nasce rolada em 16px e o primeiro quadrado encosta
     na tela, desalinhado do título. */
  scroll-padding-left: 16px;
  -webkit-overflow-scrolling: touch;
  /* Esconde a barra: no celular ela não aparece, e no desktop pesava mais que
     ajudava num trecho de cinco itens. */
  scrollbar-width: none;
}

.category-upsell-grid::-webkit-scrollbar {
  display: none;
}

.category-upsell-grid > * {
  /* Pílula: a largura sai do texto. Antes era fixa em 108px porque cada item
     era um quadrado de foto. */
  flex: 0 0 auto;
  scroll-snap-align: start;
}

/* Eram dois quadrados de foto de 96px, e só dois: 52% da largura do celular
   gastos num botão de duas opções, dentro de uma régua de rolagem feita para
   muitos itens e com título de seção próprio. Somando a régua de temas logo
   abaixo, eram DUAS fileiras de categoria fazendo trabalhos parecidos.

   Pílula diz o mesmo em 38px de altura, na mesma linguagem das abas de tema
   que já existem embaixo — e devolve a tela para as capas, que é o que a
   cliente veio ver. */
.category-tile {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 38px;
  padding: 0 16px;
  border: 1px solid var(--border-subtle);
  border-radius: 100px;
  background-color: var(--bg-tertiary);
  color: var(--text-secondary);
  font-family: var(--font-body);
  font-size: 0.83rem;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
  transition: transform var(--duration-fast) ease, background-color var(--duration-fast) ease,
    color var(--duration-fast) ease, border-color var(--duration-fast) ease;
}

.category-tile:active {
  transform: scale(0.96);
}

.category-tile.active {
  background-color: var(--accent-primary);
  border-color: transparent;
  color: #fff;
}

.category-tile-label {
  line-height: 1;
}

.category-tile.locked {
  opacity: 0.6;
}

/* O cadeado agora é um ícone ao lado do nome, não uma cortina por cima da
   foto — não há mais foto para cobrir. */
.category-tile-lock {
  display: inline-flex;
  align-items: center;
}

.category-tile-lock svg {
  width: 13px;
  height: 13px;
  color: currentColor;
}

/* ─── Grid loading state ─── */
.grid-loading {
  grid-column: 1/-1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 60px 20px;
  color: var(--text-secondary);
  font-size: 0.85rem;
}

/* ─── Etiqueta "Disponível" (capa de novela, filme e série) ───
   O verde diz uma coisa só, e é a mesma do herói: isto toca agora. */
.card-badge {
  position: absolute;
  top: 6px;
  left: 6px;
  /* Achado testando a reforma de 01/10/2026: sem z-index, o selo "Em Alta"
     (também ancorado embaixo) nascia atrás do degradê do título e sumia —
     bug antigo, não desta reforma, mas mexendo nos cartões era a hora certa
     de notar e consertar. */
  z-index: 2;
  padding: 4px 8px;
  border-radius: 4px;
  /* Era 0.6rem — 9,6px. São 48 destas na home e o público tem 50 anos ou
     mais em boa parte; 9px não se lê nesse cenário. */
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  background: var(--success);
  color: #06280f;
}

/* Novela do SuperFlixAPI, vista por quem está no teste grátis: avisa ANTES
   do clique que ali pede assinatura, em vez de só surpreender no modal. Fundo
   escuro translúcido (não verde — aqui a notícia não é "disponível", é o
   contrário) com o mesmo cadeado do quadrado de categoria bloqueado. */
.card-badge--lock {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: rgba(10, 10, 10, 0.78);
  color: #fff;
}

.card-badge--lock svg {
  width: 11px;
  height: 11px;
  flex-shrink: 0;
}

/* Dublada/Legendada — canto oposto ao de "Assinante" de propósito: os dois
   nunca aparecem juntos (novela do Telegram não é do SuperFlixAPI), mas cada
   selo fica com o seu canto mesmo assim, sem depender dessa coincidência. */
.card-badge--audio {
  left: auto;
  right: 6px;
  background: rgba(10, 10, 10, 0.78);
  color: #fff;
}

/* Novela da prateleira "Em Alta" (posicaoNosDestaques, categories-config.js)
   — pedido do dono, 16/09/2026.
   Até 01/10/2026 isto flutuava sobre a capa com um deslocamento fixo em
   pixels — e um número fixo não sabe se o título abaixo dele tem uma linha
   ou duas: ou nascia por cima do nome (deslocamento curto) ou sobrava longe
   demais num título de uma linha só, o caso mais comum (deslocamento longo).
   Relatado ao vivo pelo dono nos dois sentidos no mesmo dia.
   A correção é sair da sobreposição: o selo agora é filho de .card-info (ver
   createChannelCard em app.js), em fluxo normal, logo acima do título — por
   isso tudo abaixo reseta o absolute/top/bottom/left do .card-badge base. */
.card-info .card-badge--em-alta {
  position: static;
  display: inline-flex;
  margin-bottom: 5px;
  background: var(--accent-primary);
  color: #fff;
}

/* ═══════════════════════════════════════
   SERIES DETAIL VIEW
   ═══════════════════════════════════════ */
.series-detail {
  padding: 16px;
  animation: fadeInUp 0.3s var(--ease-out);
}

.series-detail.hidden {
  display: none;
}

.series-back-btn {
  margin-bottom: 16px;
}

.series-detail-header {
  display: flex;
  gap: 16px;
  margin-bottom: 20px;
}

.series-detail-cover {
  width: 110px;
  aspect-ratio: 3/4;
  object-fit: cover;
  border-radius: var(--radius-lg);
  background: var(--bg-tertiary);
  flex-shrink: 0;
  border: 1px solid var(--border-subtle);
}

.series-detail-info {
  flex: 1;
  min-width: 0;
}

.series-detail-title {
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 700;
  margin-bottom: 6px;
  color: var(--text-primary);
}

.series-detail-meta {
  font-size: 0.78rem;
  color: var(--accent-primary);
  font-weight: 600;
  margin-bottom: 8px;
}

.series-detail-plot {
  font-size: 0.82rem;
  color: var(--text-secondary);
  line-height: 1.6;
  display: -webkit-box;
  -webkit-line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.season-tabs {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding-bottom: 12px;
  margin-bottom: 8px;
  border-bottom: 1px solid var(--border-subtle);
  scrollbar-width: none;
}

.season-tabs::-webkit-scrollbar {
  display: none;
}

.episode-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.episode-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px;
  border-radius: var(--radius-md);
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  cursor: pointer;
  transition: background-color var(--duration-fast) ease, border-color var(--duration-fast) ease, transform var(--duration-fast) var(--ease-out);
  /* Mesma entrada em cascata dos cartões da home (cardIn) — uma lista de 40
     episódios que só "aparece" de uma vez lê como travamento; entrando em
     fila ela lê como carregada. JS só dá o atraso (ver renderSeriesDetail,
     app.js); a animação em si é só CSS. */
  animation: episodeRowIn 0.35s var(--ease-out) both;
}

@keyframes episodeRowIn {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

.episode-row:hover {
  background: var(--bg-card-hover);
  border-color: var(--border-accent);
}

.episode-row:active {
  transform: scale(0.98);
}

/* Preenchido e com brilho, igual ao play da capa (.card-play-icon) — o
   círculo translúcido de antes era discreto demais pro botão mais apertado
   da tela inteira (uma lista de episódios é só isso, cliques de play). */
.episode-play-icon {
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--accent-primary);
  color: #fff;
  box-shadow: var(--shadow-glow);
  display: flex;
  align-items: center;
  justify-content: center;
}

.episode-info {
  min-width: 0;
}

.episode-title {
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}


/* ─── Channel count badge ─── */
.channel-count {
  padding: 12px 16px;
  color: var(--text-tertiary);
  font-size: 0.78rem;
  font-weight: 500;
  display: none;
}

.channel-count.visible {
  display: block;
}

/* ═══════════════════════════════════════
   PLAYER OVERLAY
   ═══════════════════════════════════════ */
.player-overlay {
  position: fixed;
  top: 0; right: 0; bottom: 0; left: 0;
  z-index: 200;
  background: var(--bg-primary);
  display: flex;
  flex-direction: column;
  animation: playerIn 0.35s var(--ease-out);
}

.player-overlay.hidden {
  display: none;
}

@keyframes playerIn {
  from { opacity: 0; transform: translateY(100%); }
  to { opacity: 1; transform: translateY(0); }
}

.player-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  padding-top: calc(8px + var(--safe-top));
  background: var(--bg-glass-strong);
  border-bottom: 1px solid var(--border-subtle);
  min-height: 52px;
  transition: opacity 0.25s var(--ease-out);
}

/* In fullscreen, controls auto-hide after a few seconds of inactivity
   (see StreamPlayer._scheduleControlsHide) instead of staying on top of
   the video permanently. */
.player-overlay.controls-hidden .player-header,
.player-overlay.controls-hidden .player-controls {
  opacity: 0;
  pointer-events: none;
}

.player-overlay.controls-hidden .player-video-wrap {
  cursor: none;
}

/* No celular (max-width:560px, mesmo corte de barra-inferior/channel-grid)
   header e controles flutuam sobre o vídeo em vez de ficarem em barras fixas
   na coluna — o overlay do player já cobre a tela toda sozinho (`.player-
   overlay` é fixed), então ninguém ali aperta um botão separado de "tela
   cheia" (Fullscreen API) pra chegar nesse estado. Até 01/10/2026 o celular
   ficava preso no layout de coluna normal, onde header/controles são barras
   fixas que NUNCA somem de verdade (ver _deveAutoEsconder em player.js) — o
   toque na tela não tinha efeito nenhum, relatado ao vivo pelo dono. */
@media (max-width: 560px) {
  .player-header,
  .player-controls {
    position: absolute;
    left: 0;
    right: 0;
    z-index: 2;
    border: 0;
    padding-left: max(12px, env(safe-area-inset-left, 0px));
    padding-right: max(12px, env(safe-area-inset-right, 0px));
  }

  .player-header {
    top: 0;
    background: linear-gradient(to bottom, rgba(0, 0, 0, 0.8), transparent);
  }

  .player-controls {
    bottom: 0;
    background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);
  }
}

/* Mesma coisa de novo, agora pra tela cheia de VERDADE em telas largas — o
   celular já ganhou isso incondicionalmente no media query acima; aqui cobre
   quem clica o botão de tela cheia num tablet/computador (>560px, onde o
   media query não bate). Duplicado, não reaproveitado, de propósito: um
   `@media` dentro de `.is-fullscreen` tornaria as duas condições inseparáveis
   e qualquer TV antiga sem suporte a `:fullscreen` perderia os dois casos. */
.player-overlay.is-fullscreen .player-header,
.player-overlay.is-fullscreen .player-controls {
  position: absolute;
  left: 0;
  right: 0;
  z-index: 2;
  border: 0;
  /* Fallback antes do max(): TV antiga descarta a linha e ficaria sem padding. */
  padding-left: 12px;
  padding-right: 12px;
  padding-left: max(12px, env(safe-area-inset-left, 0px));
  padding-right: max(12px, env(safe-area-inset-right, 0px));
}

.player-overlay.is-fullscreen .player-header {
  top: 0;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.75), transparent);
}

.player-overlay.is-fullscreen .player-controls {
  bottom: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.75), transparent);
}

/* Mesmo ajuste do .control-btn acima: "Voltar" e "Picture in Picture" usam
   .icon-btn (compartilhado com o header da home), que também só clareia no
   :hover — sem efeito em touch. Aqui dentro, sobre vídeo, cinza apagado é
   o botão mais importante da tela ("como eu saio?") ficando difícil de ver. */
.player-header .icon-btn {
  color: var(--text-primary);
}

.player-info {
  flex: 1;
  min-width: 0;
}

.player-title {
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.player-group {
  font-size: 0.72rem;
  color: var(--text-tertiary);
}

.player-video-wrap {
  flex: 1;
  position: relative;
  background: #000;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

#video-player {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

#player-iframe {
  width: 100%;
  height: 100%;
  border: 0;
}

.player-loading {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  color: var(--text-secondary);
  font-size: 0.85rem;
  background: rgba(0, 0, 0, 0.6);
}

.player-loading.hidden {
  display: none;
}

.player-spinner {
  width: 40px;
  height: 40px;
  border: 3px solid var(--bg-tertiary);
  border-top-color: var(--accent-primary);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

.player-error {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  color: var(--danger);
  text-align: center;
  padding: 24px;
  background: rgba(0, 0, 0, 0.8);
}

.player-error.hidden {
  display: none;
}

.player-error p {
  color: var(--text-secondary);
  font-size: 0.85rem;
}

/* Player Controls */
.player-controls {
  background: var(--bg-glass-strong);
  border-top: 1px solid var(--border-subtle);
  padding: 12px 16px calc(12px + var(--safe-bottom));
  transition: opacity 0.25s var(--ease-out);
}

.player-progress-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-bottom: 10px;
}

.player-progress-row.hidden {
  display: none;
}

.player-time {
  font-size: 0.7rem;
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
  min-width: 32px;
  text-align: center;
  flex-shrink: 0;
}

.player-seek {
  flex: 1;
  height: 4px;
  border-radius: var(--radius-full);
  appearance: none;
  -webkit-appearance: none;
  background: var(--bg-tertiary);
  outline: none;
  cursor: pointer;
}

.player-seek::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--accent-primary);
  cursor: pointer;
  box-shadow: 0 0 6px var(--accent-glow);
}

.player-seek::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border: none;
  border-radius: 50%;
  background: var(--accent-primary);
  cursor: pointer;
}

.player-seek::-moz-range-track {
  height: 4px;
  border-radius: var(--radius-full);
  background: transparent;
}

.player-live-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding-bottom: 10px;
  color: var(--danger);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
}

.player-live-row.hidden {
  display: none;
}

.live-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--danger);
  box-shadow: 0 0 6px var(--danger);
  animation: liveDotPulse 1.5s ease-in-out infinite;
}

@keyframes liveDotPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}

.controls-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.control-btn {
  width: 46px;
  height: 46px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  /* --text-primary, não --text-secondary (ajuste de 01/10/2026): estes são os
     controles do player — avançar, voltar, mudo, tela cheia — e dependiam de
     :hover pra clarear. Hover não existe em touch, então no celular ficavam
     para sempre no cinza apagado (#a8a8a8), relatado ao vivo como "difícil
     de enxergar" sobre o fundo escuro/vídeo. */
  color: var(--text-primary);
  cursor: pointer;
  transition: all var(--duration-fast) ease;
}

.control-btn:hover {
  color: var(--text-primary);
  background: var(--bg-tertiary);
}

.control-btn:active {
  transform: scale(0.9);
}

.control-btn-main {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--accent-primary);
  color: #fff;
  box-shadow: var(--shadow-glow);
}

.control-btn-main:hover {
  color: #fff;
  background: var(--accent-primary);
  box-shadow: 0 0 30px var(--accent-glow);
}

.volume-wrap {
  display: flex;
  align-items: center;
  gap: 4px;
}

.volume-slider {
  width: 70px;
  height: 4px;
  border-radius: var(--radius-full);
  appearance: none;
  -webkit-appearance: none;
  background: var(--bg-tertiary);
  outline: none;
  cursor: pointer;
}

.volume-slider::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--accent-primary);
  cursor: pointer;
  box-shadow: 0 0 6px var(--accent-glow);
}

.volume-slider::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border: none;
  border-radius: 50%;
  background: var(--accent-primary);
  cursor: pointer;
}

/* Hide volume on very small mobile */
@media (max-width: 380px) {
  .volume-wrap {
    display: none;
  }
}

/* ═══════════════════════════════════════
   MODAL
   ═══════════════════════════════════════ */
.modal-overlay {
  position: fixed;
  top: 0; right: 0; bottom: 0; left: 0;
  z-index: 300;
  background: rgba(0, 0, 0, 0.8);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  animation: fadeIn var(--duration-fast) ease;
}

.modal-overlay.hidden {
  display: none;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

.modal {
  width: 100%;
  max-width: 480px;
  max-height: 85vh;
  max-height: 85dvh;
  background: var(--bg-secondary);
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  border: 1px solid var(--border-subtle);
  border-bottom: none;
  overflow-y: auto;
  animation: modalSlideUp 0.35s var(--ease-out);
  padding-bottom: var(--safe-bottom);
}

@keyframes modalSlideUp {
  from { transform: translateY(100%); }
  to { transform: translateY(0); }
}

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px 20px 0;
}

.modal-title {
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 700;
}

.modal-body {
  padding: 20px;
}

/* ─── Account modal (Minha Conta) ─── */
.account-info-list {
  display: flex;
  flex-direction: column;
  margin-bottom: 20px;
}

.account-info-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 0;
  border-bottom: 1px solid var(--border-subtle);
}

.account-info-row:last-child {
  border-bottom: none;
}

.account-info-label {
  font-size: 0.85rem;
  color: var(--text-secondary);
}

.account-info-value {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--text-primary);
}

/* ─── Category upsell modal (sinopse + preço de categoria bloqueada) ─── */
.category-upsell-cover {
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-lg);
  background-size: cover;
  background-position: center;
  margin-bottom: 16px;
}

.category-upsell-synopsis {
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--text-secondary);
  margin-bottom: 16px;
}

/* Linha de dados da ficha (ano · gênero · nota). Capa e sinopse já vêm do
   diálogo de categoria, que mostra exatamente as mesmas duas coisas. */
.ficha-meta {
  font-size: 0.82rem;
  color: var(--text-tertiary);
  margin-bottom: 12px;
}

/* O login dentro da ficha. Sem borda e sem caixa em volta: o diálogo já é a
   caixa, e uma moldura dentro da outra encolhe o campo justamente onde ele
   precisa ser fácil de acertar. */
.ficha-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.ficha-chamada {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--text-primary);
  text-align: center;
  margin: 4px 0 0;
}

.ficha-assinar {
  display: block;
  margin-top: 16px;
  text-align: center;
  font-size: 0.85rem;
  color: var(--text-secondary);
  text-decoration: underline;
}

.ficha-assinar:hover,
.ficha-assinar:active {
  color: var(--text-primary);
}

.category-upsell-price-row {
  display: flex;
  align-items: baseline;
  justify-content: center;
  margin-bottom: 16px;
}

.category-upsell-price {
  font-family: var(--font-display);
  font-size: 1.6rem;
  font-weight: 800;
  background: var(--accent-primary);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.category-upsell-price span {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-secondary);
  -webkit-text-fill-color: var(--text-secondary);
}

/* Modal Tabs */
.modal-tabs {
  display: flex;
  gap: 8px;
  margin-bottom: 20px;
}

.modal-tab {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px;
  border-radius: var(--radius-md);
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--text-tertiary);
  background: var(--bg-tertiary);
  cursor: pointer;
  transition: all var(--duration-fast) ease;
  border: 1px solid transparent;
}

.modal-tab:hover {
  color: var(--text-secondary);
}

.modal-tab.active {
  color: var(--accent-primary);
  background: rgba(229, 9, 20, 0.12);
  border-color: var(--border-accent);
}

/* Modal Tab Content */
.modal-tab-content {
  display: none;
}

.modal-tab-content.active {
  display: block;
  animation: fadeInUp 0.3s var(--ease-out);
}

/* Feedback (Conta e ajuda -> Sugestões e problemas). Classe própria em vez de
   reaproveitar .modal-tab: aquela é lida por um seletor global
   ($$('.modal-tab')) que pertence ao modal de "Carregar Lista" — reusar o
   nome faria um clique ali mexer nestes botões também. */
.feedback-tabs {
  display: flex;
  gap: 8px;
  margin-bottom: 16px;
}

.feedback-tab {
  flex: 1;
  padding: 12px;
  border-radius: var(--radius-md);
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--text-tertiary);
  background: var(--bg-tertiary);
  cursor: pointer;
  border: 1px solid transparent;
  transition: all var(--duration-fast) ease;
  text-align: center;
}

.feedback-tab.active {
  color: var(--accent-primary);
  background: rgba(229, 9, 20, 0.12);
  border-color: var(--border-accent);
}

.feedback-textarea {
  display: block;
  width: 100%;
  min-height: 130px;
  padding: 14px 16px;
  font-size: 1rem;
  font-family: inherit;
  color: var(--text-primary);
  background: var(--bg-tertiary);
  border: 2px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  resize: vertical;
  transition: border-color var(--duration-normal) var(--ease-out), box-shadow var(--duration-normal) var(--ease-out);
}

.feedback-textarea::placeholder {
  color: var(--text-tertiary);
}

.feedback-textarea:focus {
  outline: none;
  border-color: var(--accent-primary);
  box-shadow: 0 0 0 4px var(--accent-glow);
}

.feedback-msg {
  margin: 12px 0 0;
  font-size: 0.95rem;
  font-weight: 500;
}

.feedback-msg.erro {
  color: var(--danger);
}

.feedback-msg.sucesso {
  color: var(--success);
}

#btn-feedback-enviar {
  margin-top: 16px;
}

/* Drop Zone */
.drop-zone {
  border: 2px dashed var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 40px 24px;
  text-align: center;
  cursor: pointer;
  transition: all var(--duration-normal) ease;
  position: relative;
  color: var(--text-tertiary);
}

.drop-zone:hover,
.drop-zone.drag-over {
  border-color: var(--accent-primary);
  background: rgba(229, 9, 20, 0.12);
  color: var(--accent-primary);
}

.drop-zone svg {
  margin-bottom: 12px;
  opacity: 0.5;
}

.drop-zone-text {
  font-size: 0.9rem;
  color: var(--text-secondary);
  margin-bottom: 6px;
}

.drop-zone-hint {
  font-size: 0.78rem;
  color: var(--text-tertiary);
}

#file-input {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
}

/* URL Input */
.url-input-group {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.url-label {
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--text-secondary);
}

.url-input {
  padding: 14px 16px;
  border-radius: var(--radius-md);
  background: var(--bg-tertiary);
  border: 1px solid var(--border-subtle);
  color: var(--text-primary);
  /* 16px pelo mesmo motivo do campo de busca: sem `user-scalable=no`, fonte
     menor faz o iOS dar zoom ao focar. */
  font-size: 16px;
  transition: border-color var(--duration-fast) ease;
}

.url-input::placeholder {
  color: var(--text-tertiary);
}

.url-input:focus {
  border-color: var(--border-accent);
  box-shadow: 0 0 0 3px rgba(229, 9, 20, 0.1);
}

/* Modal Status */
.modal-status {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 16px 20px;
  background: rgba(229, 9, 20, 0.12);
  color: var(--text-secondary);
  font-size: 0.85rem;
}

.modal-status.hidden {
  display: none;
}

.status-spinner {
  width: 18px;
  height: 18px;
  border: 2px solid var(--bg-tertiary);
  border-top-color: var(--accent-primary);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}

/* ═══════════════════════════════════════
   TOAST NOTIFICATIONS
   ═══════════════════════════════════════ */
.toast-container {
  position: fixed;
  top: calc(var(--header-height) + var(--safe-top) + 8px);
  left: 16px;
  right: 16px;
  z-index: 500;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
}

.toast {
  background: var(--bg-glass-strong);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: 12px 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.85rem;
  color: var(--text-primary);
  box-shadow: var(--shadow-lg);
  animation: toastIn 0.35s var(--ease-spring);
  pointer-events: auto;
}

.toast.toast-out {
  animation: toastOut 0.3s var(--ease-out) forwards;
}

.toast-success {
  border-left: 3px solid var(--success);
}

.toast-error {
  border-left: 3px solid var(--danger);
}

.toast-info {
  border-left: 3px solid var(--accent-primary);
}

@keyframes toastIn {
  from { opacity: 0; transform: translateY(-20px) scale(0.95); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

@keyframes toastOut {
  from { opacity: 1; transform: translateY(0); }
  to { opacity: 0; transform: translateY(-20px) scale(0.9); }
}

/* ═══════════════════════════════════════
   RESPONSIVE ADJUSTMENTS
   ═══════════════════════════════════════ */

/* Tablets */
@media (min-width: 600px) {
  .channel-grid {
    grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
    gap: 16px;
    padding: 20px;
  }

  .modal {
    border-radius: var(--radius-xl);
    border-bottom: 1px solid var(--border-subtle);
    margin: auto;
    max-height: 80vh;
    max-height: 80dvh;
  }

  .modal-overlay {
    align-items: center;
    padding: 20px;
  }

  @keyframes modalSlideUp {
    from { opacity: 0; transform: translateY(30px) scale(0.95); }
    to { opacity: 1; transform: translateY(0) scale(1); }
  }
}

/* Desktop */
@media (min-width: 900px) {
  .channel-grid {
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 20px;
    padding: 24px;
  }

  .empty-actions {
    flex-direction: row;
    max-width: 420px;
  }

  .player-overlay {
    flex-direction: column;
  }
}

/* Large Desktop */
@media (min-width: 1200px) {
  .channel-grid {
    max-width: 1400px;
    margin: 0 auto;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  }

  .main-content {
    max-width: 1440px;
    margin: 0 auto;
    width: 100%;
  }
}

/* ─── Haptic-like touch feedback ─── */
@media (hover: none) {
  .channel-card:active {
    transform: scale(0.95);
    transition-duration: 100ms;
  }

  .card-play-overlay {
    opacity: 0 !important;
  }
}

/* ─── Utility ─── */
.hidden {
  display: none !important;
}

/* Scrollbar Styling */
::-webkit-scrollbar {
  width: 4px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: var(--bg-tertiary);
  border-radius: var(--radius-full);
}

::-webkit-scrollbar-thumb:hover {
  background: var(--text-tertiary);
}

/* ═══════════════════════════════════════
   LEVEZA EM APARELHO FRACO (TV Android antiga)
   ═══════════════════════════════════════
   Aqui existiam 15 `backdrop-filter: blur(...)`. Todos ficavam sobre
   --bg-glass-strong, que já é 92% opaco — o blur quase não aparecia e mesmo
   assim obrigava o navegador a compor uma camada do tamanho da tela a cada
   quadro. Em GPU de TV antiga é o que fazia o scroll travar. Removidos: o
   fundo sólido dá o mesmo resultado visual de graça.

   As duas regras abaixo cortam o resto do custo em quem pede menos movimento
   (o próprio sistema da TV costuma pedir) e em telas de toque grosso. */

/* Um card entrando com animação é bonito no celular; 120 deles animando ao
   mesmo tempo numa TV antiga é meio segundo de tela travada. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ═══════════════════════════════════════
   FOCO PARA CONTROLE REMOTO (D-pad)
   ═══════════════════════════════════════
   Num controle remoto não existe cursor: o único jeito de saber onde se está é
   o anel de foco. Ele precisa ser grosso e claro o suficiente para ser visto do
   sofá, e por isso é mais forte que o :focus-visible padrão do resto do app. */
body.tv-nav :focus-visible,
body.tv-nav .tv-focus {
  outline: 3px solid var(--accent-primary);
  outline-offset: 3px;
  border-radius: var(--radius-md);
}

body.tv-nav .channel-card:focus-visible,
body.tv-nav .category-tile:focus-visible,
body.tv-nav .banner-slide:focus-visible {
  outline-width: 4px;
  box-shadow: 0 0 0 4px rgba(229, 9, 20, 0.25);
}

/* O card focado cresce, do jeito Netflix — só `transform`, que é composto
   pela GPU e não empurra o layout da fileira (ao contrário de mudar
   width/margin, que obrigaria a repintar os vizinhos a cada tecla). O
   `z-index` evita o card crescido ficar coberto pelo vizinho da direita numa
   grade apertada. */
body.tv-nav .channel-card:focus-visible {
  transform: scale(1.08);
  z-index: 2;
}

/* As setas de rolagem da fileira (mouse/touch) atrapalhavam o D-pad: eram
   focáveis feito qualquer botão, então navegar por uma fileira parava nelas
   entre um card e outro — a "setinha" no meio do caminho que o controle
   remoto tinha que desviar. No D-pad quem rola a fileira é o próprio foco
   indo de card em card (scrollIntoView em tv-nav.js), então a seta não faz
   falta nenhuma — só estorva. */
body.tv-nav .faixa-seta {
  display: none;
}

/* ═══════════════════════════════════════
   BANNER DA HOME (slides curados no admin)
   ═══════════════════════════════════════
   Regra que vale para tudo aqui: nada de backdrop-filter, nada de animação
   contínua e nada de sombra grande. O alvo são TVs Android antigas, onde blur
   e sombra em elemento do tamanho da tela custam quadros no scroll. */
.home-banner {
  position: relative;
  margin: 0 0 18px;
}

.banner-track {
  position: relative;
  width: 100%;
  /* Quadrado no celular. A arte vem em 16:9 (backdrop do TMDB) e o herói agora
     carrega título de cartaz, etiquetas, sinopse e dois botões — em 4/3 o
     degradê subia até a testa dos atores. Retrato de verdade (3/4) cortaria
     metade da largura do backdrop e deixaria gente de fora do quadro; 1/1 é o
     ponto em que cabe o texto e a arte continua reconhecível.
     Travar a proporção reserva o espaço antes da imagem chegar. */
  aspect-ratio: 1 / 1;
  max-height: 68vh;
  max-height: 68dvh;
  overflow: hidden;
  /* Sem cantos: o hero encosta nas bordas da tela, e .main-content não tem
     padding lateral, então já era full-bleed — só o raio o segurava. */
  background: var(--bg-secondary);
}

/* Navegador antigo sem aspect-ratio: altura fixa razoável em vez de colapsar. */
@supports not (aspect-ratio: 1 / 1) {
  .banner-track { height: 380px; }
}

/* Em tela larga o quadrado viraria uma parede: a partir do tablet a arte volta
   ao formato de cinema, que é a proporção em que ela foi feita. */
@media (min-width: 700px) {
  .banner-track {
    aspect-ratio: 16 / 9;
    max-height: 72vh;
    max-height: 72dvh;
  }
}

.banner-slide {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  cursor: pointer;
  display: block;
  /* Cada troca de slide é um ELEMENTO NOVO (showBannerSlide recria o card
     inteiro, app.js) — então uma animation aqui dispara sozinha a cada troca,
     sem o JS precisar saber nada de CSS. Entra com um fade+leve aproximação,
     não um corte seco. */
  animation: bannerSlideIn 700ms var(--ease-out) both;
}

@keyframes bannerSlideIn {
  from { opacity: 0; transform: scale(1.03); }
  to { opacity: 1; transform: scale(1); }
}

.banner-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Zoom lento tipo documentário (Ken Burns) enquanto o slide fica em cartaz —
   dura mais que o intervalo de troca (BANNER_INTERVAL_MS, 7s) de propósito:
   a imagem nunca "termina" o movimento, então nunca fica óbvio que é um loop.
   Só quando o sistema não pediu menos movimento — mesma guarda de
   startBannerAutoplay() em app.js, agora espelhada no CSS puro. */
@media (prefers-reduced-motion: no-preference) {
  .banner-img {
    animation: bannerKenBurns 9s ease-out both;
  }
}

@keyframes bannerKenBurns {
  from { transform: scale(1); }
  to { transform: scale(1.09); }
}

/* Imagem fora do ar deixa só o gradiente — o texto continua legível. */
.banner-slide--noimg .banner-img { display: none; }
.banner-slide--noimg { background: var(--bg-tertiary); }

/* Degradê chapado (sem blur) para o texto ter contraste sobre qualquer arte. */
.banner-shade {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  background: linear-gradient(0deg, rgba(10, 10, 10, 1) 0%, rgba(10, 10, 10, 0.92) 18%, rgba(10, 10, 10, 0.45) 48%, rgba(10, 10, 10, 0) 78%);
}

.banner-copy {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 16px 16px 22px;
  max-width: 720px;
}

/* Sobrancelha: barrinha vermelha + rótulo. O traço é ::before para não virar
   mais um elemento no innerHTML do slide. */
.banner-eyebrow {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #fff;
  margin-bottom: 8px;
}

.banner-eyebrow::before {
  content: '';
  width: 4px;
  height: 15px;
  border-radius: 2px;
  background: var(--accent-primary);
}

.banner-title {
  font-family: var(--font-cartaz);
  font-size: 2.4rem; /* fallback: clamp() só existe do Chrome 79 pra frente */
  font-size: clamp(2.2rem, 11vw, 3.8rem);
  font-weight: 400; /* Anton só tem um peso; pedir 800 faz o navegador engordar
                       a fonte na mão e o desenho da letra suja */
  text-transform: uppercase;
  letter-spacing: 0.005em;
  line-height: 0.92;
  margin: 0;
  color: #fff;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.65);
}

/* Linha de etiquetas sob o título (gênero, "Dublado", o que o admin escrever
   no subtítulo do slide). */
.banner-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
}

.banner-chip {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--text-primary);
  border: 1px solid rgba(255, 255, 255, 0.35);
  padding: 4px 11px;
  border-radius: var(--radius-sm);
}

/* O verde é o único sinal da tela que não é vermelho: ele quer dizer uma coisa
   só, "isto toca agora", e por isso aparece aqui e na etiqueta da capa. */
.banner-selo {
  font-size: 0.82rem;
  font-weight: 800;
  color: var(--success);
}

.banner-sinopse {
  margin: 12px 0 0;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--text-secondary);
  /* Três linhas: o suficiente para dar o gancho sem empurrar os botões para
     fora da arte. */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.banner-acoes {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 16px;
}

.banner-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  font-size: 0.95rem;
  font-weight: 700;
  color: #0a0a0a;
  background: #fff;
  padding: 13px 26px;
  border-radius: var(--radius-md);
  cursor: pointer;
  /* Profundidade real, não só cor chapada — o botão primário é a ação que
     mais importa na tela inteira, e sombra é o que separa "clicável" de
     "etiqueta". Reagir ao toque (hover sobe, active desce) é o que faltava
     pra parecer físico em vez de uma lousa plana. */
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);
  transition: transform var(--duration-fast) var(--ease-out), box-shadow var(--duration-fast) var(--ease-out), background-color var(--duration-fast) ease;
}

.banner-cta:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.45);
}

.banner-cta:active {
  transform: translateY(0) scale(0.97);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3);
}

/* "Detalhes": mesmo tamanho do "Assistir" para o toque não errar, peso visual
   menor para não disputar com ele. Vidro, não cinza chapado — mesma
   linguagem do blur da barra inferior flutuante, pra reforma inteira ler como
   um sistema só, não dois estilos colados. */
.banner-cta--fraco {
  color: var(--text-primary);
  background: rgba(255, 255, 255, 0.14);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.22);
  box-shadow: none;
}

.banner-cta--fraco:hover {
  background: rgba(255, 255, 255, 0.24);
  box-shadow: none;
}

.banner-cta--fraco:active {
  background: rgba(255, 255, 255, 0.3);
}

.banner-dots {
  display: flex;
  justify-content: center;
  gap: 7px;
  margin-top: 10px;
}

.banner-dot {
  width: 7px;
  height: 7px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--text-tertiary);
  cursor: pointer;
  /* Bolinha de 7px é alvo de toque pequeno demais; a área clicável cresce sem
     mexer no desenho. */
  box-shadow: 0 0 0 7px transparent;
  transition: width var(--duration-normal) var(--ease-out), background-color var(--duration-normal) ease;
}

.banner-dot.active {
  background: var(--accent-primary);
  width: 20px;
  border-radius: var(--radius-full);
}

/* ─── Fallbacks de TV antiga (Samsung/LG, Firestick — Chrome 63-87) ───
   aspect-ratio só chegou no Chrome 88. Sem ele a caixa colapsa pra zero e a
   grade vira uma fileira de nada, que é como o app aparecia nessas telas.
   Altura fixa não guarda a proporção exata, mas o object-fit/background-size
   cover corta a imagem e tudo continua visível e clicável. */
@supports not (aspect-ratio: 1 / 1) {
  .card-thumb { height: 200px; }
  /* .category-tile saiu daqui: virou pílula, com altura própria de 38px e sem
     aspect-ratio nenhum — não há mais o que remendar. */
  .series-detail-cover { height: 147px; }  /* 110px de largura em 3/4 */
  .category-upsell-cover { height: 240px; }
}

@media (min-width: 1024px) {
  @supports not (aspect-ratio: 1 / 1) {
    /* Nesta faixa a grade usa colunas de 200px+, então 200px de altura
       deixaria a capa quadrada demais. */
    .card-thumb { height: 280px; }
  }
}

/* ─── Aviso global (troca do número de suporte) ───
   Não é a faixa fininha das outras (.trial-bar): o texto é uma frase inteira
   e o público é 60+, então ela ocupa espaço de propósito e o botão tem o
   mesmo peso do "Comprar agora". Some por dispensa ou por data (ver app.js). */
.aviso-bar {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
  padding: 14px 16px calc(14px + var(--safe-bottom, 0px));
  background: var(--bg-secondary);
  border-bottom: 2px solid var(--accent-primary);
}

.aviso-bar.hidden {
  display: none;
}

.aviso-texto {
  margin: 0;
  color: var(--text-primary);
  font-size: 0.95rem;
  line-height: 1.45;
  text-align: center;
}

.aviso-acao {
  width: 100%;
}

.aviso-dispensar {
  width: 100%;
  color: var(--text-secondary);
  border-color: var(--text-tertiary);
}

/* Em tela larga o texto e os botões cabem lado a lado sem virar um bloco
   gigante no topo. */
@media (min-width: 720px) {
  .aviso-bar {
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 16px;
  }
  .aviso-texto { text-align: left; }
  .aviso-acao, .aviso-dispensar { width: auto; flex-shrink: 0; }
}

/* ─── Continue Assistindo ─── */
/* A faixa é filha da .channel-grid (ver criarFaixaContinuar), então ocupa a
   linha inteira e rola na horizontal em vez de virar mais uma coluna. */
.continue-row {
  grid-column: 1 / -1;
  margin-bottom: 4px;
}

/* ═══════════════════════════════════════
   A FILEIRA DE RETOMAR É A MAIS ÚTIL DA HOME
   ═══════════════════════════════════════

   É a única que sabe onde a cliente estava. Ela tinha exatamente o mesmo peso
   visual das outras — mesmo título pequeno, mesma barra de 4px quase invisível
   em cima de uma capa escura — e disputava atenção de igual para igual com
   prateleiras que ela ainda vai escolher.

   Nada aqui muda de tamanho: capa maior empurraria o resto da home para baixo
   da dobra no celular. O que muda é contraste. */
.continue-row {
  margin-bottom: 14px;
}

/* Descendente, não filho direto: o título mora dentro de .faixa-cabecalho
   agora (ver-tudo divide a linha com ele — ver criarFaixa em app.js). */
.continue-row .continue-row-title {
  font-size: 1.05rem;
  letter-spacing: -0.01em;
}

/* A barra é o dado: diz quanto falta. 4px sobre capa escura sumia. */
.continue-row .card-progress {
  height: 6px;
  background: rgba(0, 0, 0, 0.7);
}

.continue-row .card-progress span {
  border-radius: 0 3px 3px 0;
  box-shadow: 0 0 10px var(--accent-primary);
}

/* "T1 · E14" é o que ela procura no cartão — some no cinza terciário. */
.continue-row .card-group {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-secondary);
}

.continue-row .card-group-dot {
  opacity: 1;
}

/* 1.15rem/800, não 0.95rem/700 (01/10/2026): a Netflix abre cada fileira com
   um título que domina a linha, não um rótulo discreto — a capa já é a
   atração, o nome da fileira só precisa ser lido rápido ao rolar. */
.continue-row-title {
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--text-primary);
  margin-bottom: 10px;
}

/* Título e "Ver tudo" na mesma linha — pedido do dono (10/09/2026), igual à
   home do SuperFlixAPI: cada fileira de tipo (Séries/Minisséries) tem um
   link à direita do nome. */
.faixa-cabecalho {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}

.faixa-cabecalho .continue-row-title {
  margin-bottom: 0;
}

/* Barrinha vermelha antes do nome — mesma linguagem do "Destaque de hoje"
   do herói (.banner-eyebrow), só que vertical e ao lado do título em vez de
   embutida numa sobrancelha. Só nas fileiras por TIPO da Home; as outras
   (Continue assistindo, gênero) continuam sem ela. */
.faixa-titulo-com-barra {
  display: flex;
  align-items: center;
  gap: 8px;
}

.faixa-titulo-com-barra::before {
  content: '';
  width: 4px;
  height: 16px;
  border-radius: 2px;
  background: var(--accent-primary);
  flex-shrink: 0;
}

.faixa-ver-tudo {
  display: flex;
  align-items: center;
  gap: 2px;
  flex-shrink: 0;
  background: none;
  border: none;
  padding: 4px 0;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  cursor: pointer;
  transition: color var(--duration-fast) ease;
}

.faixa-ver-tudo:hover,
.faixa-ver-tudo:focus-visible {
  color: var(--text-primary);
}

.faixa-ver-tudo svg {
  width: 14px;
  height: 14px;
}

/* Fileira de tipo sem catálogo ainda (Minisséries) — um aviso só, sem pista
   de cartão nenhuma pra rolar (ver criarFaixa). */
.faixa-em-breve {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 16px 18px;
  border: 1px dashed var(--border-subtle);
  border-radius: 10px;
  background: var(--bg-tertiary);
  color: var(--text-tertiary);
  font-size: 0.85rem;
  font-weight: 600;
}

.faixa-em-breve svg {
  flex-shrink: 0;
  opacity: 0.6;
}

.faixa-pista {
  position: relative;
}

.continue-track {
  display: flex;
  /* 8px, não 12px (01/10/2026, referência Netflix): fileira mais cheia, mais
     capa visível de uma vez sem rolar — o espaço vazio entre cartões não
     ajuda ninguém a escolher. */
  gap: 8px;
  overflow-x: auto;
  /* Espaço para o translateY(-2px) do hover e para o foco da TV não cortar. */
  padding: 4px 0 8px;
  scroll-snap-type: x proximity;
  /* A barra de rolagem sai: quem manda andar são as setas. Ela ficava atravessada
     embaixo de cada fileira, cinza, e numa home com sete fileiras viravam sete
     riscos horizontais competindo com as capas. */
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.continue-track::-webkit-scrollbar {
  display: none;
}

/* As setas ficam SOBRE as bordas da pista, centradas na altura das capas.
   Redondas e escuras para se lerem por cima de qualquer capa que passe por
   baixo — capa clara com seta clara some. */
.faixa-seta {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 1px solid var(--border-subtle);
  border-radius: 50%;
  background: rgba(10, 10, 10, 0.82);
  color: var(--text-primary);
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--duration-fast) ease, background-color var(--duration-fast) ease;
}

.faixa-seta--antes { left: -6px; }
.faixa-seta--depois { right: -6px; }

/* Aparecem quando o ponteiro entra na fileira. Sempre visíveis poluiriam a
   home inteira; e no celular não aparecem nunca — lá o dedo arrasta. */
.faixa-pista:hover .faixa-seta,
.faixa-seta:focus-visible {
  opacity: 1;
}

.faixa-seta:hover {
  background: rgba(10, 10, 10, 0.95);
}

.faixa-seta.hidden {
  display: none;
}

/* Aparelho de toque não tem ponteiro para passar por cima, e a seta ficaria
   um enfeite tapando meia capa. Lá o gesto é arrastar. */
@media (hover: none), (max-width: 560px) {
  .faixa-seta {
    display: none;
  }
}

.continue-track .channel-card {
  /* 136px, não 150px: com o gap de 8px cabe mais de meia capa a mais por
     fileira na tela do celular — mais perto da densidade de prateleira da
     Netflix, sem a capa ficar pequena a ponto de perder o rosto do pôster. */
  flex: 0 0 136px;
  scroll-snap-align: start;
}

@media (min-width: 561px) {
  .continue-track .channel-card {
    flex-basis: 160px;
  }
}

.card-progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 4px;
  background: rgba(0, 0, 0, 0.55);
  z-index: 1;
}

.card-progress span {
  display: block;
  height: 100%;
  background: var(--accent-primary);
}

/* ─── "Feito pra você": conta, suporte e termos ───
   Linha grande, ícone grande, alvo grande: é a parte do app que o público de
   60+ mais erra no toque, e ela ficava atrás de um ícone de 40px no header. */
.para-voce {
  padding: 26px 0 4px;
}

.para-voce.hidden {
  display: none;
}

/* Três atalhos lado a lado, e não três faixas empilhadas.
   Empilhados, ocupavam quase um terço da tela do celular para dizer três
   palavras — e são o RODAPÉ: a cliente vem aqui de vez em quando, não é o que
   ela veio fazer. Lado a lado eles cabem numa faixa e devolvem o espaço às
   capas.

   Continua grade de três colunas em qualquer largura: são três e sempre serão
   três, então nada de quebrar uma para a linha de baixo e deixar o conjunto
   torto. */
.para-voce-lista {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  padding: 0 16px;
}

.para-voce-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 7px;
  width: 100%;
  /* 44px é o piso do alvo que a mão de 60 anos acerta sem mirar; aqui sobra. */
  min-height: 88px;
  padding: 12px 6px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--duration-fast) ease;
}

.para-voce-item:hover,
.para-voce-item:active {
  background: var(--bg-card-hover);
}

.para-voce-icone {
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  background: rgba(229, 9, 20, 0.14);
  display: flex;
  align-items: center;
  justify-content: center;
}

.para-voce-icone svg {
  width: 19px;
  height: 19px;
}

/* Eram emojis. Emoji é desenho de outra pessoa: muda de forma em cada sistema
   (o mesmo ícone é chapado no Android, brilhante no iPhone, quadrado na TV), e
   nenhum deles combina com a marca. Trocado por traço próprio, na mesma
   espessura dos outros ícones do projeto, e o vermelho é o da marca. */
.para-voce-icone svg {
  color: var(--accent-primary);
}

.para-voce-texto {
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.para-voce-titulo {
  font-family: var(--font-display);
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.2;
}

/* A linha de apoio e a seta saem no formato lado a lado: em 110px de largura
   "Plano, vencimento e aparelhos" viraria quatro linhas de letra miúda, e a
   seta apontaria para o nada num bloco que não é mais uma faixa. O nome do
   atalho já diz o que ele faz. */
.para-voce-sub,
.para-voce-seta {
  display: none;
}

/* O título desta seção fica centralizado sobre os três atalhos. Só o desta:
   "Categorias" e "Todas as novelas" abrem fileiras que começam na margem
   esquerda, e um título centralizado ali brigaria com o conteúdo. */
.para-voce .category-section-title {
  text-align: center;
}

/* ─── O sino ─────────────────────────────────────────────────────────────── */

.sino {
  position: relative;
}

.sino.hidden {
  display: none;
}

/* A bolinha vermelha em cima do sino. Fica FORA do fluxo para não empurrar o
   ícone quando o número aparece — sem isso o topo dança a cada aviso novo. */
.sino-contador {
  position: absolute;
  top: 2px;
  right: 2px;
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: 100px;
  background: var(--accent-primary);
  color: #fff;
  font-size: 0.63rem;
  font-weight: 800;
  line-height: 17px;
  text-align: center;
  pointer-events: none;
}

.sino-contador.hidden {
  display: none;
}

.avisos-lista {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.aviso {
  display: block;
  width: 100%;
  padding: 13px 14px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  text-align: left;
  text-decoration: none;
  color: inherit;
}

/* O que ela ainda não leu ganha um traço vermelho na lateral. Cor sozinha não
   bastaria: parte do público tem dificuldade com contraste, e a posição do
   traço informa mesmo para quem não distingue o tom. */
.aviso.novo {
  border-left: 3px solid var(--accent-primary);
}

.aviso-titulo {
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 3px;
}

.aviso-texto {
  font-size: 0.85rem;
  color: var(--text-secondary);
  line-height: 1.45;
}

.aviso-quando {
  display: block;
  margin-top: 7px;
  font-size: 0.72rem;
  color: var(--text-tertiary);
}

.avisos-vazio {
  padding: 26px 10px;
  text-align: center;
  color: var(--text-tertiary);
  font-size: 0.85rem;
}

/* ─── Rodapé da home ─── */
.home-footer {
  padding: 28px 16px calc(8px + var(--safe-bottom));
  text-align: center;
  color: var(--text-tertiary);
  font-size: 0.78rem;
  line-height: 1.7;
  border-top: 1px solid var(--border-subtle);
  margin-top: 28px;
}

.home-footer p { margin: 0; }

/* ═══════════════════════════════════════
   VITRINE DE VENDA — porte literal da prévia aprovada
   ═══════════════════════════════════════
   Este é o CSS da prévia que foi aprovada, copiado sem mudar valor nenhum.
   Só duas coisas foram tocadas, e as duas por obrigação:

   1. ESCOPO. Todo seletor ganhou `#venda-pagina` na frente, e `:root`/`body`
      viraram a própria raiz. A prévia usa nomes curtos e genéricos (.b, .sec,
      .pl, .hero) que colidiriam com o app inteiro. Escopado, os dois convivem
      e mexer aqui não tem como quebrar o catálogo.

   2. AS DUAS PROPRIEDADES QUE A TV NÃO ACEITA. `inset: 0` virou as quatro
      bordas (Chrome 87) e `aspect-ratio` virou altura fixa (Chrome 88) —
      mesmo desenho, sintaxe que a TV Android entende.

   Reescrever isto "integrando ao app" já foi tentado e deu errado: a página
   chegou irreconhecível e teve de ser refeita. Se for mexer, mexa nos valores
   daqui — não traduza para as classes do app. */
#venda-pagina{
    --bg:#0a0a0a; --s1:#141414; --s2:#1f1f1f; --s3:#262626;
    --line:rgba(255,255,255,.09); --line2:rgba(255,255,255,.16);
    --red:#e50914; --ink:#f5f5f5; --ink2:#a8a8a8; --ink3:#6e6e6e;
    --ok:#4ade80; --warn:#fbbf24;
    --display:Anton,Impact,"Arial Narrow",sans-serif;
    --ui:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
  }#venda-pagina *{box-sizing:border-box;}#venda-pagina{background:var(--bg);color:var(--ink);font-family:var(--ui);line-height:1.6;
       margin:0;padding:0 18px 70px;-webkit-font-smoothing:antialiased;}#venda-pagina .doc-top h1{font-family:var(--display);font-weight:400;font-size:clamp(32px,6.4vw,50px);
              line-height:1.03;text-transform:uppercase;margin:0 0 15px;text-wrap:balance;}#venda-pagina .v2{background:var(--bg);}#venda-pagina .b{display:inline-flex;align-items:center;justify-content:center;gap:8px;font-family:var(--ui);
     font-weight:800;letter-spacing:.02em;border-radius:10px;white-space:nowrap;border:1px solid transparent;}#venda-pagina .b-lg{height:54px;padding:0 30px;font-size:15.5px;}#venda-pagina .b-md{height:44px;padding:0 20px;font-size:14px;}#venda-pagina .b-sm{height:38px;padding:0 16px;font-size:13px;}#venda-pagina .b-red{background:var(--red);color:#fff;}#venda-pagina .b-out{background:transparent;color:var(--ink);border-color:var(--line2);}#venda-pagina .nav{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:16px 24px;
       border-bottom:1px solid var(--line);}#venda-pagina .marca{font-family:var(--display);font-size:23px;letter-spacing:-.01em;text-transform:uppercase;}#venda-pagina .marca .d{color:var(--ink);}#venda-pagina .marca .tv{color:var(--red);}#venda-pagina .nav-dir{display:flex;align-items:center;gap:10px;}#venda-pagina .nav-entrar{color:var(--ink2);font-size:14px;font-weight:600;padding:0 6px;}#venda-pagina .hero{position:relative;padding:66px 24px 54px;text-align:center;overflow:hidden;}#venda-pagina .hero-fundo{position:absolute;top:0;right:0;bottom:0;left:0;
    background:radial-gradient(105% 78% at 50% 0%,#2c1a1d 0%,transparent 60%),
               radial-gradient(80% 60% at 82% 96%,#1a1418 0%,transparent 62%),var(--bg);}#venda-pagina .hero-in{position:relative;max-width:640px;margin:0 auto;}#venda-pagina .olho{font-size:11.5px;font-weight:700;letter-spacing:.19em;text-transform:uppercase;
        color:var(--ink3);margin:0 0 18px;}#venda-pagina .hero h1{font-family:var(--display);font-weight:400;font-size:clamp(38px,7.4vw,66px);
           line-height:1.08;text-transform:uppercase;letter-spacing:-.005em;
           margin:0 0 18px;text-wrap:balance;}#venda-pagina .hero h1 em{font-style:normal;color:var(--red);}#venda-pagina .hero-sub{font-size:17px;color:var(--ink2);margin:0 auto 28px;max-width:46ch;}#venda-pagina .hero-cta{display:flex;flex-direction:column;align-items:center;gap:14px;}#venda-pagina .hero-link{color:var(--ink2);font-size:14.5px;font-weight:600;text-decoration:underline;
             text-underline-offset:4px;}#venda-pagina .hero-nota{margin:18px 0 0;font-size:13px;color:var(--ink3);}#venda-pagina .ap{text-align:center;}#venda-pagina .ap-ic{display:block;margin:0 auto 10px;color:var(--red);}#venda-pagina .ap-t{font-size:14.5px;font-weight:700;margin:0 0 3px;}#venda-pagina .ap-d{font-size:13px;color:var(--ink2);margin:0;}#venda-pagina .sec{padding:56px 24px;}#venda-pagina .sec-t{font-family:var(--display);font-weight:400;font-size:clamp(27px,4.4vw,38px);line-height:1.1;
         text-transform:uppercase;text-align:center;margin:0 0 8px;letter-spacing:-.005em;}#venda-pagina .sec-s{text-align:center;font-size:15px;color:var(--ink2);margin:0 0 30px;}#venda-pagina .esteira{overflow:hidden;margin:0 -24px;padding:2px 0;
           -webkit-mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent);
                   mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent);}#venda-pagina .esteira + .esteira{margin-top:11px;}#venda-pagina .fita{display:flex;gap:11px;width:max-content;animation:anda 64s linear infinite;}#venda-pagina .esteira.volta .fita{animation-duration:78s;animation-direction:reverse;}#venda-pagina .esteira:hover .fita{animation-play-state:paused;}
  @keyframes anda{from{transform:translateX(0)}to{transform:translateX(-50%)}}
  
  @media (prefers-reduced-motion:reduce){#venda-pagina .fita{animation:none;} }#venda-pagina .cp{position:relative;width:104px;flex:none;height:156px;border-radius:7px;
      border:1px solid var(--line);overflow:hidden;display:flex;align-items:flex-end;
      background:radial-gradient(125% 92% at 26% 14%,#6b2230 0,transparent 60%),#191014;}#venda-pagina .cp:nth-child(3n){background:radial-gradient(125% 92% at 30% 20%,#4a2a48 0,transparent 60%),#15111a;}#venda-pagina .cp:nth-child(4n+1){background:radial-gradient(125% 92% at 20% 30%,#2b3f52 0,transparent 62%),#101418;}#venda-pagina .cp:nth-child(5n){background:radial-gradient(125% 92% at 35% 15%,#5c3520 0,transparent 60%),#181210;}#venda-pagina .cp:nth-child(7n){background:radial-gradient(125% 92% at 28% 22%,#3b2b58 0,transparent 60%),#12101a;}#venda-pagina .cp:nth-child(8n){background:radial-gradient(125% 92% at 24% 18%,#2f4a35 0,transparent 60%),#101610;}#venda-pagina .cp b{display:block;width:100%;padding:22px 8px 8px;font-size:10.5px;font-weight:700;
        line-height:1.25;color:#fff;
        background:linear-gradient(180deg,transparent,rgba(0,0,0,.86));}#venda-pagina .capas-mais{text-align:center;margin-top:20px;font-size:14px;color:var(--ink2);}#venda-pagina .gar{max-width:640px;margin:0 auto;background:var(--s2);border:1px solid var(--line2);
       border-radius:14px;padding:26px 24px;text-align:center;}#venda-pagina .gar-selo{display:inline-flex;align-items:center;justify-content:center;width:52px;height:52px;
    border-radius:50%;border:2px solid var(--ok);color:var(--ok);font-family:var(--display);
    font-size:19px;margin-bottom:14px;}#venda-pagina .gar h3{font-family:var(--display);font-weight:400;font-size:24px;text-transform:uppercase;margin:0 0 8px;}#venda-pagina .gar p{font-size:15px;color:var(--ink2);margin:0;max-width:44ch;margin-inline:auto;}#venda-pagina .planos{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;max-width:820px;margin:0 auto;align-items:stretch;}#venda-pagina .pl{position:relative;background:var(--s1);border:1px solid var(--line);border-radius:14px;
      padding:28px 22px 22px;display:flex;flex-direction:column;}#venda-pagina .pl.pop{background:var(--s2);border-color:var(--red);}#venda-pagina .pl-selo{position:absolute;top:-11px;left:50%;transform:translateX(-50%);background:var(--red);
    color:#fff;font-size:10.5px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;
    padding:5px 14px;border-radius:6px;white-space:nowrap;}#venda-pagina .pl-nome{font-size:12.5px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--ink2);}#venda-pagina .pl-de{font-size:13px;color:var(--ink3);text-decoration:line-through;margin-top:10px;min-height:20px;}#venda-pagina .pl-preco{font-family:var(--display);font-weight:400;font-size:46px;line-height:1;margin:2px 0 2px;}#venda-pagina .pl-preco small{font-size:19px;color:var(--ink2);margin-right:3px;}#venda-pagina .pl-ciclo{font-size:13px;color:var(--ink3);}#venda-pagina .pl-eco{font-size:13px;font-weight:700;color:var(--ok);margin-top:8px;min-height:20px;}#venda-pagina .pl ul{list-style:none;padding:0;margin:18px 0 22px;display:flex;flex-direction:column;gap:10px;flex:1;}#venda-pagina .pl li{display:flex;gap:9px;font-size:14px;align-items:flex-start;color:var(--ink2);}#venda-pagina .ck{color:var(--red);flex:none;font-weight:800;}#venda-pagina .pl .b{width:100%;}#venda-pagina .pl-cpf{text-align:center;font-size:12.5px;color:var(--ink3);margin:26px 0 0;}#venda-pagina .passos{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;max-width:760px;margin:0 auto;}#venda-pagina .ps{text-align:center;}#venda-pagina .ps-n{font-family:var(--display);font-size:30px;color:var(--red);line-height:1;margin-bottom:8px;}#venda-pagina .ps-t{font-size:14.5px;font-weight:700;margin:0 0 3px;}#venda-pagina .ps-d{font-size:13px;color:var(--ink2);margin:0;}#venda-pagina .faq{max-width:640px;margin:0 auto;}#venda-pagina .faq details{border-bottom:1px solid var(--line);padding:17px 0;}#venda-pagina .faq summary{position:relative;cursor:pointer;font-weight:600;font-size:15.5px;line-height:1.4;list-style:none;padding-right:26px;}#venda-pagina .faq summary::-webkit-details-marker{display:none;}/* O sinal era `float:right`, e float se ancora na ULTIMA linha do bloco: com as perguntas curtas antigas dava na mesma, mas as de agora quebram em duas linhas no celular e o "+" descia para o pé da pergunta. Absoluto no canto, com folga reservada no padding-right, ele fica onde o dedo procura em qualquer largura. */#venda-pagina .faq summary::after{content:"+";position:absolute;top:0;right:0;color:var(--red);font-weight:800;font-size:18px;line-height:1.4;}#venda-pagina .faq a{color:var(--red);text-decoration:underline;text-underline-offset:2px;}#venda-pagina .faq details[open] summary::after{content:"–";}#venda-pagina .faq p{margin:11px 0 0;color:var(--ink2);font-size:14.5px;}#venda-pagina .fim{padding:52px 24px;text-align:center;border-top:1px solid var(--line);background:var(--s1);}#venda-pagina .fim h3{font-family:var(--display);font-weight:400;font-size:clamp(24px,3.6vw,34px);line-height:1.1;
          text-transform:uppercase;margin:0 0 8px;}#venda-pagina .fim p{color:var(--ink2);font-size:15px;margin:0 0 20px;}#venda-pagina .rodape{padding:28px 24px;text-align:center;border-top:1px solid var(--line);}#venda-pagina .rodape-links{display:flex;gap:20px;justify-content:center;margin:14px 0;font-size:14px;color:var(--ink2);flex-wrap:wrap;}#venda-pagina .rodape p{color:var(--ink3);font-size:12.5px;margin:0;}

  @media(max-width:760px){#venda-pagina .passos{grid-template-columns:1fr;gap:18px;}#venda-pagina .capas{grid-template-columns:repeat(4,1fr);}#venda-pagina .planos{grid-template-columns:1fr;max-width:400px;}#venda-pagina .hero{padding:46px 20px 40px;}#venda-pagina .sec{padding:44px 20px;}
  }#venda-pagina .nota h3{margin:0 0 7px;font-size:15.5px;}#venda-pagina .nota p{margin:0 0 9px;color:var(--ink2);font-size:14.5px;}#venda-pagina .nota p:last-child{margin-bottom:0;}

#venda-pagina{padding:0;margin:0;}

/* A capa da esteira nasceu como GRADIENTE, sem foto — era maquete. Ao pôr o
   pôster de verdade do TMDB dentro dela, a imagem virou um item de flex sem
   regra nenhuma: largura automática de imagem ainda não carregada é ZERO, e
   elemento de área zero nunca "entra na tela", então o loading="lazy" nunca
   disparava. Ela não carregava porque tinha tamanho zero, e tinha tamanho zero
   porque não carregava. Tirar a imagem do fluxo com position:absolute quebra o
   ciclo: ela ocupa o quadro inteiro antes de existir pixel algum.

   O gradiente continua atrás e vira o fundo enquanto a foto baixa. */
/* ─── Barra inferior (celular) ───────────────────────────────────────────
   Fica em 150: acima do conteúdo, abaixo da modal (200) e do player (300) —
   assistir e a tela de conta cobrem a barra, e não o contrário.

   Nasce escondida e só aparece no celular. Em tablet e computador o topo já
   está ao alcance do mouse, e numa TV antiga barra fixa embaixo atrapalha:
   o D-pad já percorre a tela de cima a baixo, e o rodapé é onde o foco se
   perde. */
.barra-inferior {
  display: none;
}

@media (max-width: 560px) {
  /* Flutuante (pedido do dono, 01/10/2026, referência Netflix mobile): a barra
     se descola das bordas em vez de colar na tela inteira — vidro escuro com
     blur, cantos arredondados por completo (--radius-full) e sombra funda,
     pra ler como um elemento sobre o conteúdo, não como rodapé do navegador.
     `backdrop-filter` fica de reforço: sem suporte (Chrome < 76), o fundo
     sólido abaixo já resolve sozinho — nenhum navegador quebra. */
  .barra-inferior {
    display: flex;
    position: fixed;
    left: 12px;
    right: 12px;
    bottom: calc(10px + var(--safe-bottom));
    z-index: 150;
    background: rgba(20, 20, 20, 0.88);
    -webkit-backdrop-filter: blur(20px) saturate(1.6);
    backdrop-filter: blur(20px) saturate(1.6);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: var(--radius-full);
    box-shadow: var(--shadow-lg);
    padding: 6px 6px;
  }

  .barra-inferior.hidden {
    display: none;
  }

  .barra-item {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    padding: 4px 2px;
    background: none;
    border: 0;
    border-radius: var(--radius-full);
    color: var(--text-tertiary);
    font-family: var(--font-body);
    font-size: 0.64rem;
    font-weight: 600;
    cursor: pointer;
    /* 44px é o alvo que a mão de 60 anos acerta sem mirar. */
    min-height: 44px;
    transition: color var(--duration-fast) ease;
  }

  /* Selo atrás do ícone, não do botão inteiro: um retângulo cheio na pílula
     toda ficaria um bloco só; o selo redondo só no ícone é o que a Netflix e
     o iOS fazem para marcar "você está aqui" sem gritar. */
  .barra-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 26px;
    border-radius: var(--radius-full);
    transition: background-color var(--duration-fast) ease, transform var(--duration-fast) var(--ease-out);
  }

  .barra-item.active {
    color: var(--text-primary);
  }

  .barra-item.active .barra-icon {
    background: var(--accent-primary);
    color: #fff;
    transform: translateY(-1px);
  }

  /* O conteúdo precisa terminar acima da barra, senão o último cartão fica
     debaixo dela e parece que a página acabou antes. Soma a altura da barra
     (~58px) + a folga até a borda (10px) + mais um respiro. */
  #main-content {
    padding-bottom: calc(84px + var(--safe-bottom));
  }

}

#venda-pagina .cp img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* O título precisa ficar SOBRE a foto. Os dois estão posicionados, então quem
   vem depois na marcação ganha — sem inventar z-index. */
#venda-pagina .cp b {
  position: relative;
}

/* A linha acima da headline era tratamento de ETIQUETA: 11,5px, espaçamento
   de .19em, na cor mais apagada do site. Servia para as quatro palavras que
   havia ali antes. A frase agora tem duas batidas e três dores, e naquele
   tratamento viraria quatro linhas de letra miúda e cinza — o texto mais
   apagado da tela justo onde a página ataca a dor.

   Cresce o corpo, fecha o espaçamento (maiúscula comprida com tracking largo
   custa a ler) e sobe um degrau de cor. Fica um degrau ABAIXO da headline em
   peso: o olho apresenta a dor, a headline entrega a saída — inverter isso
   faria as duas brigarem.

   A largura máxima existe para a frase quebrar em duas linhas parelhas no
   computador, em vez de esticar numa só, quase encostando nas bordas. */
/* Destino do "Assinar" do topo. O cabeçalho é `position: sticky`, então uma
   âncora crua para aqui rolaria até o topo da seção e o cabeçalho cobriria o
   "Escolha seu plano" — a cliente chegaria vendo os cartões pelo meio, sem
   saber onde parou. A folga é a altura do cabeçalho mais o recorte da tela
   (celular com entalhe, que engorda o topo) e uma sobra para respirar.

   `scroll-margin-top` só existe do Chrome 69 em diante e a TV antiga vai até
   o 63. Lá a propriedade é ignorada e a âncora para um pouco alta — o
   destino continua certo, só menos folgado. Nada quebra. */
#planos {
  scroll-margin-top: calc(var(--header-height) + var(--safe-top) + 14px);
}

#venda-pagina .olho {
  font-size: 13px;
  letter-spacing: .1em;
  color: var(--ink2);
  line-height: 1.45;
  max-width: 30em;
  margin: 0 auto 18px;
  text-wrap: balance;
}

/* Na prévia os botões eram <span> (maquete). Viraram <a> e <button> de
   verdade — o que muda a aparência de fábrica do navegador, então o visual
   volta aqui: sem sublinhado, sem cor de link, sem borda cinza de botão. */
#venda-pagina a.b,
#venda-pagina a.b:hover,
#venda-pagina a.b:visited {
  text-decoration: none;
  cursor: pointer;
}

#venda-pagina .nav-entrar,
#venda-pagina .hero-link {
  background: transparent;
  border: 0;
  font-family: var(--ui);
  cursor: pointer;
}

#venda-pagina .hero-link {
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* 44px de alvo de toque nos dois, que a prévia não precisava garantir por ser
   maquete e aqui são o caminho da venda e do login. */
#venda-pagina .nav-entrar,
#venda-pagina .hero-link {
  min-height: 44px;
  padding: 0 8px;
}

/* ═══════════════════════════════════════
   MODO VISITANTE: a home é a vitrine
   ═══════════════════════════════════════
   Quem ainda não assina vê a página de venda inteira e nada mais. O destaque,
   a grade de capas, as abas e a busca do topo são do APP — para quem entrou —
   e apareciam junto com a vitrine, deixando dois heróis, dois catálogos e
   duas buscas na mesma tela.

   Esconder pelo CSS e não pelo JavaScript é de propósito: renderChannels() e
   renderCategoryTabs() tiram a classe `hidden` desses elementos quando o
   catálogo carrega, e desfariam qualquer coisa que o JavaScript fizesse. */

#app.modo-visitante #home-banner,
#app.modo-visitante #category-tabs,
#app.modo-visitante #grid-title,
#app.modo-visitante #channel-grid,
#app.modo-visitante #search-bar {
  display: none;
}

/* ═══════════════════════════════════════
   VISITANTE NOVO: a vitrine já na primeira pintura (03/10/2026)
   ═══════════════════════════════════════
   O <head> do index.html põe `frio` no <html> quando NÃO existe nenhuma marca
   de sessão no aparelho nem veio link de acesso (a mesma decisão que o app.js
   toma depois, no ramo `entrarComoVisitante`) — e um <script> logo na abertura
   do #app põe `modo-visitante`, que reaproveita todas as regras acima. Aqui só
   fica o resto do que `entrarComoVisitante()` faz com classes `hidden`, pra a
   primeira pintura já ser a final: some a splash, aparece a vitrine, aparecem
   Assinar/Entrar e some o botão de conta.

   Os `!important` são porque `.hidden` é `!important` (e tem que ser). O app.js
   TIRA a marca `frio` assim que assume, no mesmo instante em que ele mesmo
   aplica esse estado — sem isso, quando o visitante virasse assinante, a
   vitrine continuaria sendo forçada a aparecer por cima do catálogo. */
html.frio #splash-screen {
  display: none !important;
}

html.frio #venda-pagina.hidden {
  display: block !important;
}

html.frio #btn-assinar.hidden,
html.frio #btn-entrar.hidden {
  display: flex !important; /* o mesmo display de .trial-buy-btn */
}

html.frio #btn-menu {
  display: none;
}

/* ═══════════════════════════════════════
   QUEM VOLTA: o conteúdo some enquanto a splash cobre a tela (03/10/2026)
   ═══════════════════════════════════════
   Quem já tem sessão (ou chega pelo link de acesso) vê a splash e o app monta
   a home ATRÁS dela, aos pedaços: o "Nenhuma lista carregada" some, o banner
   entra depois do fetch, o "Carregando catálogo" vira as fileiras. A splash é
   opaca, então a pessoa nunca viu nada disso mexer — mas o Chrome conta o
   deslocamento do que está atrás de um overlay do mesmo jeito (medido: o mesmo
   shift com e sem overlay), e o CLS do campo ia a 0,5-0,9 por carregamento.
   O laboratório não via: ele para de medir no `load`, antes de tudo isso.

   `visibility: hidden` mantém o layout (as imagens preguiçosas continuam
   carregando atrás da splash) e tira o que se mexe da conta. O <head> do
   index.html põe `cobrindo` (só pra quem NÃO é visitante novo — esse não tem
   splash) e o app.js tira quando a splash sai; há um relógio de segurança
   de 12s no <head> pra o conteúdo nunca ficar invisível pra sempre. */
html.cobrindo #main-content {
  visibility: hidden;
}

/* A previa puxava o "Mais escolhido" para o topo no celular (order:-1).
   Portado junto, deixava a leitura Trimestral -> Mensal -> Anual: o preco do
   meio aparecia primeiro e a escada de valor sumia. A ordem agora e a mesma
   nas quatro telas — 30, 90 e 365 dias, do mais barato ao mais longo. */
#venda-pagina .pl.pop { order: 0; }

/* ─── Aparelhos: as regras que o porte apagou por engano ───
   O filtro que tirava as classes do DOCUMENTO da prévia (.doc, .frame, .app…)
   levou junto `.apps` e `.apps-in`, que são da PÁGINA. Sem a grade, os três
   viravam blocos soltos, um embaixo do outro.

   Três colunas em TODA largura, inclusive no celular — a prévia empilhava
   abaixo de 760px, e empilhado o bloco perde a graça: o que ele diz é
   "funciona nos três", e três coisas lado a lado dizem isso de relance. */
#venda-pagina .apps {
  background: var(--bg);
  padding: 30px 24px;
  /* Antes a linha de cima vinha emprestada da borda de baixo do bloco de
     busca, que ficava logo acima. Com a troca de ordem, quem está acima é a
     seção das capas, que não tem borda e usa o mesmo fundo — sem esta linha
     as duas se fundem num bloco só. */
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

#venda-pagina .apps-in {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
  max-width: 820px;
  margin: 0 auto;
}

/* No celular a coluna tem ~105px: o texto encolhe para caber sem virar
   escada de uma palavra por linha. */
@media (max-width: 560px) {
  #venda-pagina .apps {
    padding: 26px 12px;
  }

  #venda-pagina .apps-in {
    gap: 10px;
  }

  #venda-pagina .ap-t {
    font-size: 12.5px;
  }

  #venda-pagina .ap-d {
    font-size: 11px;
  }
}

/* ─── convite para instalar o app ─────────────────────────────────────────
   Deliberadamente NÃO usa .trial-bar. Aquela faixa é o cronômetro do teste:
   12px, cinza secundário e nowrap. A instrução do iPhone é uma frase inteira,
   e caía ali dentro como um borrão cinza — foi a reclamação do dono. */
/* FLUTUANTE, não em fluxo (03/10/2026). Ela era `sticky` entre o header e o
   conteúdo: entrava 1,2s depois de a pessoa sair do player e empurrava a home
   inteira ~76px, à vista e fora da janela de 500ms que isenta um toque do CLS.
   Agora fica por cima, no fim da tela, acima da barra de baixo no celular, e
   chega por `transform` (que não conta como deslocamento). */
.install-bar {
  position: fixed;
  left: 12px;
  right: 12px;
  bottom: calc(92px + var(--safe-bottom)); /* acima da barra inferior flutuante (10px de borda + 74px de altura medida + 8px de folga) */
  z-index: 140;                            /* abaixo da barra inferior (150) e dos overlays */
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  padding-left: max(14px, var(--safe-left));
  padding-right: max(14px, var(--safe-right));
  background: var(--bg-secondary);
  border: 1px solid var(--border-subtle);
  border-radius: 14px;
  box-shadow: var(--shadow-lg);
  animation: installEntra 0.35s var(--ease-out) backwards;
}

@keyframes installEntra {
  from { opacity: 0; transform: translateY(16px); }
}

/* Tablet/computador não tem barra de baixo: cartão no canto. */
@media (min-width: 561px) {
  .install-bar {
    left: auto;
    right: 16px;
    bottom: 16px;
    max-width: 420px;
  }
}

.install-bar.hidden { display: none; }

/* O ícone do app é o argumento visual: a pessoa reconhece o que vai ficar na
   tela dela antes de ler qualquer coisa. */
.install-icone {
  width: 44px;
  height: 44px;
  border-radius: 10px;
  flex-shrink: 0;
  object-fit: cover;
}

.install-texto {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;   /* deixa o texto encolher em vez de empurrar o botão para fora */
  flex: 1;
}

.install-titulo {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.2;
}

/* Duas linhas no máximo, com reticências. A instrução do iPhone é longa, e
   sem este corte ela empurraria o botão para fora da tela num celular
   estreito — que era exatamente o defeito antigo. */
.install-sub {
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-secondary);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.install-cta {
  flex-shrink: 0;
  height: 38px;
  padding: 0 16px;
  font-size: 13px;
  font-weight: 700;
  border-radius: 8px;
}

.install-x {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 8px;
  background: none;
  border: none;
  color: var(--text-tertiary);
  cursor: pointer;
}
.install-x:hover { color: var(--text-secondary); }

/* ─── a folha de instruções ───────────────────────────────────────────── */
.install-ajuda {
  position: fixed;
  /* Escrito por extenso, e não `inset: 0`: as smart TVs antigas rodam
     Chrome 87, que não conhece a forma curta. Há teste travando isso. */
  top: 0; right: 0; bottom: 0; left: 0;
  z-index: 10001;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(0, 0, 0, 0.7);
  padding: 16px;
  padding-bottom: calc(16px + var(--safe-bottom));
}

.install-ajuda.hidden { display: none; }

.install-ajuda-cartao {
  width: 100%;
  max-width: 420px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-subtle);
  border-radius: 16px;
  padding: 22px 20px 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.install-ajuda-titulo {
  margin: 0;
  font-size: 17px;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.25;
}

.install-passos {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 14px;
  counter-reset: passo;
}

/* Numerados porque é uma sequência de verdade: fora de ordem, os passos não
   funcionam. */
.install-passos li {
  counter-increment: passo;
  display: grid;
  grid-template-columns: 26px 1fr;
  gap: 12px;
  align-items: start;
  font-size: 14px;
  line-height: 1.45;
  color: var(--text-secondary);
}

.install-passos li::before {
  content: counter(passo);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--bg-tertiary);
  color: var(--text-primary);
  font-size: 12px;
  font-weight: 700;
}

/* O ícone dentro do passo é o que faz a instrução funcionar: no iPhone a
   pessoa precisa RECONHECER o desenho de Compartilhar na barra dela, e
   descrever com palavras não resolve. */
.install-passos .glifo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  margin: 0 2px;
  vertical-align: -6px;
  border-radius: 6px;
  background: var(--bg-tertiary);
  color: var(--text-primary);
}

.install-passos strong { color: var(--text-primary); font-weight: 600; }

@media (min-width: 600px) {
  .install-ajuda { align-items: center; }
}

/* A nota do último passo — não é instrução, é a saída para quem não achou o
   que a instrução prometeu. Menor e recuada, para não competir com os passos. */
.install-passos .passo-nota {
  display: block;
  font-size: 13px;
  color: var(--text-tertiary);
  line-height: 1.45;
}
.install-passos li:last-child:has(.passo-nota)::before {
  content: '!';
  background: transparent;
  border: 1px solid var(--border-subtle);
  color: var(--text-tertiary);
}

/* ─── depoimento em vídeo ─────────────────────────────────────────────────
   Retrato (9:16), porque foi gravado no celular: forçar 16:9 poria duas tarjas
   pretas gordas dos lados. Largura curta pelo mesmo motivo — vídeo vertical
   esticado na tela do computador fica ridículo. */
.depo-video {
  max-width: 320px;
  margin: 26px auto 0;
}

/* A moldura é o que separa "arquivo de vídeo solto na página" de "peça". O
   brilho vermelho é o mesmo do resto do site, bem fraco: a atenção tem que ir
   para o rosto dela, não para a borda. */
.depo-moldura {
  position: relative;
  border-radius: 18px;
  overflow: hidden;
  border: 1px solid var(--border-subtle);
  box-shadow: 0 18px 50px -20px rgba(0, 0, 0, .9), 0 0 0 1px rgba(229, 9, 20, .1);
  background: var(--bg-secondary);
}

.depo-moldura video {
  width: 100%;
  display: block;
  /* Altura fixa no fallback: aspect-ratio é Chrome 88 e a smart TV roda 87.
     Sem isso o bloco nasce com altura zero e a página pula ao carregar. */
  height: 568px;
}
@supports (aspect-ratio: 9 / 16) {
  .depo-moldura video { aspect-ratio: 9 / 16; height: auto; }
}

/* A capa que cobre o pôster até o primeiro toque. O gradiente escurece só o
   pé e o topo — o rosto continua visível, que é o que convence a tocar. */
.depo-capa {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border: none;
  cursor: pointer;
  background: linear-gradient(180deg, rgba(0,0,0,.28) 0%, rgba(0,0,0,0) 34%, rgba(0,0,0,0) 58%, rgba(0,0,0,.72) 100%);
  -webkit-tap-highlight-color: transparent;
}
.depo-capa.hidden { display: none; }

.depo-play {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 66px;
  height: 66px;
  border-radius: 50%;
  background: var(--accent-primary);
  color: #fff;
  box-shadow: 0 10px 30px -8px rgba(229, 9, 20, .7);
  /* O triângulo é óptico, não geométrico: centralizado no cálculo ele parece
     puxado para a esquerda. */
  padding-left: 4px;
  transition: transform .18s ease;
}
.depo-capa:hover .depo-play { transform: scale(1.06); }

.depo-dica {
  margin-top: 12px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 1px 8px rgba(0, 0, 0, .8);
}

/* O nome existe porque prova social sem nome é só um vídeo: o nome é o que a
   pessoa confere. */
.depo-legenda {
  margin: 14px 0 0;
  text-align: center;
  line-height: 1.45;
}
.depo-legenda strong {
  display: block;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-primary);
}
.depo-legenda span {
  display: block;
  font-size: 12.5px;
  color: var(--text-tertiary);
}

@media (prefers-reduced-motion: reduce) {
  .depo-capa:hover .depo-play { transform: none; }
}

/* ─── o problema, antes do preço ──────────────────────────────────────────
   Mesmo desenho da dizisturcas.online: olho, pergunta e quatro cartões com
   ícone à esquerda. Vem depois dos aparelhos e antes da garantia — nomear a
   frustração é o que faz o preço parecer barato.

   ESCOPADO EM #venda-pagina e usando os tokens DELE. A página de venda tem
   paleta própria dentro de styles.css; as variáveis globais dariam cores
   parecidas mas não iguais, e o bloco destoaria dos vizinhos. */
#venda-pagina .sec-olho {
  margin: 0 0 10px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--red);
  text-align: center;
}

#venda-pagina .dor {
  max-width: 560px;
  margin: 28px auto 0;
  text-align: left;
}

/* Margem e não gap entre os cartões: `gap` em flex é Chrome 84, e esta página
   abre em smart TV com Chrome 87 — margem funciona em tudo. */
#venda-pagina .dor-item {
  display: flex;
  align-items: flex-start;
  margin-bottom: 12px;
  padding: 16px 20px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--s1);
}
#venda-pagina .dor-item:last-child { margin-bottom: 0; }

/* Vermelho mais escuro que o da marca, de propósito: o ícone marca a queixa,
   não chama para a ação. No tom do botão ele competiria com o CTA logo abaixo.
   `margin-right` no lugar do gap, pelo mesmo motivo do Chrome 84. */
#venda-pagina .dor-ic {
  flex-shrink: 0;
  display: block;
  margin-right: 14px;
  color: #c0392b;
  /* Alinha o ícone com a primeira LINHA do texto, não com o topo da caixa. */
  margin-top: 1px;
}

#venda-pagina .dor-item p {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--ink2);
}

/* A primeira frase é a dor; o resto é a consequência. O peso separa as duas
   sem precisar de duas linhas. */
#venda-pagina .dor-item b { color: #f5f5f5; font-weight: 600; }

/* ─── a solução, logo depois do problema ──────────────────────────────────
   Mesmo desenho da dizisturcas.online: seis cartões em grade com ícone
   dourado. O dourado contrasta de propósito com o vermelho do bloco de cima —
   problema em vermelho, solução em ouro. O olho percebe a virada antes de
   ler a primeira palavra. */
/* O olho da solucao usa o vermelho VIVO da marca; o do problema usa o vermelho
   apagado. Mesma familia, tons diferentes: a virada continua legivel sem
   trazer uma cor que nao e do Dizis TV. */
#venda-pagina .sec-olho--ouro { color: var(--red); }

/* `gap` aqui é de GRID, não de flex: em grid ele vale desde o Chrome 57 e a
   smart TV (87) lê sem problema. É o flex que precisa de margem. */
#venda-pagina .ben {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
  max-width: 900px;
  margin: 30px auto 0;
  text-align: left;
}

@media (min-width: 700px) {
  #venda-pagina .ben { grid-template-columns: repeat(3, 1fr); }
}

#venda-pagina .ben-card {
  padding: 22px 20px;
  border: 1px solid rgba(229, 9, 20, .18);
  border-radius: 16px;
  background: var(--s1);
}

#venda-pagina .ben-ic {
  display: block;
  margin-bottom: 12px;
  /* Vermelho vivo da marca, contra o #c0392b apagado do bloco do problema. */
  color: var(--red);
}

#venda-pagina .ben-t {
  margin: 0 0 6px;
  font-size: 15px;
  font-weight: 700;
  color: #f5f5f5;
  line-height: 1.3;
}

#venda-pagina .ben-d {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--ink2);
}

/* ─── os 3 passos, redesenhados ───────────────────────────────────────────
   Eram três colunas de uma linha cada. Viraram lista com número grande em
   círculo e texto ao lado, como na dizisturcas.online: cabe explicar o que a
   pessoa FAZ, não só o que acontece.

   Estas regras vêm depois das antigas no arquivo, então ganham por ordem de
   cascata sem precisar de !important — mesma especificidade, última vence. */
#venda-pagina .passos {
  display: block;
  max-width: 620px;
  margin: 30px auto 0;
  text-align: left;
}

/* Margem e não gap: `gap` em flex é Chrome 84 e esta página abre em smart TV
   com Chrome 87. */
#venda-pagina .ps {
  display: flex;
  align-items: flex-start;
  text-align: left;
  padding: 20px 0;
  border-bottom: 1px solid var(--line);
}
#venda-pagina .ps:last-child { border-bottom: none; }

/* O degrau do outro site: 52px, degradê vermelho, número branco. É o que dá
   ritmo à lista — sem ele, três parágrafos empilhados não parecem passos. */
#venda-pagina .ps-n {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  margin: 0 18px 0 0;
  border-radius: 50%;
  background: linear-gradient(135deg, #c0392b, #7b241c);
  color: #fff;
  font-family: inherit;
  font-size: 20px;
  font-weight: 700;
  line-height: 1;
}

#venda-pagina .ps-t {
  margin: 4px 0 5px;
  font-size: 15.5px;
  font-weight: 700;
  color: #f5f5f5;
  line-height: 1.3;
}

#venda-pagina .ps-d {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--ink2);
}

/* ─── a saída para quem não decidiu ───────────────────────────────────────
   Vem depois dos 3 passos porque é ali que a dúvida aparece: ela entendeu
   como funciona e mesmo assim não clicou. Antes, o único caminho da página
   era comprar — e quem está em dúvida não compra, sai. */
#venda-pagina .teste-cta {
  max-width: 520px;
  margin: 34px auto 0;
  padding: 26px 22px;
  border: 1px solid rgba(37, 211, 102, .22);
  border-radius: 16px;
  background: var(--s1);
  text-align: center;
}

#venda-pagina .teste-t {
  margin: 0 0 8px;
  font-size: 17px;
  font-weight: 700;
  color: #f5f5f5;
  line-height: 1.3;
}

#venda-pagina .teste-d {
  margin: 0 auto 18px;
  max-width: 380px;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--ink2);
}

/* Verde do WhatsApp, o mesmo que o app já usa no convite de teste da tela de
   login. Não compete com o vermelho do "Quero assistir agora": é a segunda
   opção e tem que parecer a segunda. */
#venda-pagina .teste-b {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 14px 26px;
  border-radius: 999px;
  background: #25d366;
  color: #fff;
  font-size: 15px;
  font-weight: 700;
  text-decoration: none;
  line-height: 1;
}
/* Margem e não gap: `gap` em flex é Chrome 84, e a smart TV roda 87. */
#venda-pagina .teste-b svg { margin-right: 9px; }
#venda-pagina .teste-b:hover { background: #2fe075; }

#venda-pagina .teste-n {
  margin: 12px 0 0;
  font-size: 12px;
  color: var(--ink3);
}

/* ─── o convite no fim da solução ─────────────────────────────────────────
   Ponto de maior convencimento da página: ela acabou de ler o que ganha, um
   item por vez. Sem botão aqui, quem se convenceu precisa rolar até os planos
   sozinho — e cada rolagem a mais é gente que desiste no caminho. */
#venda-pagina .ben-cta {
  margin-top: 30px;
  text-align: center;
}

#venda-pagina .ben-cta-n {
  margin: 14px 0 0;
  font-size: 12.5px;
  color: var(--ink3);
}

/* ─── o selo dourado do plano anual ───────────────────────────────────────
   Ao lado do vermelho do trimestral, e dizendo outra coisa: vermelho é o que
   mais gente escolhe, ouro é o que sai mais barato. Quem decide por
   popularidade e quem decide por conta têm cada um a sua âncora — e o anual
   estava sem nenhuma.

   Aqui o dourado tem função (medalha, melhor negócio), diferente do bloco da
   solução, onde ele era só uma cor de fora. */
#venda-pagina .pl.ouro {
  border-color: rgba(212, 172, 13, .45);
}

#venda-pagina .pl-selo--ouro {
  background: linear-gradient(135deg, #e8c34a, #b8901f);
  /* Texto escuro sobre o ouro: branco sobre amarelo não tem contraste, e este
     selo é justamente o que precisa ser lido de longe. */
  color: #2a1f05;
  font-weight: 800;
}

/* O botão do anual acompanha o selo: contorno dourado, não o vermelho cheio —
   o cheio pertence ao trimestral, que continua sendo o principal. */
#venda-pagina .b-ouro {
  background: transparent;
  border: 1px solid rgba(212, 172, 13, .55);
  color: #e8c34a;
}
#venda-pagina .b-ouro:hover {
  background: rgba(212, 172, 13, .12);
  border-color: #e8c34a;
}
