/* APP SHELL — app-wrap/app-scroll, tab bar inferior, .app-container (utilitário de largura de tela usado em várias abas), navbar do topo. */

/* APP
   .app-wrap volta a position:fixed;inset:0 próprio (2026-08-25, achado por
   arqueologia git, docs/TECH-DEBT.md) — essa exata troca (height:100% vs
   position:fixed) já foi feita e desfeita 3x em 11 minutos em 04/08/2026
   (commits f604198→f3ca2b9→5a340a9): height:100% (repassar a altura de
   .page em vez de position:fixed próprio) foi tentado nesse mesmo dia e
   REJEITADO pela usuária pelo motivo exato oposto — "sobrava um espaço em
   branco grande" no aparelho dela. A versão que ficou estável, sem mais
   nenhuma correção depois disso por 3 semanas, foi position:fixed;inset:0.
   Ontem eu revertido pra height:100% sem saber dessa história (achando
   que eliminava uma "camada fixa duplicada" desnecessária) — na prática
   voltei pra uma versão já tentada e descartada. Mantendo position:fixed
   próprio aqui: não depende de repasse de altura entre pai/filho, cada
   position:fixed;inset:0 é recalculado pelo motor de forma independente e
   direta contra o viewport real. */
/* Altura real da barra de baixo e distância dela até a borda da tela
   (2026-10-03). Antes a conta usava 72px, de quando a barra era menor: em
   celular sem safe-area ela passava 14px da borda. Com safe-area de 34px a
   distância dá os mesmos 20px de antes; sem safe-area, 12px. .app-scroll
   reserva barra + distância + 12px de folga. */
.app-wrap{--tab-bar-h:86px;--tab-bar-gap:max(12px,calc(var(--safe-bottom) - 14px));}
.app-wrap{display:flex;flex-direction:column;position:fixed;inset:0;height:var(--full-h);}
.app-scroll{flex:1;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior-y:contain;padding-bottom:calc(var(--tab-bar-h) + var(--tab-bar-gap) + 12px);}
/* Trava o scroll de .app-scroll enquanto a aba do Chat está ativa
   (JS: switchTab() em js/app.js alterna essa classe). Causa raiz real do
   bug de teclado no iPhone (auditoria 2026-08-24, docs/TECH-DEBT.md): o
   textarea do Chat (#ai-input) não tem NENHUM ancestral scrollável de
   verdade entre ele e .app-scroll — quem rola a conversa é .ai-messages,
   que é IRMÃO do input, não ancestral. Com .app-scroll deixado
   overflow-y:auto, o WebKit sobe o DOM a partir do input, acha .app-scroll
   como "primeiro ancestral scrollável" e força nele o scroll sintético que
   usa pra tirar o campo de baixo do teclado — só que, na aba do Chat,
   .app-scroll nunca tem conteúdo excedente de verdade (#tab-ai preenche
   sua altura exatamente), então esse scroll forçado num contêiner sem pra
   onde rolar é o que fica com offset residual ao fechar o teclado (faixa
   branca embaixo, botões do topo fora de alcance). Travando aqui,
   .ai-messages passa a ser o único scroll que o WebKit encontra, e o
   scroll-into-view automático dele é bem comportado (é o padrão de
   qualquer app de chat). Não afeta as outras 4 abas — só ganham a classe
   quando NÃO são o Chat (ver switchTab). */
.app-scroll.chat-scroll-lock{overflow-y:hidden;}
/* Histórico nesta mesma sessão de debug (2026-08-25), 3 posições testadas:
   1) position:fixed;bottom:Npx puro — vão inconsistente (bottom num
      elemento fixed é resolvido contra o viewport que o WebKit usa pra
      isso, que em standalone+área de gestos não bate de forma confiável
      com a tela física).
   2) position:static (item flex normal de .app-wrap) — corrigiu o vão,
      mas limitou .app-scroll a uma faixa menor que a tela toda (rolagem
      "cortando antes da hora", ao contrário da página de Interpretação,
      que não disputa espaço com barra nenhuma).
   3) position:absolute (ancorado em .app-wrap, não no viewport do
      sistema) — resolveu os dois problemas acima, MAS quebrou o chat:
      um elemento absolute aninhado dentro de um ancestral fixed não
      recebe o tratamento especial que o iOS dá a elementos fixed de
      verdade durante a abertura do teclado (o navegador arrasta a tela
      pra mostrar o campo acima do teclado; o fixed fica ancorado
      corretamente nesse arrasto, o absolute aninhado não).
   Ficou em position:fixed (item 3 quebrava o teclado), mas em vez de
   voltar pro bottom:Npx ambíguo do item 1, ancorada por "top" — bottom
   num fixed é resolvido contra o viewport instável do WebKit nesse
   cenário, mas top+100dvh é uma combinação confiável (100dvh existe
   especificamente pra medir viewport dinâmico corretamente; top sempre
   foi a referência mais estável pra position:fixed, é bottom que sofre
   com toolbars/áreas de gesto dinâmicas). Altura do pill (~65px) é
   aproximada pelo conteúdo real (ícone+label+paddings+borda) — se o
   conteúdo do .tab-item mudar de tamanho no futuro, reconferir esse
   número. */
/* CONTAINER PADRÃO DE TELA (2026-09-11, pedido da usuária) — classe
   utilitária reutilizável: toda tela nova de CONTEÚDO/LEITURA (mapa
   natal, interpretação, trânsitos, diário, sinastria/dossiê) deve usar
   .app-container em vez de inventar seu próprio max-width fixo. Antes
   cada wrap (.chart-wrap, .jrn-wrap, .trn-wrap, .synastry-dossier,
   .interp-hero-inner) tinha max-width:680px hardcoded — em telas
   desktop largas isso deixava o conteúdo com muito espaço morto nas
   laterais, parecendo um cartãozinho boiando no meio da tela.
   Fluido via clamp() de propósito — a usuária pediu explicitamente pra
   NÃO depender de breakpoints fixos: a largura cresce suavemente
   conforme a janela é redimensionada, sem "saltos" em pontos de corte.
     - largura: clamp(320px, 94vw, --container-max) — nunca encolhe
       abaixo de 320px (telas muito estreitas), acompanha ~94% da
       viewport em telas médias, trava no teto em telas largas.
     - --container-max default 900px = uma coluna de leitura confortável
       (mesma faixa de largura que .chart-wrap/.jrn-wrap/.trn-wrap/
       .synastry-dossier já usavam antes, só que fixa; ver
       docs/TECHNICAL-ARCHITECTURE.md pra esse valor documentado).
     - .app-container--wide sobe o teto pra 1200px, pra layouts de duas
       colunas como .interp-layout (menu de capítulos + conteúdo).
     - padding lateral também em clamp() (12px→40px conforme a viewport)
       em vez de um valor fixo — em telas pequenas fica bem próximo do
       padding antigo (20px fixo), em telas largas abre mais respiro em
       vez de grudar o texto na borda do container.
     - .app-container--flush zera o padding lateral pra containers cujos
       FILHOS já têm o próprio padding horizontal (.chart-wrap via
       .mandala-wrap/.mapa-card, .synastry-dossier via
       .synastry-dossier-header-wrap) — sem isso o padding duplicaria.
   Chat (.ai-*) fica de fora de propósito: decisão de produto já tomada
   de NÃO alargar o chat no desktop (ver comentário acima do
   @media(min-width:900px) dos .ai-*, mais abaixo neste arquivo) —
   .app-container é para telas de leitura, não para a UI de conversa. */
.app-container{
  width:100%;
  max-width:clamp(320px,94vw,var(--container-max,900px));
  margin-left:auto;
  margin-right:auto;
  padding-left:clamp(12px,4vw,40px);
  padding-right:clamp(12px,4vw,40px);
  box-sizing:border-box;
}
.app-container--wide{--container-max:1200px;}
.app-container--flush{padding-left:0;padding-right:0;}

/* grid de 5 colunas iguais (2026-09-19, correção pedida pela usuária) — Órbita
   precisa ficar geometricamente no centro (3º de 5, 2 de cada lado), o que só
   é garantido com colunas de largura fixa; com display:flex/flex:1, a coluna
   central podia deslocar de largura de acordo com o texto dos labels vizinhos. */
.tab-bar{position:fixed;left:16px;right:16px;top:calc(var(--full-h) - var(--tab-bar-h) - var(--tab-bar-gap));z-index:20;background:rgba(var(--surface-rgb),0.82);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border:1px solid var(--border);border-radius:999px;box-shadow:0 8px 28px rgba(var(--black-rgb),0.18);display:grid;grid-template-columns:repeat(5,1fr);padding:6px;transition:opacity 0.2s,background-color 0.15s ease-out;}
/* Vidro fica mais transparente durante o toque num item (2026-09-20, pedido
   da usuária) — feedback de que a navbar "ouviu" o toque, some assim que o
   dedo solta. :has() já é usado no repo (mapa-sinastria-interpretacao.css),
   suportado nos browsers-alvo do PWA. */
.tab-bar:has(.tab-item:active){background:rgba(var(--surface-rgb),0.45);}
/* Some (fade, sem sair do layout) enquanto o painel "Minha interpretação"
   ou o overlay do mapa estão abertos no desktop (2026-09-19) — sem isso a
   pílula centralizada (ver @media(min-width:900px) abaixo) fica parcialmente
   coberta pela borda do painel lateral, cortada visualmente. Classe alternada
   em js/interpretation.js (open/closeInterpretationPanel) e js/overlay.js
   (open/closeChartOverlay). */
body.panel-open .tab-bar{opacity:0;pointer-events:none;}
.tab-item{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;padding:8px 4px;border-radius:999px;cursor:pointer;background:none;border:none;color:var(--color-tab-inactive);min-height:0;transition:color 0.2s,background 0.2s;}
.tab-item.active{color:var(--accent);background:var(--accent-dim);}
.tab-icon{font-size:19px;line-height:1;}
.tab-label{font-size:10px;letter-spacing:0.02em;}

/* Botão central "Órbita" elevado (2026-09-19, pedido usuária: estilo FAB,
   igual apps de navegação com ação central em destaque) — deixou de ser um
   ícone maior dentro da mesma linha da pílula (versão 2026-08-27) e passa a
   sobressair fisicamente acima do topo dela. Gradiente: o mesmo de sempre
   (mesmo usado em .ai-send/outros CTAs, coral→rosa→violeta→roxo) — uma
   tentativa de trocar pra um gradiente próprio de 2 cores (cosmic-purple→
   rosa) foi revertida no mesmo dia a pedido da usuária, cores originais
   restauradas pelo histórico do git (git show bc45819^:css/app-shell.css). */
/* top/margin-bottom reduzidos de -18 pra -16, e padding-bottom extra de 10px
   (2026-09-19, fix) — a primeira versão deixava pouca folga vertical pro
   label "Órbita", cortado embaixo em telas reais (bug reportado pela
   usuária, não reproduzido no teste sintético anterior desta sessão). */
.tab-item-orbita{position:relative;padding-bottom:10px;}
.tab-item-orbita .tab-icon{
  width:56px;height:56px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:linear-gradient(135deg,var(--gradient-start) 0%,var(--gradient-mid1) 33%,var(--gradient-mid2) 66%,var(--gradient-end) 100%);
  color:var(--color-white);
  font-size:23px;
  position:relative;
  top:-16px;
  margin-bottom:-16px;
  box-shadow:0 6px 16px rgba(var(--black-rgb),0.28);
}
.tab-item-orbita .tab-label{font-weight:700;}
/* .active também some (fundo tingido genérico não combina com o círculo de
   gradiente já colorido) — o próprio círculo já comunica destaque/seleção. */
.tab-item-orbita.active{background:none;}

/* Pílula centralizada com largura máxima no desktop (2026-09-19) — em mobile
   ela usa top:calc(100dvh...) em vez de bottom por causa dos bugs de teclado
   documentados acima; em desktop não existe teclado virtual cobrindo
   elementos fixed, então bottom:20px é seguro e mais simples. Breakpoint
   900px = mesma convenção já usada no resto do app (js/interpretation.js
   innerWidth<900, .ai-* mais abaixo neste arquivo). */
@media(min-width:900px){
  .tab-bar{left:50%;right:auto;transform:translateX(-50%);width:100%;max-width:560px;bottom:20px;top:auto;}
  .tab-item:hover{background:var(--accent-dim);}
  .tab-item-orbita:hover{background:none;}
}

.tab-screen{display:none;}
.tab-screen.active{display:block;}
#tab-ai.active{display:flex;flex-direction:column;height:100%;}

