﻿/* =============================================================================
   RETROHUB — aplicativo do jogador na linguagem visual do Terminal.
   Tema único, escuro e retrô sóbrio: cantos retos, cores sólidas e tipografia
   social. Os acentos vêm exclusivamente do cânone da suíte.
   ========================================================================== */

:root {
    --hub-bg: var(--suite-tinta);
    --hub-title: var(--suite-campo);
    --hub-yellow: var(--suite-foco);
    --hub-yellow-dark: var(--suite-foco-escuro);
    --hub-yellow-hover: #ffd35c;
    --hub-red: var(--suite-perigo);
    /* O AZUL DO APP É O AZUL DO MENU.
       Ele apontava para `--suite-info`, que é um ciano claro: ao lado da fita de
       navegação — onde o bloco de avisos é azul-royal — pareciam duas cores que
       ninguém escolheu junto. A fita é a coisa mais vista do aplicativo, e é ela
       quem manda. O cânone da suíte não muda; o que muda é para onde o token do
       Hub aponta. No tema claro o azul já é outro (a fita rosa da capa de VHS),
       e ele continua sendo. */
    --hub-blue: var(--hub-nav-notifications);
    --hub-green: var(--suite-pronto);
    --hub-purple: var(--suite-especial);
    --hub-outside: #0a0b09;
    --hub-deep: #0c0e0b;
    --hub-card: #171a14;
    --hub-hover: #1c1f18;
    --hub-row-hover: #131511;
    /* A minha mensagem e o cartao de compartilhamento dentro dela. Sao dois
       degraus PROPRIOS porque a conversa precisa de tres tons empilhados —
       balao do outro, meu balao, cartao embutido — e os tons de tabela nao
       davam essa escada sem repetir alguem.

       OS DOIS BALOES SAO MAIS CLAROS QUE O CARTAO COMUM. Numa tela cheia de
       conversa o que se le e o balao, e nao a moldura: com o tom de cartao ele
       se confundia com o piso e a conversa virava um bloco so. A escada entre
       eles nao mudou — meu balao continua um degrau ABAIXO do balao do outro,
       porque quem escreveu ja sabe o que escreveu. */
    --hub-bubble-theirs: #23271f;
    --hub-bubble-mine: #1a1e15;
    --hub-bubble-embed: #0e100b;
    /* O veu de qualquer sobreposicao. Um so valor para todas elas: e o que faz
       a folha de denuncia, a de compartilhar e a da barra de XP parecerem a
       mesma peca. */
    --hub-veil: rgb(10 11 9 / 82%);

    /* ALTURA DA BARRA COLORIDA, e o espaco que as paginas reservam embaixo
       por causa dela. No celular ela flutua sobre o conteudo, entao cada tela
       precisa terminar acima dela — e essa conta estava escrita a mao em dois
       lugares, com valores diferentes (3,25rem e 4rem) e nenhuma relacao
       declarada com a altura real. Aqui a reserva sai da propria altura, mais
       uma folga: o fim da pagina fica visivel, e o que a barra cobre e so
       espaco vazio. */
    --hub-nav-h: 42px;
    --hub-nav-reserve: calc(var(--hub-nav-h) + 2.25rem + env(safe-area-inset-bottom));
    --hub-field: #0c0e0b;
    --hub-line: #2c2f27;
    --hub-line-strong: #3a3d33;
    --hub-line-soft: #22251e;
    --hub-line-faint: #1a1d16;
    --hub-body: #e9e4d3;
    --hub-dim: #8e9080;
    --hub-mute: #5d5f52;

    /* TINTA SOBRE ACENTO. Texto em cima de amarelo, roxo, vermelho — botao
       primario, inicial de avatar, balao da propria mensagem. No tema escuro e
       o mesmo tom do fundo, e por isso ele vivia escrito como var(--hub-bg);
       num tema claro os dois divergem, e sem este nome cada um dos 106 lugares
       viraria creme sobre creme. */
    --hub-on-accent: var(--hub-bg);
    --hub-ok-text: #a9d8ab;
    --hub-ok-bg: #131711;
    --hub-err-text: #e8a49c;
    --hub-err-bg: #191211;
    --hub-warn-text: #e8d49a;
    --hub-warn-bg: #131711;
    --hub-font: "Segoe UI", system-ui, sans-serif;
    --hub-mono: "IBM Plex Mono", "Cascadia Mono", Consolas, monospace;
    --hub-nav-width: 206px;

    /* P3 · TRILHOS DE LEITURA. Tres larguras, e nao uma por tela: leitura
       corrida (feed, publicacao, conversa), pagina de trabalho (carteira,
       busca, listas) e grade larga (comunidades, mapa, gestao). Antes eram
       oito numeros diferentes espalhados pelos .razor.css. */
    /* A COLUNA DA PAGINA. Uma so, aplicada em `.hub-content__inner`: cada tela
       declarava a sua e trocar de aba movia a margem esquerda do texto.
       `--col-read` e para texto corrido DENTRO de um cartao; `--col-full` e
       para as telas que pedem a largura toda pela classe do `hub-shell`. */
    --col-read: 760px;
    --col-page: 1080px;
    --col-full: 1320px;

    /* ACENTOS DA BARRA COLORIDA. São a sequência da fita — vermelho, amarelo,
       laranja, verde, azul royal, roxo — e não papéis semânticos. Três deles não
       existem no cânone da suíte de propósito: reaproveitar --hub-green ali
       diria "saldo positivo" e --hub-blue diria "informação", que é justamente
       o que a barra NÃO está comunicando. Vivem aqui, ao lado dos demais
       tokens, para nenhum arquivo precisar escrever cor crua. */
    --hub-nav-wallet: #f07c00;
    --hub-nav-messages: #5eb95f;
    --hub-nav-notifications: #3d63e8;

    /* OS SEIS BLOCOS TÊM SEIS TOKENS, e não três. Menu, feed e perfil vestiam
       `--hub-red`, `--hub-yellow` e `--hub-purple` — tokens de PAPEL, que o tema
       claro redefine —, então a fita trocava de cor ao acender a luz: o rosa do
       perfil virava roxo. A sequência da fita não muda entre os temas, e a única
       forma de isso ser verdade é ela não pegar cor emprestada de quem muda. */
    --hub-nav-menu: #f04b40;
    --hub-nav-feed: #f7bd2e;
    --hub-nav-profile: #c45bb2;

    /* =====================================================================
       ESCALA TIPOGRAFICA — A UNICA FONTE DE TAMANHO DO HUB.
       Nenhum arquivo declara rem solto: todo font-size aponta para um degrau
       daqui. Sao dez degraus, do menor selo ao titulo-heroi, com razao de
       ~1.10 a 1.13 entre vizinhos. Se um texto novo "precisa" de um tamanho
       que nao esta aqui, o degrau errado e o do texto, nao o da escala.
       ================================================================== */
    --fs-nano: .54rem;      /*  8.6px — selo, contador, carimbo             */
    --fs-micro: .60rem;     /*  9.6px — eyebrow, microlabel caixa alta      */
    --fs-meta: .68rem;      /* 10.9px — metadado, timestamp, dt de lista    */
    --fs-sm: .76rem;        /* 12.2px — texto de apoio, label, botao padrao */
    --fs-body: .84rem;      /* 13.4px — corpo padrao da interface           */
    --fs-lead: .92rem;      /* 14.7px — corpo de publicacao, campo, lead    */
    --fs-h3: 1.05rem;       /* 16.8px — titulo de card, painel e barra      */
    --fs-h2: 1.20rem;       /* 19.2px — titulo de secao                     */
    --fs-h1: 1.60rem;       /* 25.6px — titulo de pagina                    */
    --fs-h1-compact: 1.25rem;              /* titulo de pagina no mobile    */
    --fs-h1-fluid: clamp(1.25rem, 2.4vw, 1.60rem);  /* h1 que acompanha a viewport */
    --fs-display: clamp(1.9rem, 4vw, 2.6rem);       /* heroi da entrada publica    */

    /* ENTRELINHA — quatro alturas, uma por tipo de leitura. */
    --lh-tight: 1;        /* glifo, numero, rotulo de uma linha so    */
    --lh-heading: 1.2;    /* titulo                                   */
    --lh-snug: 1.4;       /* interface compacta, lista                */
    --lh-body: 1.55;      /* texto corrido, publicacao, descricao     */

    /* ESPACAMENTO ENTRE LETRAS. Titulo grande fecha; caixa alta abre — e
       abre mais quanto menor for o texto, senao vira um borrao. */
    --ls-tighter: -.03em; /* display / heroi                          */
    --ls-tight: -.01em;   /* titulo de pagina e secao                 */
    --ls-flat: 0;         /* texto normal                             */
    --ls-label: .08em;    /* rotulo levemente afastado                */
    --ls-caps: .12em;     /* caixa alta em texto pequeno              */
    --ls-caps-wide: .16em;/* caixa alta miuda: eyebrow, microlabel    */

    /* PESO. O mono so tem 400/500/600 carregados (ver App.razor): pedir 700
       ali faz o navegador falsificar o negrito e borrar a fonte. */

    /* GLIFOS E INICIAIS — desenham simbolo, nao texto. Ficam fora da escala
       de leitura de proposito: quem mexe no corpo do texto nao mexe no ícone. */
    --fs-icon-sm: 1rem;
    --fs-icon-md: 1.15rem;
    --fs-icon-lg: 1.4rem;
    --fs-icon-xl: 2rem;
    --fs-avatar-nano: .60rem;
    --fs-avatar-meta: .68rem;
    --fs-avatar-compact: .76rem;
    --fs-avatar-row: .84rem;
    --fs-avatar-sm: 1.1rem;
    --fs-avatar-md: 1.5rem;
    --fs-avatar-lg: 1.8rem;
    --fs-avatar-xl: 2.2rem;
    --fs-balance: 2.5rem;
    --fs-balance-compact: 2.25rem;
    --fs-credit-stepper: 2rem;

    /* BOTOES — tres tamanhos. O texto vem da escala acima, nunca de um rem
       proprio, para o botao acompanhar a tipografia sozinho. */
    /* As medidas sao as da pagina de estabelecimentos, que e a referencia
       aprovada. O degrau grande e o do botao Salvar de la: 42px de altura com
       texto de 12,2px. Botao nao tem texto de corpo — se o texto do botao
       cresce, ele vira um bloco amarelo e domina a tela. */
    --btn-h-sm: 34px;
    --btn-h-md: 38px;
    --btn-h-lg: 42px;
    --btn-pad-sm: .3rem .6rem;
    --btn-pad-md: .5rem .9rem;
    --btn-pad-lg: .65rem 1rem;
    --btn-fs-sm: var(--fs-meta);
    --btn-fs-md: var(--fs-sm);
    --btn-fs-lg: var(--fs-sm);
    /* Altura de campo de formulario. O botao grande empata com ela de
       proposito: botao e campo lado a lado ficam alinhados. */
    --field-h: 42px;
    --btn-weight: 600;
    /* O BOTÃO DE GLIFO TEM A ALTURA DO BOTÃO DE TEXTO do mesmo degrau (dono,
       17/08/2026). Eram 32/36/44 contra 34/38/42, e por isso o "···" ao lado
       de "Abrir comunidade" ou "Abrir perfil" saía dois pixels menor — o
       bastante para a dupla parecer desalinhada em toda linha de catálogo.
       Quadrado continua quadrado; o que mudou foi o lado. */
    --btn-icon-sm: 34px;
    --btn-icon-md: 38px;
    --btn-icon-lg: 42px;
}

html { background: var(--hub-bg); }

body {
    background: var(--hub-bg);
    color: var(--hub-body);
    font-family: var(--hub-font);
    /* O PISO DO CORPO. Sem esta linha, tudo que esquece de declarar tamanho cai
       nos 16px do navegador — maior que qualquer degrau da regua menos titulo.
       Era dai que vinha o texto gigante nas telas novas. */
    font-size: var(--fs-body);
    line-height: var(--lh-body);
    margin: 0;
}

body * { box-sizing: border-box; }
body ::selection { background: var(--hub-purple); color: var(--hub-on-accent); }
a { color: var(--hub-yellow); }
a:hover { color: var(--hub-title); }

/* Abas de conteúdo usadas por perfis e comunidades. Manter este contrato
   global evita que o espaçamento varie entre páginas por causa do CSS
   isolado de cada componente. */
.hub-content-tabs {
    border-bottom: 1px solid var(--hub-line);
    display: flex;
    gap: 1.6rem;
    margin-bottom: -.1rem;
}

.hub-content-tab {
    background: transparent;
    border: 0;
    border-bottom: 2px solid transparent;
    color: var(--hub-dim);
    cursor: pointer;
    flex: 0 0 auto;
    font-size: var(--fs-lead);
    margin-bottom: -1px;
    padding: 0 0 .75rem;
    text-decoration: none;
}

.hub-content-tab:hover { color: var(--hub-body); }
.hub-content-tab.is-active { border-bottom-color: var(--hub-yellow); color: var(--hub-title); }

@media (max-width: 760px) {
    .hub-content-tabs {
        gap: 1.25rem;
        overflow-x: auto;
        padding: 0 16px;
        scrollbar-width: none;
    }

    .hub-content-tabs::-webkit-scrollbar { display: none; }
    .hub-content-tab { font-size: var(--fs-body); padding-top: .75rem; }
}

@media (max-width: 390px) {
    .hub-content-tabs { gap: 1rem; }
}
button, input, select, textarea { font: inherit; }
h1, h2, h3, h4, h5, h6 { line-height: var(--lh-heading); }
/* Piso da hierarquia: sem isto um heading sem regra propria cai no 2em/1.5em
   do navegador e estoura o desenho. Qualquer regra de pagina vence esta. */
/* A hierarquia da pagina de estabelecimentos, que e o padrao aprovado:
   titulo de pagina 25,6 -> titulo de secao 16,8 -> corpo 13,4.
   Atencao: --fs-h2 (19,2) NAO e o tamanho do elemento h2 — e o degrau de
   numero em destaque. O h2 de secao usa --fs-h3. */
/* O peso tambem tem piso: sem ele, h1 de tela sem regra propria caia no
   negrito 700 do navegador — era ESSA a diferenca ("titulo grosso" no forum,
   nos participantes e nas mensagens) que denunciava tela fora do coro. */
h1 { font-size: var(--fs-h1); font-weight: 600; }
h2 { font-size: var(--fs-h3); }
h3 { font-size: var(--fs-lead); }
h4, h5, h6 { font-size: var(--fs-body); }
h1[tabindex="-1"]:focus { outline: none; }
p { margin-top: 0; }
img, svg { max-width: 100%; vertical-align: middle; }
hr { border: 0; border-top: 1px solid var(--hub-line); margin: 1rem 0; }

input:focus-visible,
select:focus-visible,
textarea:focus-visible,
button:focus-visible,
a:focus-visible {
    outline: 1px solid var(--hub-blue);
    outline-offset: 2px;
}

* { scrollbar-color: var(--hub-line-strong) transparent; scrollbar-width: thin; }

.visually-hidden {
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    height: 1px;
    overflow: hidden;
    position: absolute;
    white-space: nowrap;
    width: 1px;
}

.hub-mono,
.microlabel,
.eyebrow,
.section-kicker,
.post-handle,
.post-count,
.score,
.balance,
code {
    font-family: var(--hub-mono);
}

/* Shell ------------------------------------------------------------------ */

/* Tres linhas, largura inteira: topo, barra de navegacao e conteudo. A coluna
   da sidebar saiu — os destinos dela vivem no painel do bloco vermelho. */
.hub-shell {
    background: var(--hub-bg);
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: 60px 42px minmax(0, 1fr);
    height: 100dvh;
    overflow: hidden;
}

.hub-content {
    background: var(--hub-bg);
    grid-column: 1;
    grid-row: 3;
    margin: 0;
    max-width: none;
    min-width: 0;
    overflow: auto;
    padding: 1.75rem clamp(1.5rem, 3vw, 2rem) 3rem;
    width: 100%;
}
/* A LARGURA DA PAGINA E UMA SO, E ELA MORA AQUI.
   Cada tela declarava a sua: o feed em 760, o perfil herdava 1320, Ajustes
   travava em 1080, a caixa de mensagens em 1320. Trocar de aba movia a margem
   esquerda do texto — e nada disso era escolha, era o que cada tela tinha
   quando foi escrita. A moldura passa a dar a coluna, e quem precisa de mais
   largura pede pela classe do `hub-shell` (o mapa e a conversa ja fazem isso). */
.hub-content__inner { align-content: start; display: grid; gap: 1rem; margin-inline: auto; max-width: var(--col-page); }
/* =========================================================================
   A MOLDURA DE FORA — quem lê os documentos sem estar logado.

   Termos, privacidade, política da comunidade e as duas telas de erro caem
   aqui. Antes era uma folha em branco preta: nem marca, nem chave de tema,
   nem porta de volta. A moldura repete o vocabulário de dentro (fita de seis,
   marca da topbar, trilho de --col-page) sem nada que dependa de conta.
   ========================================================================= */
.hub-public-layout {
    background: var(--hub-bg);
    display: flex;
    flex-direction: column;
    min-height: 100dvh;
}

/* A MESMA FITA DA BARRA E DA ENTRADA, e pelos mesmos seis tokens: eles não
   mudam com o tema, e a sequência é a assinatura do produto. */
.public-color-strip {
    display: grid;
    flex: 0 0 6px;
    /* `1fr` puro, e não `minmax(0, 1fr)`: os seis filhos são vãos vazios, então
       não há conteúdo mínimo para estourar a coluna — e `HubNavBarTests` conta
       as ocorrências da forma longa neste arquivo para garantir que as DUAS
       declarações da barra de navegação (moldura e rodapé do celular) sigam
       tendo o mesmo número de colunas. Uma terceira ocorrência que não é a
       barra cegaria essa conta. */
    grid-template-columns: repeat(6, 1fr);
    height: 6px;
}
.public-color-strip span:nth-child(1) { background: var(--hub-nav-menu); }
.public-color-strip span:nth-child(2) { background: var(--hub-nav-feed); }
.public-color-strip span:nth-child(3) { background: var(--hub-nav-wallet); }
.public-color-strip span:nth-child(4) { background: var(--hub-nav-messages); }
.public-color-strip span:nth-child(5) { background: var(--hub-nav-notifications); }
.public-color-strip span:nth-child(6) { background: var(--hub-nav-profile); }

.public-topbar {
    align-items: center;
    background: var(--hub-deep);
    border-bottom: 1px solid var(--hub-line);
    display: flex;
    gap: 1.5rem;
    justify-content: space-between;
    padding: 0 24px;
    height: 64px;
}
.public-topbar__actions { align-items: center; display: flex; gap: .75rem; }

/* O trilho é o MESMO de dentro (--col-page): ir de um documento ao aplicativo
   não pode mover a margem esquerda do texto. */
.public-main { flex: 1; min-height: 0; padding: 2rem 24px 3rem; }
.public-main__inner { margin: 0 auto; max-width: var(--col-page); width: 100%; }

.public-footer { background: var(--hub-deep); border-top: 1px solid var(--hub-line); padding: 1.5rem 24px; }
.public-footer__inner {
    align-items: center;
    column-gap: 1.5rem;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    margin: 0 auto;
    max-width: var(--col-page);
    row-gap: 1rem;
    width: 100%;
}
.public-footer__brand {
    align-items: center;
    color: var(--hub-dim);
    display: inline-flex;
    font: 500 var(--fs-micro)/var(--lh-tight) var(--hub-mono);
    gap: 10px;
    letter-spacing: var(--ls-caps);
    text-decoration: none;
}
.public-footer__brand img { display: block; height: 22px; width: 22px; }
.public-footer__links { column-gap: 1.25rem; display: flex; flex-wrap: wrap; row-gap: .5rem; }
.public-footer__links a { color: var(--hub-mute); font-size: var(--fs-sm); text-decoration: none; }
.public-footer__links a:hover { color: var(--hub-yellow); }
.public-footer__enter { align-items: center; display: flex; gap: .75rem; }

/* A CHAVE DE TEMA TEM UMA CASA POR TAMANHO DE TELA, como no aplicativo: em
   cima no computador, embaixo no celular — onde a topbar não existe. */
.public-footer__theme { display: none; }


/* /map e /local/{slug} são a única tela que não é documento: ela É o mapa. No
   desktop a moldura entrega a linha 3 inteira — sem respiro lateral e sem o
   trilho de leitura de 1320px — para que a página do mapa não precise desfazer
   o padding com margem negativa. Cancelar na origem é o que mantém a conta
   exata: compensar por fora com 100vw erra por metade da barra de rolagem
   assim que existir barra, e devolve rolagem lateral.

   O piso de 901px não é enfeite: estas regras têm dois seletores e venceriam
   por especificidade as do bloco de ≤900px, que têm um só, mesmo estando antes
   no arquivo — @media não soma especificidade. */
@media (min-width: 901px) {
    .hub-shell--map .hub-content {
        overflow: hidden;
        padding: 0;
    }

    /* Coluna de altura definida: o convite de instalar o app, que é irmão do
       @Body, empurra; o mapa fica com o resto. Flex e não grid porque em grid o
       convite disputaria a mesma faixa do mapa; em flex ele só empurra, e
       quando não existe não deixa buraco. `height: 100%` fecha porque
       .hub-content é item de uma linha minmax(0, 1fr) num grid de 100dvh. */
    .hub-shell--map .hub-content__inner {
        display: flex;
        flex-direction: column;
        gap: 0;
        height: 100%;
        margin-inline: 0;
        max-width: none;
    }

    /* A caixa de mensagens fecha a MESMA cadeia de altura do mapa: a moldura
       prende a rolagem, o inner repassa a altura e quem rola é a lista ou a
       conversa — nunca a página, que levaria o campo de escrever embora. A
       diferença é que aqui a coluna de leitura (--col-page) continua valendo:
       só a altura é da moldura. */
    .hub-shell--messages .hub-content { overflow: hidden; }

    .hub-shell--messages .hub-content__inner {
        display: flex;
        flex-direction: column;
        height: 100%;
        min-height: 0;
    }

    }

/* A sidebar deixou de ser coluna da moldura: ela existe só dentro do painel do
   bloco vermelho, e por isso não tem mais fundo, borda nem altura próprios. */
.app-sidebar {
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.app-nav-label {
    color: var(--hub-mute);
    display: block;
    font: var(--fs-micro) var(--hub-mono);
    letter-spacing: var(--ls-caps-wide);
    padding: 6px 20px 12px;
}

.app-nav {
    align-content: start;
    display: grid;
    flex: 1 1 auto;
    gap: 2px;
    min-height: 0;
    overflow-y: auto;
}

.app-nav-link {
    align-items: center;
    background: transparent;
    border: 0;
    border-left: 3px solid transparent;
    color: var(--hub-dim);
    display: flex;
    gap: 12px;
    min-height: 44px;
    padding: .7rem 20px;
    text-decoration: none;
}

/* A busca dentro do menu, so no celular — ver AppSidebar.razor. */
.app-nav-search { display: none; }

/* A linha do tema no menu, SO NO CELULAR — mesma regra da busca logo acima, e
   pelo mesmo motivo: no computador a chave ja mora na topbar, e mostra-la
   tambem aqui era a mesma ferramenta duas vezes na mesma tela. No celular a
   topbar nao existe (`.hub-shell--page-mobile-header .app-topbar` some), entao
   o menu vermelho e a unica casa dela.

   Mesma altura dos destinos, mas sem cara de destino: ela nao leva a lugar
   nenhum. */
.app-nav-theme { display: none; }
.app-nav-theme { align-items: center; color: var(--hub-dim); font-size: var(--fs-sm); gap: .6rem; justify-content: space-between; min-height: 44px; padding: 0 .75rem; }
.app-nav-theme > span { letter-spacing: var(--ls-label); text-transform: uppercase; font-size: var(--fs-micro); font-family: var(--hub-mono); }

.app-nav-link:hover { background: var(--hub-row-hover); box-shadow: none; color: var(--hub-body); }
.app-nav-link.active { background: var(--hub-card); border-left-color: var(--hub-yellow); box-shadow: none; color: var(--hub-title); }
.app-nav-icon { background: var(--hub-line-strong); flex: 0 0 9px; height: 9px; width: 9px; }
.app-nav-link.active .app-nav-icon { background: var(--hub-yellow); }
.app-nav-link > strong { font-size: var(--fs-lead); font-weight: 400; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.app-nav-link.active > strong { font-weight: 600; }

.app-topbar {
    align-items: center;
    background: var(--hub-deep);
    border-bottom: 1px solid var(--hub-line);
    display: grid;
    gap: 1.5rem;
    grid-column: 1 / -1;
    grid-row: 1;
    /* Marca | busca | tema — e a busca no CENTRO da barra: as laterais tem
       o mesmo 1fr, entao a coluna do meio fica centrada de verdade. O desenho
       antigo (espaco flexivel + busca encostada na direita) fazia sentido com
       o XP de contrapeso; sem ele, a busca ficava pendurada fora do eixo. */
    grid-template-columns: 1fr minmax(260px, 460px) 1fr;
    min-width: 0;
    padding: 0 24px;
    position: sticky;
    top: 0;
    /* Acima da barra colorida (41): o painel de resultados nasce aqui dentro e
       precisa passar por cima dela. */
    z-index: 50;
}
/* Filho direto de proposito: a mesma classe se repete dentro da folha de busca
   do celular, e la o alinhamento nao tem nada a alinhar. */
.app-topbar > .topbar-search { justify-self: center; }

.topbar-brand { align-items: center; color: var(--hub-title); display: inline-flex; font: 600 var(--fs-body) var(--hub-mono); gap: 10px; justify-self: start; letter-spacing: var(--ls-caps); text-decoration: none; }
.topbar-brand img { display: block; height: 26px; width: 26px; }
.topbar-search { display: block; max-width: 560px; width: 100%; }
.topbar-search input { background: var(--hub-outside); border: 1px solid var(--hub-line); color: var(--hub-body); font-family: var(--hub-font); font-size: var(--fs-body); min-height: 38px; padding: .55rem .8rem; width: 100%; }
/* O botao de limpar de <input type="search"> e desenhado pelo navegador, com
   o degrade do sistema, e nao aceita token de cor. Some em todos os campos; o
   `type` continua sendo search porque e ele que da a tecla "buscar" no teclado
   do celular e o papel certo para o leitor de tela. */
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration { appearance: none; display: none; }

.topbar-search input::placeholder { color: var(--hub-dim); }

/* Só a busca mobile mora aqui: saldo, avisos e perfil desceram para a barra. */
.topbar-actions { align-items: center; display: flex; gap: 16px; justify-self: end; min-width: 0; }

.icon-button {
    align-items: center;
    background: var(--hub-card);
    border: 1px solid var(--hub-line-strong);
    color: var(--hub-body);
    display: inline-flex;
    min-height: var(--btn-icon-sm);
}

.icon-button { justify-content: center; text-decoration: none; width: 32px; }
.icon-button, .icon-button:hover { box-shadow: none; }

.player-badge { align-items: center; display: flex; gap: .5rem; }
.player-avatar,
.mini-avatar,
.community-avatar {
    align-items: center;
    background: var(--hub-purple);
    color: var(--hub-on-accent);
    display: inline-flex;
    font-family: var(--hub-mono);
    font-weight: 600;
    justify-content: center;
}
.player-avatar { height: 32px; width: 32px; }
.player-avatar img { display: block; height: 100%; object-fit: cover; width: 100%; }
.player-info { display: grid; line-height: var(--lh-heading); }
.player-info strong { color: var(--hub-title); font-size: var(--fs-micro); }
.player-info small { color: var(--hub-dim); font-size: var(--fs-nano); }
.player-badge-compact .player-info { display: none; }
/* A barra colorida e a linha 2 da moldura no desktop; no mobile o proprio
   componente a prende no rodape. */
.app-nav-bar {
    background: var(--hub-deep);
    display: grid;
    grid-column: 1;
    grid-row: 2;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    position: relative;
    z-index: 30;
}
/* O perfil comercial nao tem caixa de mensagens nesta entrega, entao a barra
   volta a cinco blocos e a coluna 4 nao fica vazia no meio. */
.app-nav-bar--commercial { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.app-nav-bar__item { align-items: center; display: flex; justify-content: center; min-height: 42px; text-decoration: none; }

/* ==========================================================================
   O AVISO — UM DESENHO SÓ, QUATRO TONS
   ==========================================================================
   O aplicativo tinha três peças diferentes para dizer coisas de passagem: o
   toast, a barra de "instale o app" e a faixa de erro do circuito, que nascia
   colada no rodapé com fundo escuro e letra miúda. Numa das telas as três
   apareceram JUNTAS — "Publicado." em cima e "Ocorreu um erro inesperado"
   embaixo, contando histórias opostas com caras diferentes.

   Agora é uma caixa só: quadrado sólido com o desenho da casa dentro, texto, e
   — quando há o que fazer — uma ação na MESMA linha. O tom mora no quadrado, e
   nunca numa fita em cima da caixa: a fita de 3px é o vocabulário de "tipo de
   cartão", e num aviso de cinco segundos ela era um segundo sinal dizendo o que
   o quadrado já diz, do outro lado da peça. */
.hub-toast {
    align-items: center;
    background: var(--hub-card);
    border: 1px solid var(--hub-line-strong);
    bottom: 24px;
    box-shadow: 8px 8px 0 rgb(0 0 0 / 28%);
    color: var(--hub-body);
    display: flex;
    gap: .75rem;
    max-width: min(420px, calc(100vw - 32px));
    min-width: min(340px, calc(100vw - 32px));
    padding: .8rem;
    position: fixed;
    right: 24px;
    z-index: 150;
}

.hub-toast__mark {
    align-items: center;
    color: var(--hub-on-accent);
    display: flex;
    flex: none;
    height: 34px;
    justify-content: center;
    width: 34px;
}

.hub-toast--success .hub-toast__mark { background: var(--hub-green); }
.hub-toast--error .hub-toast__mark { background: var(--hub-red); }
.hub-toast--neutral .hub-toast__mark { background: var(--hub-yellow); }
.hub-toast--info .hub-toast__mark { background: var(--hub-blue); }

.hub-toast p { flex: 1; font-size: var(--fs-body); line-height: var(--lh-snug); margin: 0; min-width: 0; }
.hub-toast strong { color: var(--hub-title); display: block; font-size: var(--fs-body); }
.hub-toast small { color: var(--hub-dim); display: block; font-size: var(--fs-meta); line-height: var(--lh-snug); }

/* A AÇÃO FICA NA MESMA LINHA, e é sempre um `.btn` da casa — o convite de
   instalar tinha o botão numa linha própria, embaixo do texto, e por isso o
   aviso ocupava três alturas de linha para oferecer um clique. */
.hub-toast__action { flex: none; }

/* O AVISO QUE NÃO FLUTUA — para a tela que não tem circuito (21/08/2026).

   As doze sub-telas de conta são estáticas: elas POSTAM um formulário e voltam
   renderizadas pelo servidor. Não há Blazor ligado nelas, então não há quem
   feche um aviso nem quem conte os cinco segundos.

   Um `.hub-toast` normal ali seria uma caixa presa no canto da tela que
   ninguém consegue dispensar — pior que a faixa que ele veio substituir. Então
   a peça ganha uma variante que FLUI no lugar onde a faixa estava: mesmo
   quadrado com o desenho, mesmos três tons, mesma frase. O que ela não tem é o
   `×` e o relógio, porque numa página estática eles seriam botões mortos.

   Vale para o `StatusMessage`, que é por onde as 24 telas de conta e de
   autenticação falam. */
.hub-toast--inline {
    bottom: auto;
    box-shadow: none;
    margin: 0 0 .9rem;
    max-width: none;
    min-width: 0;
    position: static;
    right: auto;
    width: 100%;
    z-index: auto;
}

.hub-toast__close {
    align-items: center;
    background: transparent;
    border: 0;
    color: var(--hub-dim);
    cursor: pointer;
    display: flex;
    flex: none;
    height: 28px;
    justify-content: center;
    padding: 0;
    width: 28px;
}

.hub-toast__close:hover { color: var(--hub-title); }

/* A FAIXA DE ERRO DO CIRCUITO É O MESMO AVISO.
   O elemento de fora continua sendo o interruptor — é nele que o Blazor escreve
   `display: block` quando o circuito cai —, e o toast mora dentro. Trocar o
   `display` do próprio toast quebraria a linha, porque o estilo em linha do
   Blazor vence a folha. */
#blazor-error-ui { display: none; }

/* A CAIXA DE MENSAGENS FLUTUANTE — só no computador.

   No celular o envelope já é um dos cinco blocos da barra colorida e a tela
   inteira é a conversa; aqui embaixo o botão só taparia a barra. No computador
   ele resolve o oposto: responder custava sair do feed e voltar depois.

   O verde é `--hub-nav-messages`, o MESMO do bloco de mensagens na fita — cada
   bloco tem a sua tela, e esta é a mesma porta. Fica abaixo do diálogo (100) e
   do aviso (150) na pilha: quando os dois aparecem, é porque têm algo mais
   urgente a dizer do que um atalho. */
/* À ESQUERDA, e isso é sobre a SOMBRA. A sombra dura da casa cai para a
   direita-baixo, e no canto direito ela ficava apontando para fora da tela —
   parecia luz vindo do lugar errado. Trocando o lado, a sombra volta ao sentido
   de sempre e o painel passa a se descolar do conteúdo naturalmente. */
.messages-dock {
    align-items: flex-start;
    bottom: 24px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    left: 24px;
    position: fixed;
    z-index: 90;
}

.messages-dock__trigger {
    align-items: center;
    background: var(--hub-nav-messages);
    border: 1px solid var(--hub-nav-messages);
    color: var(--hub-on-accent);
    cursor: pointer;
    display: inline-flex;
    height: 52px;
    justify-content: center;
    padding: 0;
    position: relative;
    width: 52px;
}

.messages-dock__trigger:hover { box-shadow: 4px 4px 0 rgb(0 0 0 / 28%); }
.messages-dock__trigger:focus-visible { outline: 1px solid var(--hub-yellow); outline-offset: 2px; }

/* O contador é o sinal de que há algo esperando, e por isso vermelho: verde é o
   bloco, não o estado. */
.messages-dock__badge {
    align-items: center;
    background: var(--hub-red);
    color: var(--hub-on-accent);
    display: flex;
    font: 600 var(--fs-nano) var(--hub-mono);
    height: 18px;
    justify-content: center;
    min-width: 18px;
    padding: 0 3px;
    position: absolute;
    right: -6px;
    top: -6px;
}

/* A LINHA DE CONVERSA — retrato, nome, prévia e a hora com o contador.
   Nasceu presa ao CSS isolado da tela de mensagens e subiu quando a caixa
   flutuante passou a mostrar a mesma lista: escopo por componente não
   atravessa, então lá ela vinha sem estilo nenhum. Mesma história do resto
   desta folha — a peça sobe quando a segunda tela aparece. */
.messages-row {
    align-items: center;
    border-bottom: 1px solid var(--hub-line-soft);
    color: inherit;
    display: grid;
    gap: .65rem;
    grid-template-columns: 40px minmax(0, 1fr) auto;
    padding: .8rem 1rem;
    text-decoration: none;
}

.messages-row:hover {
    background: var(--hub-row-hover);
}

.messages-row.is-open {
    background: var(--hub-hover);
}

.messages-row__avatar {
    height: 40px;
    overflow: hidden;
    width: 40px;
}

.messages-row__avatar img {
    height: 100%;
    object-fit: cover;
    width: 100%;
}

.messages-row__body {
    display: grid;
    gap: .15rem;
    min-width: 0;
}

.messages-row__body strong {
    color: var(--hub-title);
    font-size: var(--fs-body);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.messages-row__body small {
    color: var(--hub-dim);
    font-size: var(--fs-meta);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.messages-row__meta {
    align-items: end;
    display: grid;
    gap: .3rem;
    justify-items: end;
}

.messages-row__meta time {
    color: var(--hub-mute);
    font: 500 var(--fs-nano)/var(--lh-tight) var(--hub-mono);
}

/* SEM LER, A LINHA INTEIRA FICA DE PÉ.
   O fio amarelo da borda e o contador diziam "tem coisa nova" só para quem já
   sabia onde olhar. O que se lê de relance numa lista é o PESO do nome e a cor
   do trecho: lidas ficam no tom apagado de sempre, e a não lida sobe para o tom
   de leitura. Os três sinais juntos — fio, peso e contador — é o que faz a
   diferença aparecer sem precisar procurar. */
.messages-row.is-unread .messages-row__body strong { font-weight: 700; }
.messages-row.is-unread .messages-row__body small { color: var(--hub-body); }

/* O contador de não-lidas é o único número da lista, então ele carrega o
   amarelo — do mesmo jeito que o ponto da barra de navegação. */
.messages-row__meta em {
    background: var(--hub-yellow);
    color: var(--hub-on-accent);
    font: 600 var(--fs-nano)/var(--lh-tight) var(--hub-mono);
    font-style: normal;
    min-width: 18px;
    padding: 2px 5px;
    text-align: center;
}

/* Clicar fora recolhe. O véu é TRANSPARENTE, ao contrário do véu escuro do
   diálogo: o painel é um atalho e não uma decisão — escurecer a página diria
   que o resto parou de valer, e quem está lendo o feed atrás dele continua
   lendo. Ele fica sob o painel e sobre o resto. */
.messages-dock__veil { inset: 0; position: fixed; z-index: 89; }

/* 440px é a largura do escritor com folga: abaixo disso a fileira de anexo,
   emoji, voz e enviar aperta o campo até o convite quebrar em duas linhas.
   Sombra dura da casa, no sentido de sempre — é o painel que mudou de lado
   para poder tê-la assim. */
.messages-dock__panel {
    box-shadow: 8px 8px 0 rgb(0 0 0 / 28%);
    display: grid;
    grid-template-rows: auto minmax(0, 1fr);
    height: min(560px, calc(100dvh - 140px));
    padding: 0;
    /* Âncora dos diálogos de dentro: denúncia, bloqueio e sair da conversa
       abrem SOBRE o painel, e não no meio da tela. Ver `.messages-dock__panel
       .dm-sheet` mais abaixo. */
    position: relative;
    width: 440px;
}

.messages-dock__head {
    align-items: center;
    border-bottom: 1px solid var(--hub-line-strong);
    display: flex;
    gap: 10px;
    min-height: 48px;
    padding: 0 8px 0 14px;
}

.messages-dock__head > strong { color: var(--hub-title); flex: 1; font-size: var(--fs-body); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.messages-dock__back,
.messages-dock__expand,
.messages-dock__close {
    background: transparent;
    border: 0;
    color: var(--hub-dim);
    cursor: pointer;
    flex: none;
    font-size: var(--fs-meta);
    padding: .3rem .45rem;
    text-decoration: none;
}

.messages-dock__back:hover,
.messages-dock__expand:hover,
.messages-dock__close:hover { color: var(--hub-title); }

/* A rolagem é do CORPO, e não do painel: o cabeçalho fica parado, como no
   cabeçalho fixo da conversa no celular. */
.messages-dock__body { display: grid; min-height: 0; overflow: hidden; }

/* `align-content: start` NÃO É DETALHE: sem ele a grade reparte a altura sobrando
   entre as conversas, e três linhas viram três blocos gigantes com o nome
   perdido no meio. Foi o que o dono viu como "conversas desajustadas". */
.messages-dock__list {
    align-content: start;
    display: grid;
    list-style: none;
    margin: 0;
    overflow-y: auto;
    padding: 6px;
}

.messages-dock__list > li { min-width: 0; }
.messages-dock__list .messages-row { text-align: left; width: 100%; }
.messages-dock__new { padding: 4px 4px 8px; }
.messages-dock__new > .btn { width: 100%; }

.messages-dock__picker { display: grid; grid-template-rows: auto minmax(0, 1fr); min-height: 0; }

/* O CAMPO É O CAMPO DA CASA. Ele estava colado nas bordas e sem altura, porque
   `margin: 0` o tirava do respiro e nada lhe dava o `--field-h` de 42px que
   todo campo do app tem. Aqui ele ganha a moldura de sempre e um vão em volta,
   como em qualquer formulário. */
.messages-dock__search {
    background: var(--hub-field);
    border: 1px solid var(--hub-line-strong);
    margin: 10px;
    min-height: var(--field-h);
    padding: 0 .75rem;
    width: calc(100% - 20px);
}

.messages-dock__search:focus { border-color: var(--hub-yellow); outline: 0; }
.messages-dock__vazio { align-content: center; display: grid; gap: 12px; justify-items: center; padding: 20px; }
.messages-dock__vazio > .empty-state { margin: 0; }
.messages-dock__body > .empty-state { margin: 0; padding: 20px; }

/* A espera fica no MEIO do painel, empilhada: numa coluna estreita o rótulo ao
   lado dos quadradinhos empurrava os dois para fora do centro. */
.messages-dock__loading { align-content: center; justify-items: center; padding: 24px; text-align: center; }

/* PAINEL SÓBRIO: sem as fitas coloridas.
   No computador a tela de mensagens desenha TRÊS cartões empilhados, cada um
   com a sua fita — azul na conversa, amarela no escritor. Aquilo é a composição
   de uma página inteira; espremido num painel de 440px vira um empilhado de
   listras. Aqui o painel é uma superfície só, e as bordas de cartão de dentro
   somem com elas. */
.messages-dock__panel .dm-thread__card,
.messages-dock__panel .dm-composer,
.messages-dock__panel .dm-thread__closed {
    border: 0;
    box-shadow: none;
    height: auto;
    margin-top: 0;
    padding-top: 0;
}

.messages-dock__panel .dm-thread__card::before,
.messages-dock__panel .dm-composer::before { display: none; }
.messages-dock__panel .dm-composer { border-top: 1px solid var(--hub-line); }

/* AS CAMADAS DO MENSAGEIRO ABREM NO CENTRO DA PÁGINA — decisão do dono,
   17/08/2026. Elas já eram assim por natureza (`position: fixed` centrado):
   são as mesmas de quando a conversa É a página inteira.

   Houve uma tentativa de prendê-las ao painel, pela ideia de que o diálogo
   deve nascer onde o gesto aconteceu. Na tela ficou pior: um diálogo de 414px
   espremido no canto esquerdo de um monitor largo, cobrindo por inteiro o
   painel que o abriu — e a conversa, que era o contexto, sumia atrás dele.
   Decidir é uma pausa na página; a página inteira é o lugar disso.

   Não escrever aqui nenhuma regra que reposicione `.dm-sheet`, `.dm-confirm`
   ou `.hub-modal` dentro de `.messages-dock__panel`. E se um dia isso voltar
   a ser tentado, saiba que as duas primeiras nascem no CSS ISOLADO da conversa
   (`.dm-sheet[b-xxxx]`, mesma especificidade que `.messages-dock__panel
   .dm-sheet`) e que o pacote isolado carrega DEPOIS deste arquivo: sem um
   `body` na frente, a regra daqui perde calada e só a denúncia obedece —
   que foi exatamente o defeito que apareceu na tela. */

@media (max-width: 760px) {
    .hub-toast {
        bottom: calc(82px + env(safe-area-inset-bottom));
        left: 16px;
        max-width: none;
        min-width: 0;
        right: 16px;
    }
}

/* Cabeçalhos e controles ------------------------------------------------- */

/* O CABEÇALHO DE PÁGINA — peça única (<PageHeader>, régua do dono 15/08/2026):
   título 600 + subtítulo apagado, sem sobretexto — kicker acima de título de
   página saiu do vocabulário. Substitui o coro P2 de nove classes
   {tela}-heading que dizia isto com nove nomes. A peça não traz margem: o vão
   pertence ao layout da página, que já o dá por grid/gap. */
.hub-page-heading { align-items: end; display: flex; gap: 1.5rem; justify-content: space-between; }
.hub-page-heading__copy { min-width: 0; }
.hub-page-heading h1 { color: var(--hub-title); font-size: var(--fs-h1); font-weight: 600; letter-spacing: var(--ls-tight); margin: 0; }
.hub-page-heading__copy p { color: var(--hub-dim); font-size: var(--fs-lead); margin: .4rem 0 0; max-width: 72ch; }
.hub-page-heading__actions { align-items: center; display: flex; flex-wrap: wrap; gap: .5rem; justify-content: flex-end; }
@media (max-width: 900px) {
    .hub-page-heading--desktop { display: none; }
    .hub-page-heading h1 { font-size: var(--fs-h1-compact); }
}
/* 600 e o peso mais forte que o IBM Plex Mono carrega; 700 aqui seria negrito
   falsificado pelo navegador (a eyebrow herda mono da regra compartilhada). */
/* P5 · EYEBROW. Etiqueta de pagina e de secao: mono, caixa alta, amarela.
   Antes so ficava amarela dentro de .page-header, e cada tela criava a sua
   variante cinza (micro-label, settings-microlabel, search-kicker,
   report-label). Agora e uma classe so, e ela vale onde for usada.
   Excecao documentada: cabecalho de GRUPO DE LISTA continua apagado, mais
   abaixo — ali a etiqueta separa blocos, nao anuncia a secao. */
.eyebrow, .section-kicker { color: var(--hub-yellow); font-size: var(--fs-micro); font-weight: 600; letter-spacing: var(--ls-caps-wide); margin: 0 0 .25rem; text-transform: uppercase; }

/* BOTOES ------------------------------------------------------------------
   Duas escolhas independentes, nunca misturadas na mesma classe:
     TAMANHO  .btn-sm | (padrao) | .btn-lg          -> caixa e texto
     TIPO     .btn-primary | .btn-secondary | .btn-danger
              .btn-ghost | .btn-link | .btn-icon    -> cor e peso visual
   Um botao e sempre `.btn` + no maximo um tamanho + no maximo um tipo. */

.btn {
    align-items: center;
    background: transparent;
    border: 1px solid var(--hub-line-strong);
    color: var(--hub-body);
    cursor: pointer;
    display: inline-flex;
    font-size: var(--btn-fs-md);
    font-weight: var(--btn-weight);
    gap: .5rem;
    justify-content: center;
    letter-spacing: var(--ls-flat);
    min-height: var(--btn-h-md);
    padding: var(--btn-pad-md);
    text-decoration: none;
    text-transform: none;
}

.btn, .btn:hover, .btn:active { box-shadow: none; filter: none; transform: none; }
.btn:hover { background: var(--hub-hover); border-color: var(--hub-dim); color: var(--hub-title); }

/* Tamanhos */
.btn-sm { font-size: var(--btn-fs-sm); min-height: var(--btn-h-sm); padding: var(--btn-pad-sm); }
.btn-lg { font-size: var(--btn-fs-lg); min-height: var(--btn-h-lg); padding: var(--btn-pad-lg); }

/* Tipos */
.btn-primary { background: var(--hub-yellow); border-color: var(--hub-yellow); color: var(--hub-on-accent); }
.btn-primary:hover { background: var(--hub-yellow-hover); border-color: var(--hub-yellow-hover); color: var(--hub-on-accent); }
.btn-secondary { background: var(--hub-card); }
.btn-danger { background: var(--hub-err-bg); border-color: var(--hub-red); color: var(--hub-err-text); }
.btn-danger:hover { background: var(--hub-err-bg); border-color: var(--hub-red); color: var(--hub-title); }
.btn-ghost { border-color: transparent; }
.btn-ghost:hover { background: var(--hub-hover); border-color: var(--hub-line-strong); }
.btn-link { border-color: transparent; color: var(--hub-yellow); padding-inline: .25rem; }

/* Botao que so carrega um glifo: quadrado, sem respiro lateral extra. */
.btn-icon {
    font-size: var(--fs-icon-sm);
    gap: 0;
    min-height: var(--btn-icon-md);
    padding: 0;
    width: var(--btn-icon-md);
}

.btn-sm.btn-icon { min-height: var(--btn-icon-sm); width: var(--btn-icon-sm); }
.btn-lg.btn-icon { min-height: var(--btn-icon-lg); width: var(--btn-icon-lg); }
.btn:disabled, .btn.disabled { cursor: not-allowed; opacity: .45; }
.w-100 { width: 100%; }

/* CHAVE LIGA-DESLIGA. Nasceu escopada nos Ajustes e subiu porque o alternador
   de tema precisa da mesma peca: quadrada, sem arredondamento, com o botao
   deslizando de um lado ao outro. Verde e a cor de "ligado" no cânone. */
.hub-switch {
    align-items: center;
    background: var(--hub-deep);
    border: 1px solid var(--hub-line-strong);
    cursor: pointer;
    display: inline-flex;
    flex: 0 0 40px;
    height: 20px;
    justify-content: flex-start;
    padding: 0;
    width: 40px;
}
.hub-switch i { background: var(--hub-line-strong); height: 16px; margin: 0 2px; width: 16px; }

/* O TOCADOR DE VIDEO — miniatura ate alguem tocar, e so entao o iframe.
   Nasceu escopado no mensageiro e subiu quando a publicacao passou a fazer o
   mesmo. O fundo e o mesmo do embrulho de citacao do balao. */
.hub-video { display: grid; }

.hub-video__play {
    background: var(--hub-bubble-embed);
    border: 1px solid var(--hub-line-strong);
    cursor: pointer;
    display: grid;
    padding: 0;
    position: relative;
}

.hub-video__play img {
    aspect-ratio: 16 / 9;
    display: block;
    object-fit: cover;
    width: 100%;
}

.hub-video__glyph {
    align-items: center;
    background: var(--hub-red);
    color: var(--hub-on-accent);
    display: flex;
    font-size: var(--fs-icon-md);
    height: 44px;
    justify-content: center;
    left: 50%;
    position: absolute;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 62px;
}

.hub-video iframe {
    aspect-ratio: 16 / 9;
    border: 1px solid var(--hub-line-strong);
    display: block;
    width: 100%;
}

/* A LINHA DE PERFIL NUMA LISTA — retrato, nome com o @, uma linha de apoio e a
   acao na ponta. Nasceu escopada na tela de Conexoes e subiu porque a lista de
   contas bloqueadas em /settings mostra a mesma coisa: la ela era um contador
   com um link para outra tela, e quem chegava pela notificacao de bloqueio nao
   encontrava nem quem tinha bloqueado nem como desfazer.

   CADA PESSOA E UM CARTAO (decisao do dono, 17/08/2026). Ela era uma linha sem
   fundo, separada da seguinte por um filete — e a lista de participantes de
   uma comunidade, que mostra exatamente a mesma coisa, ja era cartao com
   moldura e vao entre um e outro. Duas telas de "gente numa lista" com dois
   desenhos. Agora e o mesmo, e o vao vem de quem monta a lista
   (`.connection-rows` / `.connections-list`), nao da linha. */
.connection-rows { display: grid; gap: 1rem; }

.connection-row {
    align-items: center;
    background: var(--hub-card);
    border: 1px solid var(--hub-line);
    display: flex;
    gap: 14px;
    min-width: 0;
    padding: .9rem;
}

.connection-avatar {
    align-items: center;
    color: var(--hub-on-accent);
    display: flex;
    flex: none;
    font: 600 var(--fs-avatar-row) var(--hub-mono);
    height: 36px;
    justify-content: center;
    text-decoration: none;
    width: 36px;
}

.connection-avatar img { display: block; height: 100%; object-fit: cover; width: 100%; }
.connection-copy { flex: 1; min-width: 0; }
.connection-name-line { align-items: center; display: flex; flex-wrap: wrap; gap: 8px; }
.connection-name-line > a { color: var(--hub-title); font-size: var(--fs-lead); font-weight: 600; text-decoration: none; }
.connection-name-line > span:not(.blocked-name) { color: var(--hub-mute); font: var(--fs-sm) var(--hub-mono); }

.connection-name-line b {
    background: var(--hub-blue);
    color: var(--hub-on-accent);
    font: 500 var(--fs-nano) var(--hub-mono);
    letter-spacing: var(--ls-label);
    padding: .1rem .35rem;
}

.connection-copy small { color: var(--hub-dim); display: block; font-size: var(--fs-body); margin-top: 3px; }
.blocked-name { color: var(--hub-body); font-size: var(--fs-lead); }
.blocked-row .connection-copy small { color: var(--hub-mute); font-family: var(--hub-mono); font-size: var(--fs-sm); }

/* A LINHA DE RODAPE DE UMA FOLHA — a acao principal, separada do resto por um
   filete e no mesmo formato de um item de menu.
   Nasceu escopada na barra de navegacao e subiu porque o indice de Ajustes no
   celular precisa da MESMA peca para "Sair da conta": la ela era um botao de
   caixa com contorno vermelho ocupando a largura toda, o elemento mais gritado
   de uma tela que nao tem nenhuma outra acao. O nome guarda a origem; as cores
   por bloco continuam no CSS da barra. */
.nav-sheet__footer-item {
    align-items: center;
    background: transparent;
    border: 0;
    border-top: 1px solid var(--hub-line);
    color: var(--hub-dim);
    cursor: pointer;
    display: flex;
    font-family: var(--hub-font);
    gap: 12px;
    min-height: 44px;
    padding: .7rem 20px;
    text-align: left;
    text-decoration: none;
    width: 100%;
}

.nav-sheet__footer-item strong { font-size: var(--fs-lead); font-weight: 400; }
.nav-sheet__footer-icon { background: var(--hub-line-strong); flex: 0 0 9px; height: 9px; width: 9px; }

.nav-sheet__footer-item:hover,
.nav-sheet__footer-item:focus-visible {
    background: var(--hub-row-hover);
    color: var(--hub-body);
    outline: 0;
}

/* Sair da conta e vermelho onde quer que esteja. */
.nav-sheet__logout { margin: 0; }
.nav-sheet__logout .nav-sheet__footer-item { color: var(--hub-red); }
.nav-sheet__logout .nav-sheet__footer-icon { background: var(--hub-red); }

/* A MESMA CHAVE, MOVIDA POR UM CAMPO.
   Dentro de um formulario quem manda e o <input type="checkbox">, para o teclado
   e o @bind funcionarem sem JavaScript nenhum: e o `:checked` dele que empurra
   o trilho, e nao uma classe. (A chave de TEMA tem a sua propria regra mais
   abaixo, presa ao atributo do <html> — veja o comentario de la.)

   Nasceu de TRES copias byte a byte do mesmo trilho — `.commercial-toggle`,
   `.manage-visibility` e `.community-message-mode` —, que divergiam em duas
   coisas: a cor do fio e, na do mapa, a AUSENCIA de foco visivel. Como o
   <input> real e transparente e tem 1x1px, aquela chave era invisivel ao
   teclado: o foco existia e nao aparecia em lugar nenhum. */
.hub-switch-field {
    align-items: center;
    cursor: pointer;
    display: grid;
    gap: .65rem;
    grid-template-columns: auto minmax(0, 1fr);
}

.hub-switch-field > input { height: 1px; opacity: 0; position: absolute; width: 1px; }
.hub-switch-field > input:checked + .hub-switch { background: var(--hub-green); border-color: var(--hub-green); justify-content: flex-end; }
.hub-switch-field > input:checked + .hub-switch i { background: var(--hub-on-accent); }
.hub-switch-field > input:focus-visible + .hub-switch { outline: 1px solid var(--hub-yellow); outline-offset: 2px; }
.hub-switch-field > input:disabled + .hub-switch { cursor: not-allowed; opacity: .5; }
.hub-switch-field__copy { display: grid; gap: .12rem; min-width: 0; }
.hub-switch-field__copy strong { color: var(--hub-title); font-size: var(--fs-body); }
.hub-switch-field__copy small { color: var(--hub-dim); font-size: var(--fs-sm); }

/* A chave de tema nao acende por classe: a posicao dela sai do atributo do
   <html>. Classe no botao a navegacao melhorada apaga ao trocar de pagina — o
   atributo no <html> ela nao toca, e por isso a chave nao volta sozinha para a
   esquerda no meio da navegacao. */
:root[data-hub-theme="dark"] .theme-toggle__button { background: var(--hub-green); border-color: var(--hub-green); justify-content: flex-end; }
:root[data-hub-theme="dark"] .theme-toggle__button i { background: var(--hub-on-accent); }
.theme-toggle { align-items: center; display: inline-flex; gap: .45rem; }
.theme-toggle__label { color: var(--hub-mute); font: 600 var(--fs-micro) var(--hub-mono); letter-spacing: var(--ls-caps); text-transform: uppercase; }

/* Superfícies e layouts -------------------------------------------------- */
.map-layout { grid-template-columns: minmax(0, 1.8fr) minmax(260px, .8fr); }

/* CARTAO COM FAIXA COLORIDA NO TOPO. Nasceu escopado no feed, mas
   CommunityPolicy e HiddenPosts ja pediam a classe no markup e ficavam sem
   estilo nenhum. A faixa e SEMPRE no topo: a borda ESQUERDA fica reservada a
   alerta e estado (.alert-*, .is-unread, .empty-state), e misturar as duas
   apaga a diferenca entre "que tipo de cartao e este" e "algo aconteceu". */
/* A FAIXA DO CARTAO E AMARELA, e ela so muda de cor quando a COR E O ASSUNTO
   (dono, 18/08/2026).

   Antes cada tela escolhia a sua, e descer uma pagina era ler tres cores sem
   nenhuma regra: o cabecalho de perfil roxo, o compositor logo abaixo azul, e
   as publicacoes vermelhas. Nenhuma das tres dizia nada — eram vizinhas de
   acaso.

   O que sobrou, e o que cada uma quer dizer:

   - AMARELO e o padrao. E a cor da CASA e a cor da ACAO no app inteiro; um
     cartao que nao esta comunicando outra coisa veste ela.
   - VERMELHO e o que NAO TEM VOLTA: excluir, denunciar, bloquear. Ele so
     aparece em dialogo de decisao, e por isso continua tendo peso quando
     aparece. A publicacao e o compositor largaram o vermelho justamente para
     nao empatar com o do "excluir" tres linhas abaixo.
   - VERDE e o que DEU CERTO — a confirmacao de que a denuncia chegou, a barra
     de XP.
   - AZUL NAO VESTE FAIXA: ele e a cor do LINK, e e so isso que o dono quer
     que ele diga.
   - ROXO NAO VESTE FAIXA: ele e superficie e marca (avatar de comunidade,
     bloco de conta na barra, selo de convite).

   `HubCardBandTests` cobra as duas metades: nenhuma faixa azul ou roxa volta,
   e o vermelho nao sai do dialogo de perigo. */
.hub-card { background: var(--hub-card); border: 1px solid var(--hub-line); position: relative; }
.hub-card::before { content: ""; height: 3px; left: 0; position: absolute; right: 0; top: 0; }
.hub-card--yellow::before { background: var(--hub-yellow); }
.hub-card--blue::before { background: var(--hub-blue); }
.hub-card--purple::before { background: var(--hub-purple); }
.hub-card--green::before { background: var(--hub-green); }
.hub-card--red::before { background: var(--hub-red); }

.panel,
.community-card,
.settings-section {
    background: var(--hub-card);
    border: 1px solid var(--hub-line);
    box-shadow: none;
    color: var(--hub-body);
    margin: 0;
    padding: 1rem;
}

.panel h2,
.panel h3,
.settings-section h2 { color: var(--hub-title); }
.panel h2, .settings-section h2 { font-size: var(--fs-body); letter-spacing: var(--ls-label); margin: 0 0 .8rem; }
.panel h3 { font-size: var(--fs-sm); margin: 0; }
.section-heading { align-items: center; border-bottom: 1px solid var(--hub-line-soft); display: flex; justify-content: space-between; margin: -1rem -1rem .75rem; padding: .7rem 1rem; }
.section-heading h2 { margin: 0; }
.section-heading > span { color: var(--hub-mute); font: var(--fs-nano) var(--hub-mono); }
/* P8 · VAZIO E FEEDBACK. Dois formatos para a tela inteira, e nao um por
   pagina: borda esquerda de 3px, sem fundo, --fs-body. A borda ESQUERDA e de
   estado — a faixa de topo, do .hub-card, e de tipo de cartao. Vinte e duas
   classes *-empty e doze *-feedback viviam repetindo isto com pequenas
   variacoes de tom e recuo. */
.empty-state { background: transparent; border-left: 3px solid var(--hub-line-strong); color: var(--hub-dim); font-size: var(--fs-body); margin: 0; padding: .8rem; }
.empty-state.is-error { border-left-color: var(--hub-red); color: var(--hub-err-text); }
.feedback { background: transparent; border-left: 3px solid var(--hub-green); color: var(--hub-green); font-size: var(--fs-body); margin: 0; padding: .65rem .75rem; }
.feedback.is-success { border-left-color: var(--hub-green); color: var(--hub-green); }
.feedback.is-error { border-left-color: var(--hub-red); color: var(--hub-red); }
.map-canvas > .empty-state { box-shadow: none; }
.muted { color: var(--hub-dim); }

/* Listas de dados -------------------------------------------------------- */

/* P7 · CARTAO DE COMENTARIO. O mesmo desenho aparecia em tres arquivos com
   tres nomes: feed, publicacao e forum. As declaracoes eram identicas fora um
   gap de 2,8px de diferenca. Os nomes ficam onde estao, porque cada tela pendura
   seletores proprios neles; o que era duplicata sai. */
/* P7 · CARTAO DE COMENTARIO. O mesmo desenho aparecia em tres arquivos com
   tres nomes: feed, publicacao e forum. As declaracoes eram identicas fora um
   gap de 2,8px de diferenca. Os nomes ficam onde estao, porque cada tela pendura
   seletores proprios neles; o que era duplicata sai.

   ESTE CORPO JA MORREU UMA VEZ, e o estrago foi grande: ao trocar o antigo
   `.forum-legacy-comment` — que era o ULTIMO seletor desta lista — por um
   comentario, o corpo da regra foi junto. Os quatro seletores ficaram orfaos,
   coleram na regra seguinte (`.hub-gif-card`) e todo comentario do app virou
   uma caixa de 140px: sem a grade de duas colunas, o retrato, o nome e o texto
   empilhavam num filete. Nada acusou, porque CSS invalido nao da erro.

   Quem for mexer aqui: a lista termina no `{` desta linha, e nada de novo
   entra ENTRE o ultimo seletor e ele. `HubCssIntegrityTests` cobra.

   E NADA DE FAIXA COLORIDA (dono, 18/08/2026). Havia uma de 3px vermelha, e
   ela nao era escolha: entrou de carona quando a RESPOSTA do forum dividia
   esta regra — la a faixa tinha motivo. A resposta virou .social-post e levou
   a faixa dela junto; o que ficou aqui era heranca, e pintava de vermelho todo
   comentario do feed, do mural e do topico. */
.comment-card,
.feed-comment-card,
.forum-comment,
.post-comment-card {
    align-items: start;
    background: var(--hub-card);
    border: 1px solid var(--hub-line);
    display: grid;
    gap: 10px;
    grid-template-columns: auto minmax(0, 1fr);
    padding: 1rem 1.1rem;
    position: relative;
}

/* O GIF — A MESMA FIGURA NO FEED E NO MEIO DO TEXTO DO FORUM.

   GIF e reacao, nao fotografia: o dono pediu 1/9 da area da primeira versao
   (420px viraram 140px lineares), um selo que acompanha o texto e nao um
   painel luminoso disputando com ele. O teto vale nos dois lugares, e e por
   isso que o bloco de GIF do editor nao oferece as larguras de 33/50/66/100%
   que a imagem oferece: elas nao mudariam nada contra este max-width.

   Estava no HubGifCard.razor.css. Subiu porque o texto do forum desenha esta
   mesma figura em HTML gravado, e regra isolada nao alcanca markup de outro
   componente. */
/* DENTRO DE UMA PUBLICAÇÃO, O GIF SEGUE O RECUO DO TEXTO (dono, 18/08/2026).
   A regra existia só na folha do feed; no perfil o mesmo cartão desenhava o
   GIF colado na borda esquerda, e a mesma publicação aparecia de dois jeitos
   conforme a tela em que se olhava. Aqui ela vale para toda superfície que use
   o `.social-post` — feed, perfil, mural e perfil público. */
body .hub-shell .hub-content .social-post .hub-gif-card { margin: 0 20px 16px; }

/* MAS O COMENTARIO NAO E A PUBLICACAO (21/08/2026).
   A regra acima recua o GIF para acompanhar o texto DA PUBLICACAO. So que os
   comentarios ficam DENTRO do mesmo `<article class="social-post">`, e o
   seletor de descendente nao sabe disso: o GIF de um comentario ganhava os
   mesmos 20px de recuo, enquanto o texto ao lado dele — que tem o proprio
   recuo, o do cartao de comentario — ficava alinhado a esquerda. O GIF
   aparecia um dedo mais para dentro que tudo em volta.

   Zero aqui porque o espaco ja vem do embrulho (`.post-comment-card__image`,
   8px), o mesmo que a FOTO do comentario usa — que e por isso que a foto
   sempre esteve alinhada e o GIF nao.

   Especificidade: uma classe a mais que a regra acima, entao vence tambem a
   variante de celular la embaixo sem precisar ser repetida dentro dela. */
body .hub-shell .hub-content .social-post .comment-card .hub-gif-card,
body .hub-shell .hub-content .social-post .feed-comment-card .hub-gif-card,
body .hub-shell .hub-content .social-post .forum-comment .hub-gif-card,
body .hub-shell .hub-content .social-post .post-comment-card .hub-gif-card {
    margin: 0;
}

.hub-gif-card {
    background: var(--hub-card);
    border: 1px solid var(--hub-line);
    margin: .75rem 0 0;
    max-width: 140px;
    overflow: hidden;
    position: relative;
}

.hub-gif-card__vivo {
    display: block;
    height: auto;
    max-height: 140px;
    object-fit: cover;
    width: 100%;
}

.hub-gif-card__origem {
    color: var(--hub-dim);
    font: 500 var(--fs-nano)/var(--lh-tight) var(--hub-mono);
    letter-spacing: var(--ls-caps-wide);
    padding: .3rem .5rem;
    text-transform: uppercase;
}

/* O DESCANSO: depois das voltas o video para no ultimo quadro e o TOCAR
   aparece por cima — quem liga e desliga e o JS inline do proprio elemento,
   que sai do HubGifPlayback. SEM desvio de prefers-reduced-motion, de
   proposito (decisao do dono, 2026-08-14): o sinal do sistema congelava tudo
   e parecia defeito. */
.hub-gif-card__tocar {
    align-items: center;
    background: var(--hub-veil);
    border: 0;
    cursor: pointer;
    display: none;
    inset: 0;
    justify-content: center;
    position: absolute;
}

.hub-gif-card__tocar span {
    background: var(--hub-card);
    border: 1px solid var(--hub-line-strong);
    color: var(--hub-body);
    font: 600 var(--fs-nano)/var(--lh-tight) var(--hub-mono);
    letter-spacing: var(--ls-caps-wide);
    padding: .3rem .5rem;
}

.hub-gif-card__tocar:hover span {
    border-color: var(--hub-yellow);
    color: var(--hub-yellow);
}

/* A RESPOSTA DO FORUM NAO TEM REGRA PROPRIA, E ISSO E O PONTO.
   Ela veste .social-post, e com ele vem tudo: a moldura, o recuo e a FAIXA
   VERMELHA, que sai do ::before logo acima — o mesmo lugar de onde o topico e
   a publicacao tiram a delas. Ate 17/08/2026 ela era uma peca de duas colunas
   (.forum-legacy-comment) com fundo, fio e faixa proprios, e por isso nao
   parecia da mesma familia do assunto que ela responde.

   Quem for tentado a devolver um `border-top` aqui repare no celular: la o
   ::before some e o cartao troca a moldura pelo fio de baixo. Uma borda
   propria sobreviveria a essa troca, e a resposta seria a unica peca da tela
   com faixa no telefone. */

.leaderboard, .record-list, .statement-list, .notification-list, .comment-list { display: grid; }
.leader-row,
.record-row,
.statement-row,
.notification-row,
.comment-row,
.ranking-mini-row {
    align-items: center;
    border-bottom: 1px solid var(--hub-line-soft);
    display: grid;
    gap: .75rem;
    min-width: 0;
    padding: .7rem .25rem;
}
.leader-row:last-child, .record-row:last-child, .statement-row:last-child, .notification-row:last-child { border-bottom: 0; }
.leader-row { background: transparent; grid-template-columns: 42px minmax(0, 1fr) auto; }
.leader-row:first-child { background: transparent; box-shadow: none; }
.record-row { grid-template-columns: minmax(0, 1fr) auto minmax(120px, .5fr); }
.statement-row { grid-template-columns: minmax(0, 1fr) auto 100px; }
.notification-row { grid-template-columns: minmax(0, 1fr) auto; }
.ranking-mini-row { grid-template-columns: 34px minmax(0, 1fr) auto; }
.leader-row strong, .record-row strong, .statement-row strong, .ranking-mini-row strong { color: var(--hub-title); font-size: var(--fs-meta); }
.leader-row small, .record-row small, .statement-row small, .ranking-mini-row small { color: var(--hub-mute); font-size: var(--fs-nano); }
.rank { color: var(--hub-yellow); font: 600 var(--fs-micro) var(--hub-mono); }
.credit-positive { color: var(--hub-green); }
.credit-negative, .text-danger { color: var(--hub-red); }
.text-info { color: var(--hub-blue); }

/* Feed e comunidades ---------------------------------------------------- */

.community-grid { display: grid; gap: 1rem; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.community-header { border-bottom-color: var(--hub-purple); }
.community-feed, .community-composer { display: grid; gap: 1rem; }
.community-card { display: grid; gap: .75rem; min-width: 0; text-decoration: none; }
.community-card:hover { background: var(--hub-hover); }
.community-banner { align-items: end; background: var(--hub-deep); border-bottom: 3px solid var(--hub-yellow); display: flex; min-height: 94px; padding: .75rem; }
.community-avatar { height: 46px; width: 46px; }
.community-avatar,
.player-avatar,
.mini-avatar { box-shadow: none; }
.community-card h2 { color: var(--hub-title); font-size: var(--fs-body); margin: 0; }
.community-card p, .community-card small { color: var(--hub-dim); font-size: var(--fs-micro); margin: 0; }

.community-post { display: grid; gap: .75rem; }
.post-author { align-items: center; display: flex; gap: .6rem; }
.mini-avatar { flex: 0 0 auto; height: 32px; width: 32px; }
.post-author strong { color: var(--hub-title); display: block; font-size: var(--fs-meta); }
.post-meta, .card-meta { color: var(--hub-mute); font: var(--fs-nano) var(--hub-mono); }
.post-body { color: var(--hub-body); font-size: var(--fs-meta); white-space: pre-line; }
.post-actions, .composer-actions, .notification-actions, .settings-actions { align-items: center; display: flex; flex-wrap: wrap; gap: .5rem; }
.notification-row p { color: var(--hub-body); font-size: var(--fs-meta); margin: .25rem 0; }
.notification-row small { color: var(--hub-dim); display: block; font-size: var(--fs-nano); }
.notification-channel { border-left: 2px solid var(--hub-blue); margin-top: .45rem; padding-left: .5rem; }
.notification-channel-success { border-left-color: var(--hub-green); color: var(--hub-ok-text) !important; }
.composer-card { align-items: center; display: grid; gap: .75rem; grid-template-columns: minmax(0, 1fr) auto; }
.community-textarea { min-height: 96px; resize: vertical; }
.comment-form { display: grid; gap: .5rem; grid-template-columns: minmax(0, 1fr) auto; }
.comment-row { grid-template-columns: auto minmax(0, 1fr); }

/* Mapa ------------------------------------------------------------------- */

.map-canvas {
    background: var(--hub-deep);
    border: 1px solid var(--hub-line-strong);
    min-height: 480px;
    overflow: hidden;
    position: relative;
}
.map-canvas::before, .map-canvas::after { background: var(--hub-line-soft); content: ""; position: absolute; }
.map-canvas::before { height: 1px; left: 0; right: 0; top: 50%; }
.map-canvas::after { bottom: 0; left: 50%; top: 0; width: 1px; }
.map-pin { align-items: center; background: var(--hub-yellow); border: 2px solid var(--hub-bg); box-shadow: none; color: var(--hub-on-accent); display: flex; font-size: var(--fs-nano); font-weight: 700; height: 26px; justify-content: center; position: absolute; text-decoration: none; transform: translate(-50%, -50%); width: 26px; z-index: 2; }
.map-pin:hover { background: var(--hub-title); box-shadow: none; color: var(--hub-on-accent); }
.map-panel { padding: .75rem; }

/* Perfil e ajustes ------------------------------------------------------- */
.settings-section { display: grid; gap: .75rem; }
.settings-section--wide { grid-column: 1 / -1; }
.settings-note { color: var(--hub-dim); font-size: var(--fs-micro); margin: 0; }

/* Formulários ------------------------------------------------------------ */

.form-grid { display: grid; gap: .8rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.field { display: grid; gap: .3rem; }
.field-full { grid-column: 1 / -1; }
/* Rotulo de campo em --fs-meta, como na pagina de estabelecimentos: --fs-nano
   (8,6px) e legivel num selo, mas nao em algo que a pessoa precisa ler para
   preencher o campo certo. */
.form-label, .control-label, .field > label, .form-floating > label { color: var(--hub-dim); font: 600 var(--fs-meta) var(--hub-mono); letter-spacing: var(--ls-label); text-transform: uppercase; }

/* P9 · CAMPO PADRAO. Altura --field-h (42px), a mesma do .btn-lg: campo e
   botao lado a lado tem de alinhar. O texto e --fs-body, como manda a regua —
   estava em --fs-meta, que e degrau de metadado e ficava minusculo dentro de
   uma caixa de 42px. A busca da topbar segue em 38px, exceção documentada. */
.form-control, .input, select, textarea {
    background: var(--hub-field);
    border: 1px solid var(--hub-line-strong);
    color: var(--hub-body);
    display: block;
    font-family: var(--hub-font);
    font-size: var(--fs-body);
    min-height: var(--field-h);
    padding: .55rem .65rem;
    width: 100%;
}
.field small, .toggle-copy small { font-family: var(--hub-font); }
.form-control:hover, .input:hover, select:hover, textarea:hover { border-color: var(--hub-dim); }
.form-control:focus, .input:focus, select:focus, textarea:focus { background: var(--hub-field); border-color: var(--hub-blue); box-shadow: none !important; color: var(--hub-title); outline: 0; }
.form-control:disabled, .form-control[readonly] { background: var(--hub-deep); color: var(--hub-mute); }
.form-floating { display: grid; gap: .3rem; }
.form-floating > .form-control { height: auto; line-height: inherit; padding: .55rem .65rem; }
.form-floating > label { order: -1; padding: 0; position: static; transform: none; }
.form-check-input { appearance: none; background: var(--hub-field); border: 1px solid var(--hub-line-strong); height: 16px; margin: 0; width: 16px; }
.form-check-input:checked { background: var(--hub-yellow); border-color: var(--hub-yellow); box-shadow: inset 0 0 0 3px var(--hub-field); }
.hub-checkbox { appearance: none; background: var(--hub-field); border: 1px solid var(--hub-line-strong); cursor: pointer; display: grid; flex: 0 0 18px; height: 18px; margin: 0; place-items: center; width: 18px; }
.hub-checkbox:checked { background: var(--hub-yellow); border-color: var(--hub-yellow); }
.hub-checkbox:checked::after { color: var(--hub-on-accent); content: "✓"; font: 600 var(--fs-body) var(--hub-font); line-height: var(--lh-tight); }
.hub-checkbox:focus-visible { outline: 2px solid var(--hub-yellow); outline-offset: 2px; }
.checkbox { align-items: center; color: var(--hub-dim); display: flex; font-size: var(--fs-micro); gap: .5rem; }
.validation-message, .text-danger { display: block; font-size: var(--fs-nano); margin-top: .25rem; }

.alert,
.alert-success,
.alert-danger,
.alert-warning,
.alert-info {
    background: var(--hub-card);
    border: 1px solid var(--hub-line-strong);
    border-left-width: 4px;
    color: var(--hub-body);
    font-size: var(--fs-meta);
    margin-bottom: .8rem;
    padding: .65rem .75rem;
}
.alert-success { background: var(--hub-ok-bg); border-left-color: var(--hub-green); color: var(--hub-ok-text); }
.alert-danger { background: var(--hub-err-bg); border-left-color: var(--hub-red); color: var(--hub-err-text); }
.alert-warning { background: var(--hub-warn-bg); border-left-color: var(--hub-yellow); color: var(--hub-warn-text); }
.alert-info { background: var(--hub-deep); border-left-color: var(--hub-blue); color: var(--hub-body); }
.alert, .alert-success, .alert-danger, .alert-warning, .alert-info { box-shadow: none; }
.turnstile-widget, .cf-turnstile { max-width: 100%; overflow: hidden; width: 100%; }

/* Autenticação ----------------------------------------------------------- */

.auth-layout { background: var(--hub-bg); min-height: 100dvh; }
.auth-page { background: var(--hub-bg); border: 0; box-shadow: none; display: grid; grid-template-columns: minmax(300px, 42%) minmax(420px, 1fr); min-height: 100dvh; }
.auth-brand { border-bottom: 1px solid var(--hub-line); padding-bottom: 1rem; }
.auth-hero__copy { margin: clamp(4rem, 12vh, 7rem) 0 0; max-width: 520px; }
/* O herói do login é a única voz que continua em 700 de propósito: é peça de
   marca, não cabeçalho de página — o piso de 600 não vale aqui. */
.auth-hero__copy p { color: var(--hub-dim); font-size: var(--fs-meta); margin: 1rem 0 0; max-width: 46ch; }
.auth-form__row { align-items: center; display: flex; gap: .75rem; justify-content: space-between; }
.auth-form__row > a { font-size: var(--fs-micro); text-decoration: none; }
.auth-link-list--single { text-align: center; }
.auth-secondary-access { margin-top: .25rem; }
.oauth-button-list { display: grid; gap: .5rem; }
.oauth-button { width: 100%; }
.auth-layout > section,
.auth-layout > div:not(.auth-page):not(#blazor-error-ui) { background: var(--hub-card); border: 1px solid var(--hub-line); box-shadow: none; color: var(--hub-body); }

/* A folha de sugestões do compositor — UMA peça para o feed e o mural.
   Os gatilhos ('/' comunidade, '@' jogador, '#' estabelecimento) falam a
   mesma gramática (HubComposerTriggers) nas duas telas, e a folha que os
   mostra também é uma só: eram duas cópias escopadas que já divergiam no
   vão. Cada linha é <strong>token</strong> + <span>nome legível</span>. */
.composer-suggestions {
    background: var(--hub-deep);
    border: 1px solid var(--hub-line-strong);
    display: grid;
    margin: 2px 0 10px;
    max-height: 220px;
    overflow-y: auto;
}

.composer-suggestions button {
    align-items: baseline;
    background: transparent;
    border: 0;
    border-bottom: 1px solid var(--hub-line-soft);
    color: var(--hub-body);
    cursor: pointer;
    display: flex;
    gap: 9px;
    padding: var(--btn-pad-md);
    text-align: left;
}

.composer-suggestions button:last-child { border-bottom: 0; }
.composer-suggestions button:hover { background: var(--hub-hover); }
.composer-suggestions strong { color: var(--hub-yellow); font: 500 var(--fs-sm) var(--hub-mono); }
.composer-suggestions span { color: var(--hub-dim); font-size: var(--fs-sm); }

/* Contrato único de publicação ------------------------------------------
   Feed, comunidade e perfis só fornecem dados e ações. A moldura, a ordem
   visual e a densidade pertencem a este contrato compartilhado. */

body .hub-shell .hub-content .social-post {
    background: var(--hub-card);
    border: 1px solid var(--hub-line);
    padding: 0;
    position: relative;

    /* CHEGAR PELA ANCORA SEM ENTRAR DEBAIXO DO CABECALHO. O `#post-{id}` leva o
       navegador a encostar o topo da publicacao no topo da area rolavel — e no
       celular os 54px de cabecalho ficam FIXOS por cima dela. Esta folga e o
       que faz a publicacao chegar inteira. */
    scroll-margin-top: 4.5rem;
}

/* A PUBLICACAO VESTE A FAIXA DA CASA (dono, 18/08/2026). Ela era VERMELHA, e
   o vermelho ficou sendo so o que nao tem volta — ver a regua no bloco do
   .hub-card. Numa tela de perfil desciam tres cores sem regra: cabecalho roxo,
   compositor azul, publicacoes vermelhas.

   A regra e daqui e nao da classe porque nem toda publicacao e um .hub-card: a
   do mural e a do perfil sao .social-post sem a classe da casa, e sem esta
   linha elas ficariam sem faixa nenhuma. */
body .hub-shell .hub-content .social-post::before {
    background: var(--hub-yellow);
    content: "";
    height: 3px;
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
}

body .hub-shell .hub-content .social-post__header {
    align-items: center;
    display: flex;
    gap: 12px;
    margin: 0;
    padding: 18px 20px 0;
    position: relative;
}

body .hub-shell .hub-content .social-post__avatar {
    align-items: center;
    color: var(--hub-on-accent);
    display: inline-flex;
    flex: 0 0 36px;
    font: 600 var(--fs-avatar-compact) var(--hub-mono);
    height: 36px;
    justify-content: center;
    width: 36px;
}

body .hub-shell .hub-content .social-post__avatar img { display: block; height: 100%; object-fit: cover; width: 100%; }
body .hub-shell .hub-content .hub-profile-link { color: inherit; text-decoration: none; }
body .hub-shell .hub-content .social-post__identity { flex: 1; min-width: 0; }
body .hub-shell .hub-content .social-post__identity-line { align-items: baseline; display: flex; flex-wrap: wrap; gap: 8px; }
body .hub-shell .hub-content .social-post__identity strong { color: var(--hub-title); font-size: var(--fs-lead); font-weight: 600; }
body .hub-shell .hub-content .social-post__handle { color: var(--hub-mute); font-size: var(--fs-sm); }

body .hub-shell .hub-content .social-post__follow {
    background: transparent;
    border: 1px solid var(--hub-line-strong);
    color: var(--hub-body);
    cursor: pointer;
    flex: 0 0 auto;
    font-size: var(--fs-sm);
    min-height: 30px;
    padding: .35rem .8rem;
}

body .hub-shell .hub-content .social-post__follow:hover,
body .hub-shell .hub-content .social-post__follow.is-following { border-color: var(--hub-yellow); color: var(--hub-yellow); }
body .hub-shell .hub-content .social-post__options { margin-left: auto; position: relative; }
body .hub-shell .hub-content .social-post__more { background: transparent; border: 0; color: var(--hub-mute); cursor: pointer; display: inline-flex; font-size: var(--fs-icon-md); padding: 0 4px; }
body .hub-shell .hub-content .social-post__more:hover { color: var(--hub-body); }

/* Só a ANCORAGEM fica aqui: a aparência é a da folha compartilhada acima. */
body .hub-shell .hub-content .social-post__menu {
    right: 18px;
    top: 46px;
}

body .hub-shell .hub-content .social-post__options .social-post__menu { right: 0; top: 32px; }

body .hub-shell .hub-content .social-post__review { align-items: center; color: var(--hub-body); display: flex; gap: 10px; margin: 0; padding: 14px 20px 0; text-decoration: none; }
body .hub-shell .hub-content .social-post__review span { color: var(--hub-yellow); font-size: var(--fs-lead); letter-spacing: var(--ls-label); }
body .hub-shell .hub-content .social-post__review strong { color: var(--hub-title); font-size: var(--fs-body); }
body .hub-shell .hub-content .social-post__review:hover strong { color: var(--hub-blue); }

body .hub-shell .hub-content .social-post__body {
    color: var(--hub-body);
    font-size: var(--fs-lead);
    line-height: var(--lh-body);
    margin: 0;
    padding: 16px 20px 2px;
    text-wrap: pretty;
    white-space: pre-line;
}

body .hub-shell .hub-content .social-post__destinations { margin: 0; padding: 0 20px 4px; }
body .hub-shell .hub-content .social-post .post-media-gallery { margin: .85rem 0; }

/* A ENQUETE ENTRA NA MESMA COLUNA DO TEXTO. Ela é um componente irmão do corpo
   da publicação e nasce sem recuo lateral nenhum; os 20px são os mesmos que o
   `.social-post__body` carrega por dentro. A regra existia SÓ na folha do feed
   — e por isso, no perfil, no perfil público e no mural, as opções da enquete
   começavam 20px à esquerda do texto que as apresenta. Vale para as quatro
   telas porque todas montam `.social-post`. */
body .hub-shell .hub-content .social-post .post-poll { margin: 0 20px 16px; }

body .hub-shell .hub-content .social-post__actions {
    align-items: center;
    border-top: 1px solid var(--hub-line-soft);
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin: 0;
    /* O recuo lateral e 20px menos os .6rem que o proprio botao ja tem, para o
       rotulo cair na mesma vertical do texto da publicacao. */
    padding: 7px 10.4px 11px;
}

/* ACAO E TEXTO, NAO BOTAO.
   Tres caixas com borda logo abaixo de cada publicacao pesavam mais do que o
   proprio conteudo. Aqui vale o mesmo tratamento das acoes do comentario
   (Responder, Fixar, Dar coracao): texto puro, que so acende ao ser tocado.
   O alvo de toque nao encolhe junto — os 34px de altura continuam, e sao eles
   que garantem o dedo mesmo sem borda para enxergar. */
body .hub-shell .hub-content .social-post__action {
    align-items: center;
    background: transparent;
    border: 0;
    color: var(--hub-dim);
    cursor: pointer;
    display: inline-flex;
    flex: none;
    font-size: var(--fs-meta);
    gap: 5px;
    justify-content: center;
    padding: var(--btn-pad-sm);
    text-decoration: none;
    white-space: nowrap;
}

/* Rotulo de interface na fonte do corpo; numero em mono, que e o papel dele.
   Os dois no mesmo degrau — um numero maior que a palavra ao lado era o que
   fazia "Curtir 0" parecer duas coisas coladas em vez de uma acao. */
body .hub-shell .hub-content .social-post__action span { font: 400 var(--fs-meta) var(--hub-font); }
body .hub-shell .hub-content .social-post__action strong { color: var(--hub-mute); font: 500 var(--fs-meta) var(--hub-mono); }
body .hub-shell .hub-content .social-post__action:hover,
body .hub-shell .hub-content .social-post__action.is-active { color: var(--hub-yellow); }
body .hub-shell .hub-content .social-post__action.is-active strong { color: var(--hub-yellow); }

/* AS REACOES ENTRAM NA FILEIRA COM O MESMO RECUO EM TODA TELA.
   A fileira desconta 9,6px porque o botao de texto ao lado carrega esse
   respiro por dentro, e o selo, que tem borda propria, nao carrega — sem isto
   ele nasce a esquerda da margem do corpo da publicacao. A regra e daqui e nao
   do CSS de cada tela: as cinco escreveram a sua, e uma delas com outra
   propriedade. */
body .hub-shell .hub-content .social-post__actions > .hub-reactions,
body .hub-shell .hub-content .feed-post__actions > .hub-reactions,
body .hub-shell .hub-content .profile-post > footer > .hub-reactions,
body .hub-shell .hub-content .public-profile-post > footer > .hub-reactions { margin-left: .6rem; }
body .hub-shell .hub-content .social-post__action--dislike:hover { color: var(--hub-red); }

body .hub-shell .hub-content .social-post__comments {
    background: var(--hub-row-hover);
    border-top: 1px solid var(--hub-line-strong);
    display: grid;
    gap: 10px;
    margin: 0;
    padding: 14px 20px;
}

@media (max-width: 720px) {
    body .hub-shell .hub-content .social-post {
        border: 0;
        border-bottom: 1px solid var(--hub-line-soft);
    }

    body .hub-shell .hub-content .social-post::before { display: none; }

    /* SEM FAIXA COLORIDA NO CELULAR (regra do dono). A publicação já abria mão
       da dela aqui — a linha acima é de 15/08 —, e os cartões de peça
       (`.hub-card--*`) continuavam com a sua: cabeçalho de perfil roxo,
       compositor azul, "responder tópico" vermelho. Numa coluna de 412px, em
       que o cartão perde a moldura e vira a própria tela, a faixa deixa de
       marcar um cartão e vira um risco solto no alto do conteúdo.

       DIÁLOGO É EXCEÇÃO, e não esquecimento (dono, 18/08/2026): ele flutua
       sobre a tela, com moldura e fundo próprios, e ali a faixa continua sendo
       o que ela sempre foi — o tom do que está sendo decidido. Foi a denúncia
       que denunciou: sem a faixa vermelha, o cartão de "mandar para análise"
       ficava com a mesma cara de um cartão qualquer. */
    body .hub-shell .hub-content .hub-card:not([role="dialog"]):not([role="alertdialog"])::before { display: none; }
    body .hub-shell .hub-content .social-post__header { gap: 10px; padding: 16px 16px 0; }
    body .hub-shell .hub-content .social-post__handle { display: none; }
    body .hub-shell .hub-content .social-post__identity strong { font-size: var(--fs-lead); }
    body .hub-shell .hub-content .social-post__follow { font-size: var(--fs-sm); padding-inline: .6rem; }
    body .hub-shell .hub-content .social-post__body { font-size: var(--fs-lead); line-height: var(--lh-body); padding: 12px 16px 2px; }
    body .hub-shell .hub-content .social-post__review { align-items: flex-start; flex-direction: column; gap: 4px; padding: 12px 16px 0; }
    body .hub-shell .hub-content .social-post__destinations { padding: 0 16px 2px; }
    body .hub-shell .hub-content .social-post .post-media-gallery { margin: .85rem 0; }
    body .hub-shell .hub-content .social-post .hub-gif-card { margin: 0 16px 12px; }
    body .hub-shell .hub-content .social-post__actions { border-top: 0; padding: 2px 6.4px 10px; }
    body .hub-shell .hub-content .social-post__comments { padding-inline: 16px; }
}

/* FORUM · a linha da categoria e os selos de estado.
   Compartilhados pelo cartao do topico (mural e indice do forum) e pela
   pagina do topico aberto, que sao a mesma peca em telas diferentes. Os
   degraus sao os de .hub-post-breadcrumbs, a linha que a publicacao usa. */
/* NUMERO NAO E ACAO — a linha de contagem do topico (dono, 17/08/2026).

   "Respostas", "Comentarios" e "Leituras" moravam na FILEIRA DE ACOES, com a
   mesma classe de "Exibir" e "Compartilhar": pareciam botoes, nao respondiam
   ao clique, e a tela dava a impressao de ter travado. Sao DADO, e dado se le
   como metadado — mono, apagado, numa linha propria logo abaixo da categoria.

   Estava so no CSS da pagina do topico. Subiu porque o cartao do forum, do
   feed e do mural passou a usar a mesma linha: e a mesma frase nos dois
   lugares, e ler diferente era o que fazia o cartao parecer outra coisa. */
.forum-thread-stats {
    color: var(--hub-dim);
    display: flex;
    flex-wrap: wrap;
    font: 500 var(--fs-meta)/var(--lh-tight) var(--hub-mono);
    gap: 1.1rem;
    padding: 2px 20px 0;
}

@media (max-width: 760px) {
    .forum-thread-stats { padding: 2px 16px 0; }
}

.forum-topic-preview__meta {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
}

.forum-topic-preview__meta > span { color: var(--hub-dim); font-size: var(--fs-sm); }
.forum-topic-preview__meta a { color: var(--hub-blue); font: 600 var(--fs-sm) var(--hub-mono); text-decoration: none; }

.forum-topic-preview__category {
    color: var(--hub-purple);
    font: 600 var(--fs-sm) var(--hub-mono);
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
}

.forum-topic-preview__category[data-category="question"],
.forum-topic-preview__category[data-category="event"] { color: var(--hub-yellow); }
.forum-topic-preview__category[data-category="guide"],
.forum-topic-preview__category[data-category="showcase"] { color: var(--hub-red); }

.forum-topic-preview__flags { display: flex; flex-wrap: wrap; gap: .35rem; margin-bottom: .35rem; }
.forum-topic-preview__flags span { border: 1px solid var(--hub-line-strong); color: var(--hub-yellow); font: var(--fs-micro) var(--hub-mono); padding: .08rem .3rem; }

/* Estados globais -------------------------------------------------------- */

.hub-system-page, .hub-not-found-page {
    align-items: center;
    display: flex;
    justify-content: center;
    min-height: min(680px, calc(100dvh - 8rem));
    padding: clamp(1rem, 3vw, 2.5rem) 0;
}

.hub-system-panel, .hub-not-found-panel {
    background: var(--hub-card);
    border: 1px solid var(--hub-line-strong);
    color: var(--hub-body);
    max-width: 46rem;
    width: min(100%, 46rem);
}

.hub-system-hazard, .hub-not-found-hazard { background: var(--hub-red); height: 4px; }
.hub-system-panel__body, .hub-not-found-panel__body { display: flex; flex-direction: column; gap: 1rem; padding: clamp(1.35rem, 4vw, 2.4rem); }
.hub-system-signal, .hub-not-found-code {
    align-items: center;
    background: var(--hub-deep);
    border: 1px solid var(--hub-line-strong);
    display: flex;
    height: 54px;
    justify-content: center;
    width: 92px;
}
.hub-system-signal { gap: .35rem; }
.hub-system-signal i { background: var(--hub-red); height: 9px; width: 9px; }
.hub-system-signal i:nth-child(2) { background: var(--hub-yellow); }
.hub-system-signal i:nth-child(3) { background: var(--hub-purple); }
.hub-not-found-code { color: var(--hub-yellow); font-size: var(--fs-h2); font-weight: 700; }
.hub-system-kicker, .hub-not-found-kicker { color: var(--hub-red); font-size: var(--fs-micro); font-weight: 700; letter-spacing: var(--ls-label); }
.hub-system-panel h1, .hub-not-found-panel h1 { color: var(--hub-title); font-size: var(--fs-display); line-height: var(--lh-tight); margin: 0; }
.hub-system-panel p, .hub-not-found-panel p { color: var(--hub-dim); font-size: var(--fs-meta); line-height: var(--lh-body); margin: 0; max-width: 68ch; }
.hub-system-diagnostic { background: var(--hub-deep); border: 1px solid var(--hub-line); margin: .25rem 0 0; padding: 1rem; }
.hub-system-diagnostic dt { color: var(--hub-red); font-size: var(--fs-nano); letter-spacing: var(--ls-label); margin-bottom: .45rem; }
.hub-system-diagnostic dd { margin: 0; overflow-wrap: anywhere; }
.hub-system-diagnostic code { color: var(--hub-body); font: inherit; font-size: var(--fs-micro); }

/* Operações de conta ----------------------------------------------------- */

.account-inline-form { display: inline-block; }
.nav { display: flex; list-style: none; margin: 0; padding: 0; }
.nav-item { list-style: none; }
.nav-pills { gap: .25rem; }
.flex-column { flex-direction: column; }
.nav-link { border-left: 3px solid transparent; color: var(--hub-dim); display: block; font-size: var(--fs-micro); padding: .55rem .65rem; text-decoration: none; }
.nav-link:hover, .nav-link.active { background: var(--hub-hover); color: var(--hub-title); }
.nav-link.active { border-left-color: var(--hub-yellow); }
.nav-pills .nav-link,
.nav-pills .nav-link:hover,
.nav-pills .nav-link.active { background: transparent; border: 0; border-left: 3px solid transparent; box-shadow: none; color: var(--hub-dim); }
.nav-pills .nav-link:hover { background: var(--hub-hover); color: var(--hub-title); }
.nav-pills .nav-link.active { background: var(--hub-hover); border-left-color: var(--hub-yellow); color: var(--hub-title); }
.row { display: flex; flex-wrap: wrap; margin: 0 -.5rem; }
.col-md-4, .col-md-6, .col-md-12, .col-xl-6 { min-width: 0; padding: 0 .5rem; width: 100%; }
.col-md-4 { width: 33.333%; }
.col-md-6, .col-xl-6 { width: 50%; }
.table { border-collapse: collapse; color: var(--hub-body); font-size: var(--fs-micro); width: 100%; }
.table th, .table td { border-bottom: 1px solid var(--hub-line-soft); padding: .55rem; text-align: left; }
.list { display: grid; gap: .5rem; list-style: none; margin: 0; padding: 0; }
.recovery-code { background: var(--hub-deep); border: 1px solid var(--hub-line); color: var(--hub-yellow); display: inline-block; font-size: var(--fs-meta); padding: .4rem .5rem; }
/* Larga e legivel: esta lista aparece uma vez so, e e para ser copiada agora. */
.recovery-code-grid { display: grid; gap: 6px; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
.recovery-code-grid .recovery-code { font: 600 var(--fs-body) var(--hub-mono); letter-spacing: var(--ls-label); text-align: center; -webkit-user-select: all; user-select: all; }
/* O botao de copiar e mais um item da grade, de proposito: ele fica ao lado do
   ultimo codigo, que e onde a mao ja esta. `align-self: stretch` casa a altura
   dele com a das celulas — botao mais baixo abriria um degrau na fileira. */
.recovery-code-grid .recovery-code-copy { align-self: stretch; }
.text-success { color: var(--hub-green); }
.font-weight-bold { font-weight: 700; }
.form-horizontal { display: grid; gap: .8rem; }
.glyphicon { display: inline-block; font-style: normal; }
.glyphicon-warning-sign::before { color: var(--hub-red); content: "!"; font-weight: 700; }
.input-group { display: flex; }
.input-group > .form-control { flex: 1; min-width: 0; }
.input-group-text { align-items: center; background: var(--hub-deep); border: 1px solid var(--hub-line-strong); display: flex; padding: .5rem; }
.input-group-append { display: flex; }
.mb-3 { margin-bottom: 1rem; }
.h-100 { height: 100%; }

/* Responsive ------------------------------------------------------------- */

@media (max-width: 1100px) {
    .community-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
    .hub-shell { display: grid; grid-template-columns: 1fr; grid-template-rows: 54px minmax(0, 1fr); height: 100dvh; min-height: 0; overflow: hidden; }
    .app-topbar { gap: 1rem; grid-column: 1; grid-row: 1; grid-template-columns: minmax(0, 1fr) auto; height: 54px; padding-inline: 16px; }
    .topbar-brand { font-size: var(--fs-sm); gap: 8px; }
    .topbar-brand img { height: 24px; width: 24px; }
    .app-topbar > .topbar-search { display: none; }
    .app-topbar > .topbar-actions { grid-column: 2; }
    .app-nav-search { display: block; padding: .2rem .75rem .7rem; }
    .app-nav-search .topbar-search input { min-height: 44px; }
    /* A MOLDURA DE FORA NO CELULAR. Quem dá o título aqui é o MobilePageHeader
       de cada página, e ele é FIXO no alto: duas barras disputariam a mesma
       faixa. A fita desce para debaixo dele e vira o fio de baixo daquela
       barra — no fluxo ela era o primeiro elemento da moldura e ficava
       inteiramente escondida atrás do cabeçalho. São 6px que cabem na folga
       entre a barra e o conteúdo, sem empurrar nada; o z-index passa o 60 do
       cabeçalho pelo mesmo motivo. */
    .public-topbar { display: none; }
    .public-color-strip { left: 0; position: fixed; right: 0; top: 54px; z-index: 61; }
    .public-main { padding: 1rem 1rem 2rem; }
    .public-footer { padding: 1.25rem 1rem calc(1.25rem + env(safe-area-inset-bottom)); }
    .public-footer__inner { justify-content: center; text-align: center; }
    .public-footer__links { justify-content: center; }
    /* A chave de tema tem uma casa por tamanho de tela, como no aplicativo. */
    .public-footer__theme { display: inline-flex; }

    /* Aqui a topbar nao existe, entao o menu e a unica casa da chave de tema. */
    .app-nav-theme { display: flex; }
    /* E o envelope ja e um bloco da fita: o flutuante seria o mesmo destino
       duas vezes, ainda por cima tapando a barra de baixo. */
    .messages-dock { display: none; }
    /* A reserva da barra vale para os DOIS jeitos de chegar ao fim da pagina:
       `padding` para quem rola com o dedo, `scroll-padding` para quando quem
       rola e o codigo — `scrollIntoView` depois de publicar um comentario,
       um salto de âncora. Sem a segunda, o alvo encosta na borda de baixo da
       moldura, que no celular fica embaixo da barra colorida. */
    .hub-content { grid-column: 1; grid-row: 2; overflow: auto; padding: 1rem 1rem var(--hub-nav-reserve); scroll-padding-bottom: var(--hub-nav-reserve); }
    .hub-shell--page-mobile-header { grid-template-rows: minmax(0, 1fr); }
    .hub-shell--page-mobile-header .app-topbar { display: none; }
    .hub-shell--page-mobile-header .hub-content { grid-row: 1; }
    /* `auto`, e não `hidden`: quem matou a rolagem parasita foi o padding-bottom
       zerado, e em retrato o conteúdo cabe — nada rola, fica idêntico. Com
       `hidden`, no celular DEITADO o piso de 520px do mapa não cabia nos ~348px
       da tela e os 130px de baixo (onde ficam "Ver perfil" e "Como chegar" da
       ficha) eram recortados sem nenhuma forma de alcançá-los. */
    .hub-shell--map .hub-content {
        overflow: auto;
        padding-bottom: 0;
    }
    .app-nav-bar {
        background: var(--hub-deep);
        border-top: 1px solid var(--hub-line);
        bottom: 0;
        display: grid;
        grid-template-columns: repeat(6, minmax(0, 1fr));
        left: 0;
        padding-bottom: env(safe-area-inset-bottom);
        position: fixed;
        right: 0;
        z-index: 30;
    }
    .app-nav-bar--commercial { grid-template-columns: repeat(5, minmax(0, 1fr)); }
    .app-nav-bar__item { align-items: center; display: flex; justify-content: center; min-height: 42px; text-decoration: none; }
    .map-layout { grid-template-columns: 1fr; }
    .auth-page { align-content: start; grid-template-columns: 1fr; }
    .auth-hero__copy { margin: 1.75rem 0 0; }
}

@media (max-width: 680px) {
    .player-info { display: none; }
    .page-header { align-items: start; flex-direction: column; min-height: 0; }
    .header-actions { justify-content: flex-start; }
    .community-grid,
.form-grid { grid-template-columns: 1fr; }
    .record-row, .statement-row { align-items: start; grid-template-columns: 1fr auto; }
    .record-row small, .statement-row > small { grid-column: 1 / -1; }
    .col-md-4, .col-md-6, .col-xl-6 { width: 100%; }
    .map-canvas { min-height: 360px; }
    .hub-content { padding: 0 0 var(--hub-nav-reserve); }
    .hub-content__inner { gap: 0; max-width: none; width: 100%; }

    /* A CONVERSA NO CELULAR OCUPA A ALTURA, COMO O MAPA.
       Sem isto quem rola é a página: o cabeçalho da conversa — retrato, nome e o
       `···` das ações — sobe junto com os balões e some depois das primeiras
       mensagens. A receita é a do mapa: a coluna fecha em altura e o filho
       decide quem rola por dentro. */
    /* A COLUNA DE MENSAGENS RESERVA SÓ A BARRA (dono, 18/08/2026). O
       `--hub-nav-reserve` guarda a altura da barra MAIS um respiro de 2,25rem,
       que existe para o conteúdo que rola não terminar colado nela. Aqui
       embaixo não há conteúdo rolando: há o campo de buscar, que é peça fixa —
       e o respiro virava um vão de 36px entre ele e a barra. */
    .hub-shell--messages .hub-content {
        overflow: hidden;
        padding-bottom: calc(var(--hub-nav-h) + env(safe-area-inset-bottom));
    }

    .hub-shell--messages .hub-content__inner { display: flex; flex-direction: column; height: 100%; min-height: 0; }
}

@media (max-width: 440px) {
    .app-topbar { padding-inline: .75rem; }
    .auth-brand { border-bottom: 0; padding-bottom: 0; }
    .auth-hero__copy { display: none; }
    .comment-form { grid-template-columns: 1fr; }
}

/* ATIVIDADE E NOTIFICAÇÕES COMPARTILHAM ESTE LAYOUT.
   São duas telas com endereços próprios (/activity e /notifications) e o
   mesmo desenho; as regras moram aqui, e não no CSS isolado de uma delas,
   para que o visual de uma não mude sem a outra. */
.activity-page { display: grid; gap: 1.25rem; width: 100%; }
/* O CORO P2 MORREU AQUI (15/08/2026): as nove classes {tela}-heading que
   diziam "titulo 600 + subtitulo apagado" com nove nomes viraram a peca unica
   <PageHeader> (.hub-page-heading, no bloco de cabecalhos). Nao recrie uma
   classe de cabecalho por tela. */
.activity-filters button,
.activity-item > button,
.activity-load-more { background: transparent; border: 1px solid var(--hub-line-strong); color: var(--hub-dim); cursor: pointer; font-size: var(--fs-sm); padding: var(--btn-pad-md); }
.activity-filters button:hover,
.activity-item > button:hover,
.activity-load-more:hover { border-color: var(--hub-yellow); color: var(--hub-yellow); }
.activity-filters { display: flex; gap: .5rem; overflow-x: auto; }
.activity-filters button { flex: 0 0 auto; }
.activity-filters button.is-active { background: var(--hub-card); border-color: var(--hub-yellow); color: var(--hub-yellow); }
.activity-list { display: grid; gap: 1rem; }
.activity-approvals { display: grid; gap: .5rem; }
.activity-approvals > h2 { color: var(--hub-yellow); font: 500 var(--fs-micro) var(--hub-mono); letter-spacing: var(--ls-caps-wide); margin: .35rem 0; }
.activity-day { display: grid; gap: .5rem; }
.activity-day h2 { color: var(--hub-mute); font: 500 var(--fs-micro) var(--hub-mono); letter-spacing: var(--ls-caps-wide); margin: .35rem 0; }
.activity-item { align-items: center; background: var(--hub-card); border: 1px solid var(--hub-line); display: grid; gap: .8rem; grid-template-columns: auto minmax(0, 1fr) auto; padding: .9rem; }
.activity-item-actions { align-items: center; display: flex; flex-wrap: wrap; gap: .45rem; justify-content: flex-end; }
.activity-item-actions button { background: transparent; border: 1px solid var(--hub-line-strong); color: var(--hub-dim); cursor: pointer; font-size: var(--fs-sm); padding: var(--btn-pad-md); }
.activity-item-actions button:hover { border-color: var(--hub-yellow); color: var(--hub-yellow); }
.activity-item-actions button.is-accept { border-color: var(--hub-yellow); color: var(--hub-yellow); }
.activity-item-actions button.is-reject { border-color: var(--hub-red); color: var(--hub-red); }
.activity-item-actions button:disabled { cursor: wait; opacity: .55; }
.activity-item.is-unread { border-left: 3px solid var(--hub-yellow); }

/* O CARTAO COMPACTO — retrato, duas linhas e a acao NA MESMA FILEIRA.
   Este desenho nasceu dentro das folhas da barra de navegacao e so existia la,
   em CSS isolado: as paginas de avisos e de atividade mostravam a mesma
   informacao em cartoes o dobro mais altos, e no celular a acao ainda caia para
   uma segunda linha. Virou modificador da casa para que "lista de avisos" tenha
   UM desenho, e nao um por tela.

   A dupla `.activity-item.activity-item--compact` nao e enfeite: a regra do
   celula la embaixo redeclara `.activity-item` em duas colunas e prende a acao
   na coluna 2. Com uma classe so, quem vencesse dependeria da ORDEM no arquivo —
   com duas, o compacto vence sempre, esteja onde estiver. */
.activity-item.activity-item--compact {
    align-items: center;
    gap: .6rem;
    grid-template-columns: auto minmax(0, 1fr) auto;
    padding: .55rem .65rem;
}

.activity-item--compact .activity-symbol { font-size: var(--fs-sm); height: 28px; width: 28px; }
.activity-item--compact .activity-content p { margin: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* NOME E @ ABREVIAM JUNTOS (dono, 22/08/2026).

   So o `strong` tinha corte, entao o nome virava "Matheus Uener Sil..." e o @
   logo ao lado QUEBRAVA A LINHA, empurrando o cartao para tres linhas e
   desalinhando a acao da direita. Meia regra e o pior dos dois mundos: parece
   deliberado no nome e parece defeito no @.

   `flex: 0 1 auto` nos dois com `min-width: 0` e o que permite ao navegador
   encolher os dois; sem o `min-width`, item de flex recusa ficar menor que o
   proprio conteudo e o corte nunca acontece. */
.activity-item--compact .activity-title-line { flex-wrap: nowrap; min-width: 0; }
.activity-item--compact .activity-title-line strong,
.activity-item--compact .activity-title-line span {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Tanto faz se a acao e link ou botao: "Abrir" leva a algum lugar, "Ativar"
   grava uma escolha, e as duas sao a mesma peca no desenho. */
.activity-item.activity-item--compact > .activity-item-actions,
.activity-item.activity-item--compact > a,
.activity-item.activity-item--compact > button { grid-column: auto; justify-self: end; }

.activity-item--compact .activity-item-actions { justify-content: flex-end; }
.activity-item--compact .activity-item-actions a,
.activity-item--compact .activity-item-actions button,
.activity-item--compact > a,
.activity-item--compact > button {
    background: transparent;
    border: 1px solid var(--hub-line-strong);
    color: var(--hub-dim);
    cursor: pointer;
    font-family: var(--hub-font);
    font-size: var(--fs-meta);
    padding: var(--btn-pad-sm);
    text-decoration: none;
    white-space: nowrap;
}

.activity-item--compact .activity-item-actions a:hover,
.activity-item--compact .activity-item-actions a:focus-visible,
.activity-item--compact .activity-item-actions button:hover,
.activity-item--compact .activity-item-actions button:focus-visible,
.activity-item--compact > a:hover,
.activity-item--compact > a:focus-visible,
.activity-item--compact > button:hover,
.activity-item--compact > button:focus-visible {
    border-color: var(--hub-yellow);
    color: var(--hub-yellow);
    outline: 0;
}

/* O DIALOGO DE DECISAO — o mesmo em toda tela que pergunta antes de agir.
   Nasceu como `.feed-modal` dentro do CSS isolado do feed, e por isso a mesma
   pergunta ("mandar isto para analise?") tinha uma caixa no feed e outra na
   conversa: uma descia do centro, a outra ficava presa la, e nenhuma das duas
   virava folha no celular. Aqui e uma peca so.

   NO CELULAR ELE SOBE DO RODAPE. Caixa centrada em tela alta deixa o polegar
   longe dos botoes; folha encostada embaixo cai onde a mao ja esta. */
.hub-modal-backdrop {
    align-items: center;
    background: var(--hub-veil);
    display: flex;
    inset: 0;
    justify-content: center;
    padding: 20px;
    position: fixed;
    z-index: 100;
}

.hub-modal { display: grid; gap: 10px; max-height: min(88dvh, 720px); max-width: 440px; overflow-y: auto; padding: 24px; width: 100%; }
.hub-modal h2 { color: var(--hub-title); font-size: var(--fs-h3); margin: 0; }
.hub-modal > p { color: var(--hub-dim); font-size: var(--fs-body); line-height: var(--lh-body); margin: 0 0 8px; }
.hub-modal__actions { display: flex; flex-wrap: wrap; gap: .6rem; justify-content: flex-end; margin-top: .4rem; }
.hub-modal__comment { background: var(--hub-deep); border: 1px solid var(--hub-line-strong); color: var(--hub-body); font: var(--fs-body) var(--hub-font); min-height: 70px; padding: .55rem; resize: vertical; width: 100%; }
.hub-modal__label { color: var(--hub-dim); font: 500 var(--fs-meta)/var(--lh-tight) var(--hub-mono); letter-spacing: var(--ls-label); text-transform: uppercase; }

/* AS DUAS SAIDAS DE UM DIALOGO DE ESCOLHA — titulo em cima, explicacao embaixo,
   e a moldura amarela em quem esta escolhido. Nasceu como `.feed-dislike-choice`
   e tinha gemeas em duas folhas de tela (`.dislike-option` e
   `.public-dislike-option`), que era o que fazia o mesmo dialogo aparecer com
   tres caras. `::deep` porque a lista de motivos e um componente filho, e o
   atributo de escopo nao atravessa. */
.hub-modal__choice { background: transparent; border: 1px solid var(--hub-line-strong); color: var(--hub-dim); cursor: pointer; display: grid; gap: 3px; padding: 14px; text-align: left; }
.hub-modal__choice.is-selected { background: var(--hub-hover); border-color: var(--hub-yellow); }

/* A ESCOLHA EMPRESTA O TOM DO CARTÃO (dono, 18/08/2026). Amarelo é a cor de
   AÇÃO no app, e no diálogo de denúncia ele contradizia a faixa vermelha logo
   acima: a superfície dizia "isto é grave" e a opção escolhida dizia "isto é
   só mais um botão". Onde o cartão é vermelho, a escolha é vermelha. */
.hub-card--red .hub-modal__choice.is-selected { border-color: var(--hub-red); }
.hub-card--red .hub-reason.is-selected { border-left-color: var(--hub-red); }
.hub-card--red .hub-reason:focus-visible { outline-color: var(--hub-red); }
.hub-modal__choice strong { color: var(--hub-title); font-size: var(--fs-lead); }
.hub-modal__choice span { color: var(--hub-dim); font-size: var(--fs-body); }
.hub-modal__choice .hub-reasons,
.hub-modal__choice .hub-modal__comment { margin-top: 9px; }

/* ESCOLHER MOTIVO E UMA LISTA A MOSTRA, e nao um `<select>`: o campo nativo
   abre a roda do sistema operacional — cinza, arredondada, com a fonte do
   aparelho — e no meio de um dialogo escrito a mao ele e a unica peca que
   parece de outro aplicativo. Com um item escolhido, ele ainda esconde os
   outros. */
.hub-reasons { border: 1px solid var(--hub-line-strong); display: grid; }
.hub-reasons + .hub-reasons { margin-top: .4rem; }

.hub-reason {
    background: var(--hub-deep);
    border: 0;
    border-bottom: 1px solid var(--hub-line);
    /* A faixa existe SEMPRE, transparente ate a escolha: com ela aparecendo so
       na selecionada, a linha andava 3px para o lado a cada toque. */
    border-left: 3px solid transparent;
    color: var(--hub-body);
    cursor: pointer;
    font-size: var(--fs-body);
    padding: .6rem .7rem;
    text-align: left;
}

.hub-reason:last-child { border-bottom: 0; }
.hub-reason:hover { background: var(--hub-hover); color: var(--hub-title); }
.hub-reason:focus-visible { outline: 1px solid var(--hub-yellow); outline-offset: -1px; }
.hub-reason.is-selected { background: var(--hub-card); border-left-color: var(--hub-yellow); color: var(--hub-title); font-weight: 600; }
.hub-reason:disabled { cursor: not-allowed; opacity: .5; }

@media (max-width: 560px) {
    .hub-modal-backdrop { align-items: end; padding: 0; }
    .hub-modal { border-inline: 0; max-height: 92dvh; max-width: none; }
}

/* OS TRES QUADRADINHOS VERDES — o mesmo desenho que aparece quando a conexao
   cai e o app tenta voltar. Ele morava so no aviso de reconexao, em CSS isolado
   daquele componente; virou peca da casa para que "carregando" tenha UMA cara em
   todo lugar, e nao uma por tela. */
.hub-pixels { align-items: center; display: inline-flex; gap: 3px; }

.hub-pixels i {
    animation: hub-pixels-blink 900ms steps(2, end) infinite;
    background: var(--hub-green);
    display: block;
    height: 9px;
    width: 9px;
}

.hub-pixels i:nth-child(2) { animation-delay: 150ms; }
.hub-pixels i:nth-child(3) { animation-delay: 300ms; }

/* AS REAÇÕES — os selos do que existe, e o gatilho que abre a paleta.
   Peça da casa porque o mesmo gesto vale na publicação, no comentário e na
   mensagem: antes eram dois jeitos, e o do comentário mostrava seis botões com
   quatro zeros embaixo de quem nunca reagiu. */
.hub-reactions { align-items: center; display: flex; flex-wrap: wrap; gap: .3rem; }

.hub-reactions__badge,
.hub-reactions__trigger {
    align-items: center;
    background: transparent;
    border: 1px solid var(--hub-line);
    color: var(--hub-dim);
    cursor: pointer;
    display: inline-flex;
    font-size: var(--fs-sm);
    gap: .25rem;
    justify-content: center;
    min-height: 28px;
    padding: .15rem .4rem;
}

.hub-reactions__badge span { font: var(--fs-micro) var(--hub-mono); }
.hub-reactions__trigger { color: var(--hub-mute); min-width: 30px; }

.hub-reactions__badge:hover,
.hub-reactions__trigger:hover,
.hub-reactions__badge.is-mine,
.hub-reactions__trigger.is-mine {
    background: var(--hub-hover);
    border-color: var(--hub-yellow);
    color: var(--hub-yellow);
}

.hub-reactions__badge:disabled,
.hub-reactions__trigger:disabled { cursor: wait; opacity: .55; }

.hub-reactions__picker { position: relative; }

/* O VÉU FECHA A PALETA AO TOCAR FORA. Sem ele, abrir a paleta e rolar a tela
   deixava um retângulo flutuando sobre outra publicação. */
.hub-reactions__veil { inset: 0; position: fixed; z-index: 40; }

.hub-reactions__palette {
    background: var(--hub-card);
    border: 1px solid var(--hub-line-strong);
    bottom: calc(100% + 4px);
    display: grid;
    gap: 2px;
    grid-template-columns: repeat(6, 1fr);
    left: 0;
    /* ELA NASCE NA ESQUERDA DO GATILHO E CRESCE PARA A DIREITA, sempre. Chegou
       a ser ancorada à direita no celular, para não vazar da tela — e vazava
       pelo outro lado, porque o gatilho fica na ESQUERDA da fileira de ações: a
       paleta saía para fora da margem esquerda e não dava para tocar nela. O
       teto de largura é o que a segura dentro da tela. */
    max-width: calc(100vw - 2rem);
    padding: 4px;
    position: absolute;
    z-index: 41;
}

.hub-reactions__palette button {
    background: transparent;
    border: 0;
    cursor: pointer;
    font-size: var(--fs-lead);
    line-height: var(--lh-tight);
    padding: .3rem;
}

.hub-reactions__palette button:hover,
.hub-reactions__palette button.is-mine { background: var(--hub-hover); }

/* Numa resposta de comentário, tudo um degrau menor. */
.hub-reactions--compact .hub-reactions__badge,
.hub-reactions--compact .hub-reactions__trigger { font-size: var(--fs-meta); min-height: 24px; }

/* Um degrau menor, para caber dentro de um botao da barra. */
.hub-pixels--sm i { height: 6px; width: 6px; }

/* Um degrau maior, para o desenho segurar uma tela inteira sozinho: a 9px ele
   sumia no meio de uma pagina vazia. */
.hub-pixels--lg { gap: 5px; }
.hub-pixels--lg i { height: 13px; width: 13px; }

@keyframes hub-pixels-blink {
    0%, 30% { opacity: .25; }
    31%, 100% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .hub-pixels i { animation: none; opacity: 1; }
}

/* A ESPERA DE UMA TELA INTEIRA — o desenho centralizado, com legenda.

   O PISO NAO E RESERVA DE ESPACO, e seria mentira dizer que é: o que chega no
   lugar tem a altura que tiver — um feed inteiro numa tela, um aviso de quatro
   dedos noutra. O piso existe para o desenho ter corpo quando ele está SOZINHO
   numa página em branco, que é o caso do feed, do perfil e da autorização do
   estabelecimento. Onde o que chega é curto — a busca, que alterna entre três
   avisos de uma linha —, a tela baixa o piso pelo `--hub-loading-h` em vez de
   empurrar o resto para baixo e puxá-lo de volta meio segundo depois.

   O rótulo é mono, caixa alta e miúdo: ele é legenda do desenho, não um
   parágrafo. */
.hub-loading {
    align-content: center;
    display: grid;
    gap: .85rem;
    justify-items: center;
    min-height: var(--hub-loading-h, 150px);
    padding: 2rem 1rem;
    text-align: center;
}

.hub-loading__label {
    color: var(--hub-dim);
    font: 500 var(--fs-meta)/var(--lh-tight) var(--hub-mono);
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
}

/* Numa linha só, para dentro de um cartão ou ao lado de um campo. */
.hub-loading--inline {
    align-items: center;
    display: inline-flex;
    gap: .5rem;
    min-height: 0;
    padding: 0;
    text-align: left;
}

/* O TAMANHO DOS DESENHOS DA CASA (`<HubIcon />`). Fica aqui, e nao no CSS
   isolado de cada tela, por um motivo mecanico: o `<svg>` sai de OUTRO
   componente e nao carrega o atributo de escopo de quem o chamou — uma regra
   isolada so o alcancaria com `::deep`, repetido em toda tela que usa icone.
   Como classe global, o tamanho e um so e ninguem precisa saber disso.
   `currentColor` e o que faz o desenho mudar de tom junto com o botao. */
.hub-icon { fill: currentColor; flex: 0 0 auto; height: 20px; width: 20px; }
.hub-icon--sm { height: 16px; width: 16px; }
.hub-icon--lg { height: 24px; width: 24px; }

.activity-symbol { align-items: center; color: var(--hub-on-accent); display: flex; font: 600 var(--fs-body) var(--hub-mono); height: 34px; justify-content: center; width: 34px; }
.activity-symbol.is-blue { background: var(--hub-blue); }
.activity-symbol.is-red { background: var(--hub-red); }
.activity-symbol.is-yellow { background: var(--hub-yellow); }
.activity-symbol.is-purple { background: var(--hub-purple); }
.activity-symbol.is-green { background: var(--hub-green); }
/* QUANDO HA FOTO, ELA OCUPA O QUADRADO INTEIRO — a inicial e o que aparece na
   falta dela, e nao o contrario. Declarado aqui, junto do quadrado, para nao
   virar a mesma regra repetida em cada lista que resolver mostrar retrato. */
.activity-symbol img { display: block; height: 100%; object-fit: cover; width: 100%; }

/* O MESMO SIMBOLO, UM DEGRAU ABAIXO. Onde a linha e item de leitura rapida —
   barra lateral do perfil, listas de afinidade — e nao o assunto da tela. Os
   tons continuam sendo os de cima: e o mesmo quadrado, e nao outro. */
.activity-symbol--sm { font-size: var(--fs-meta); height: 28px; width: 28px; }

/* LINHA DE ENTIDADE — simbolo, nome e uma segunda linha, apontando para um
   lugar, uma comunidade ou um perfil.
   Era a mesma peca desenhada de novo em cada tela: a lista do "Onde jogar", os
   lugares e comunidades do seu perfil, e as tres listas do perfil publico —
   cada uma com o seu nome de classe, o seu quadrado e a sua escala de cor.
   Quem mexesse numa nao teria como saber das outras.

   Dois tamanhos, e a diferenca e de papel: `--lead` quando a lista E o assunto
   da tela, o pequeno quando ela e leitura de canto. */
/* PAINEL DE OPCOES — a folha que abre a partir de um gatilho.
   E o desenho do menu da publicacao, aqui em peca propria: fundo fundo, fio, e
   itens em coluna que acendem ao toque. Onde ele nasce e de quem o abre; aqui
   fica so o que e igual em todos.
   Existe porque a alternativa e o `<select>`, que abre a folha DO SISTEMA — a
   fonte do Android, o azul do Android, o canto arredondado do Android — no meio
   de uma tela que nao tem nada disso. */
.hub-menu { background: var(--hub-deep); border: 1px solid var(--hub-line-strong); display: grid; padding: 4px; position: absolute; z-index: 20; }
.hub-menu__item { background: transparent; border: 0; color: var(--hub-body); cursor: pointer; font-family: var(--hub-font); font-size: var(--fs-sm); padding: .65rem .75rem; text-align: left; text-decoration: none; }
.hub-menu__item:hover { background: var(--hub-hover); color: var(--hub-yellow); }
.hub-menu__item.is-active { color: var(--hub-yellow); }

.entity-row { align-items: center; color: inherit; display: flex; gap: 10px; min-width: 0; text-decoration: none; }
.entity-row--lead { gap: .8rem; }
.entity-row__identity { display: grid; min-width: 0; }
.entity-row__identity strong { color: var(--hub-body); font-size: var(--fs-body); font-weight: 400; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.entity-row__identity small { color: var(--hub-mute); font-size: var(--fs-sm); }
.entity-row--lead .entity-row__identity strong { color: var(--hub-title); font-weight: 600; }
a.entity-row:hover .entity-row__identity strong { color: var(--hub-yellow); }
.activity-content { min-width: 0; }
.activity-title-line { align-items: baseline; display: flex; flex-wrap: wrap; gap: .55rem; }
.activity-title-line strong { color: var(--hub-title); font-size: var(--fs-body); }
.activity-title-line span { color: var(--hub-mute); font: var(--fs-meta) var(--hub-mono); }
.activity-content p { color: var(--hub-body); font-size: var(--fs-body); line-height: var(--lh-snug); margin: .18rem 0; }
.activity-content blockquote { border-left: 2px solid var(--hub-line-strong); color: var(--hub-dim); font-size: var(--fs-sm); margin: .45rem 0; padding-left: .65rem; }
.activity-content small { color: var(--hub-dim); font: var(--fs-nano) var(--hub-mono); letter-spacing: var(--ls-label); }

.activity-load-more { justify-self: center; }

.activity-feedback.is-error { border-color: var(--hub-red); color: var(--hub-red); }
.activity-item--approval { align-items: start; border-left-color: var(--hub-yellow); grid-template-columns: auto minmax(0, 1fr); }
.approval-actions { display: flex; flex-wrap: wrap; gap: .45rem; margin-top: .7rem; }
.approval-actions button { background: transparent; border: 1px solid var(--hub-line-strong); color: var(--hub-body); cursor: pointer; font: var(--fs-meta) var(--hub-font); min-height: var(--btn-h-sm); padding: var(--btn-pad-sm); }
.approval-actions button:hover { border-color: var(--hub-yellow); color: var(--hub-yellow); }
.approval-actions button.is-primary { background: var(--hub-yellow); border-color: var(--hub-yellow); color: var(--hub-on-accent); font-weight: 600; }
.approval-actions button:disabled { cursor: wait; opacity: .55; }

/* "VER DETALHES" E DESTINO, E NAO DECISAO (21/08/2026).
   Ele vive na mesma fileira dos tres botoes, mas nao pode competir com eles:
   quem chega no cartao esta ali para decidir, e um quarto retangulo com borda
   diria que ha uma quarta escolha. Entao ele e link — texto sublinhado no
   hover, sem moldura —, que e como o app ja marca "isto leva a outro lugar". */
.approval-actions__detalhe {
    align-self: center;
    color: var(--hub-dim);
    font-size: var(--fs-meta);
    margin-left: auto;
    text-decoration: none;
}
.approval-actions__detalhe:hover { color: var(--hub-yellow); text-decoration: underline; }

/* A TELA DO DETALHE. O cartao vem da folha da casa; o que e desta pagina e o
   empilhamento e a tabela de fatos. */
.autorizacao-cartao { margin-bottom: 1rem; }
.autorizacao-vazia { display: grid; gap: .75rem; justify-items: start; padding: 1.25rem; }
.autorizacao-vazia h2 { color: var(--hub-title); font-size: var(--fs-h3); font-weight: 600; margin: 0; }
.autorizacao-vazia p { color: var(--hub-dim); font-size: var(--fs-body); margin: 0; }
.autorizacao-fatos { display: grid; gap: 1rem; padding: 1.15rem; }
.autorizacao-fatos dl { display: grid; gap: .55rem; margin: 0; }
.autorizacao-fatos dl > div {
    align-items: baseline;
    border-bottom: 1px solid var(--hub-line-soft);
    display: flex;
    gap: 1rem;
    justify-content: space-between;
    padding-bottom: .55rem;
}
.autorizacao-fatos dl > div:last-child { border-bottom: 0; padding-bottom: 0; }
.autorizacao-fatos dt { color: var(--hub-dim); font-size: var(--fs-meta); margin: 0; }
.autorizacao-fatos dd { color: var(--hub-body); font-size: var(--fs-body); margin: 0; text-align: right; }
.autorizacao-mono { font-family: var(--hub-mono); font-size: var(--fs-meta); word-break: break-all; }
.autorizacao-saldo {
    border-top: 1px solid var(--hub-line);
    display: grid;
    gap: .75rem;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    padding-top: 1rem;
}
.autorizacao-saldo > div { display: grid; gap: .25rem; }
.autorizacao-saldo span {
    color: var(--hub-mute);
    font: 500 var(--fs-micro) var(--hub-mono);
    letter-spacing: var(--ls-caps-wide);
    text-transform: uppercase;
}
/* O saldo em VERDE, como na carteira: amarelo e a cor de acao no resto do app,
   e saldo nao e uma acao. */
.autorizacao-saldo strong { color: var(--hub-green); font-size: var(--fs-h3); }
.autorizacao-voltar { margin-top: 1rem; }
.activity-invitation-backdrop { align-items: center; background: var(--hub-veil); display: flex; inset: 0; justify-content: center; padding: 1rem; position: fixed; z-index: 80; }
.activity-invitation-dialog { background: var(--hub-card); border: 1px solid var(--hub-line-strong); border-top: 3px solid var(--hub-yellow); max-width: 560px; padding: 1.25rem; width: 100%; }
.activity-invitation-dialog > span { color: var(--hub-purple); font: var(--fs-meta) var(--hub-mono); letter-spacing: var(--ls-caps-wide); }
.activity-invitation-dialog h2 { color: var(--hub-title); font-size: var(--fs-h2); margin: .55rem 0 .8rem; }
.activity-invitation-dialog > p { color: var(--hub-body); font-size: var(--fs-body); line-height: var(--lh-body); margin: 0; white-space: pre-line; }
.activity-invitation-dialog footer { border-top: 1px solid var(--hub-line-soft); display: flex; gap: .7rem; justify-content: flex-end; margin-top: 1.2rem; padding-top: 1rem; }
.activity-invitation-dialog button { background: transparent; border: 1px solid var(--hub-line-strong); color: var(--hub-body); cursor: pointer; padding: var(--btn-pad-md); }
.activity-invitation-dialog button.is-accept { background: var(--hub-yellow); border-color: var(--hub-yellow); color: var(--hub-on-accent); font-weight: 600; }

@media (max-width: 680px) {
    .activity-page { gap: 0; padding: 0 1rem 1rem; }
    .activity-filters { margin: 0 -1rem 1rem; padding: .85rem 1rem; }
    .activity-item { align-items: start; grid-template-columns: auto minmax(0, 1fr); }
    .activity-item > button { grid-column: 2; justify-self: start; }
    .activity-item-actions { grid-column: 2; justify-content: flex-start; }
    .activity-invitation-dialog footer { align-items: stretch; flex-direction: column-reverse; }
    .activity-invitation-dialog button { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; scroll-behavior: auto !important; transition-duration: .01ms !important; }
}

@media (max-width: 900px) {
    .hub-system-page,
    .hub-not-found-page {
        align-items: stretch;
        flex-direction: column;
        justify-content: flex-start;
        padding: 0 1rem 1rem;
    }

    .hub-system-panel,
    .hub-not-found-panel { margin-top: 1rem; }
}

/* ==========================================================================
   AJUSTES — O CARTÃO, A LINHA E O CAMPO
   ==========================================================================
   Estas regras nasceram presas ao CSS isolado da tela de Ajustes e subiram
   para cá quando as SUB-TELAS passaram a usar o mesmo desenho: trocar senha,
   gerenciar e-mail, excluir a conta. Escopo de componente não atravessa
   fronteira de componente — cada sub-tela teria de recopiar o cartão inteiro,
   e a segunda cópia já divergiria na primeira mudança.

   Aqui também some a necessidade de `::deep`: a folha da casa não carrega
   atributo de escopo, então o seletor alcança o filho direto. */

.settings-avatar {
    align-items: center;
    background: var(--hub-purple);
    color: var(--hub-on-accent);
    display: flex;
    flex: none;
    font-family: var(--hub-mono);
    font-weight: 600;
    justify-content: center;
}

/* AJUSTES TEM UMA PEÇA DE CARTÃO, UM CABEÇALHO E UMA LINHA — e é só isso.
   Antes eram grupos dentro de grupos: um cabeçalho de grupo, cartões dentro,
   alguns com cabeçalho próprio e listas dentro deles. Três níveis de título e
   quatro tamanhos de texto para dizer coisas do mesmo peso. Cada assunto agora
   é um cartão, todos iguais, empilhados como as publicações do feed. */

.settings-card {
    background: var(--hub-card);
    border: 1px solid var(--hub-line);
    display: grid;
    gap: .75rem;
    margin-bottom: 12px;
    padding: 1.1rem 1.25rem;
    position: relative;
}

/* SEM FAIXA GROSSA. A fita de 3px marca "aconteceu algo" ou "está selecionado";
   num cartão de ajuste ela era decoração, e havia uma cor por cartão. O que
   pede atenção se marca no ponto de estado, que é redondo, pequeno e fica na
   linha do assunto. */
.settings-attention { border-color: var(--hub-line-strong); }

.settings-section-heading { align-items: start; display: flex; gap: 1rem; justify-content: space-between; }
.settings-section-heading > div { display: grid; gap: .2rem; min-width: 0; }
/* O PESO É DECLARADO. Esta regra vem depois de `.settings-card h2` e tem a
   mesma força, então é ela que decide — e sem `font-weight` o título caía no
   negrito do navegador (700), mais pesado que o resto das seções da casa. */
.settings-section-heading h2 { color: var(--hub-title); font-size: var(--fs-h3); font-weight: 600; margin: 0; }
.settings-section-heading p { color: var(--hub-mute); font-size: var(--fs-sm); margin: .2rem 0 0; }

/* A LINHA: estado, assunto, ação. É o que todo cartão de Ajustes contém. */
.settings-row {
    align-items: center;
    border-top: 1px solid var(--hub-line-soft);
    display: flex;
    flex-wrap: wrap;
    gap: .75rem;
    padding-top: .75rem;
}

.settings-row:first-of-type,
.settings-section-heading + .settings-row { border-top: 0; padding-top: 0; }
/* O PONTO ENTRA NA LISTA DE EXCEÇÕES, e essa ausência era um defeito visível:
   sem ela o `flex: 1` desta regra alcançava o `.settings-dot`, e o quadradinho
   de 9px virava uma BARRA VERDE de duzentos pixels ao lado do e-mail e das
   chaves de acesso. Largura declarada não vence `flex-grow`. */
.settings-row > span:not(.settings-row__actions):not(.settings-badge):not(.settings-avatar):not(.settings-dot) { display: grid; flex: 1; gap: .1rem; min-width: 0; }
.settings-row strong { color: var(--hub-title); font-size: var(--fs-body); font-weight: 600; }
.settings-row small { color: var(--hub-dim); font-size: var(--fs-sm); overflow: hidden; text-overflow: ellipsis; }
.settings-row__actions { display: flex; flex: none; gap: .4rem; }
/* O FORMULARIO SOME DA CONTA DO VAO. Dois botoes dentro de um `<form>` viravam
   UM item de flex, e o `gap` acima nao os alcancava: eles encostavam um no
   outro, os unicos assim na tela. `display: contents` deixa o form existir para
   o envio e desaparecer para o layout. */
.settings-carrier { display: contents; }

/* O PONTO DE ESTADO — o único sinal de cor do cartão. */
/* O CHIP DE ESTADO — o ÚNICO lugar onde o cartão de Ajustes declara em que pé
   as coisas estão (v2, 18/08/2026).

   Antes o estado saía por três bocas ao mesmo tempo: um ponto colorido solto no
   cabeçalho, uma frase no corpo ("Ativo.", "Ligada") e às vezes um terceiro
   `small` repetindo. Quem lia tinha de juntar as três para saber uma coisa só.
   Aqui o ponto ganha a palavra ao lado e vira uma etiqueta: LIGADA, INATIVO,
   3 SESSÕES, SEM VOLTA.

   Ele fica no `.settings-section-heading`, na ponta direita — o mesmo lugar de
   onde o ponto solto saiu. */
.settings-chip {
    align-items: center;
    display: inline-flex;
    flex: none;
    font: 600 var(--fs-meta) var(--hub-mono);
    gap: .45rem;
    letter-spacing: var(--ls-caps);
    text-transform: uppercase;
    white-space: nowrap;
}

.settings-chip--ok { color: var(--hub-green); }
.settings-chip--alert { color: var(--hub-red); }
.settings-chip--off { color: var(--hub-mute); }

/* AS TRES CORES DO PONTO, E QUANDO CADA UMA VALE (20/08/2026).

   Ate aqui a regra era implicita, e por isso quatro pontos mentiam: um verde
   fixo ao lado de uma senha que nao existia, "push desligado" e "duas etapas
   desligadas" em vermelho como se algo estivesse quebrado, e uma contagem de
   sessoes em verde como se o app soubesse que todas sao suas. Duas telas
   chegaram a discordar sobre o MESMO fato, em direcoes opostas: o e-mail nao
   confirmado era cinza no resumo e vermelho no detalhe; as duas etapas
   desligadas, o contrario.

   - CINZA (sem modificador): desligado, nao configurado, ou uma contagem.
     E estado, nao problema. E o caso mais comum.
   - VERDE (.is-ok): ligado, configurado, existe, esta ativo agora.
   - VERMELHO (.is-alert): quebrado, esgotado ou sem volta. NUNCA um simples
     "desligado" — vermelho so pesa enquanto for raro, e e a mesma tinta do
     .btn-danger e do que nao tem volta.

   O teste do vermelho: alguma coisa PAROU de funcionar? E-mail nao confirmado
   passa (o "esqueci minha senha" nao funciona sem ele). Push desligado nao
   passa. Duas etapas desligadas nao passam: e o padrao de toda conta nova.

   O chip ao lado anda junto: --ok, --off e --alert, na mesma regra. */
.settings-dot { background: var(--hub-line-strong); flex: 0 0 9px; height: 9px; width: 9px; }
.settings-dot.is-ok { background: var(--hub-green); }
.settings-dot.is-alert { background: var(--hub-red); }

.settings-badge {
    border: 1px solid var(--hub-line-strong);
    color: var(--hub-mute);
    flex: none;
    font: 500 var(--fs-nano) var(--hub-mono);
    letter-spacing: var(--ls-label);
    padding: .2rem .4rem;
}

.settings-note { color: var(--hub-mute); font-size: var(--fs-sm); line-height: var(--lh-snug); margin: 0; }

/* O CAMPO É O DA CASA: 42px, rótulo em caixa alta pelo CSS, foco amarelo. */
.settings-field { display: grid; gap: .4rem; min-width: 0; }
.settings-field label { color: var(--hub-mute); font: var(--fs-meta) var(--hub-mono); letter-spacing: var(--ls-label); text-transform: uppercase; }
.settings-field input,
.settings-field textarea,
.settings-field select {
    background: var(--hub-field);
    border: 1px solid var(--hub-line);
    color: var(--hub-body);
    font: var(--fs-body) var(--hub-font);
    min-height: var(--field-h);
    min-width: 0;
    padding: .65rem;
    width: 100%;
}

.settings-field textarea { resize: vertical; }
.settings-field input:focus,
.settings-field textarea:focus,
.settings-field select:focus { border-color: var(--hub-yellow); outline: 1px solid var(--hub-yellow); }

/* DOIS CAMPOS NUMA FILEIRA — cidade + UF, DDI + telefone. O segundo de cada
   par e ESTREITO e de largura fixa: uma sigla de duas letras e um codigo de
   pais nao merecem metade da linha, e a grade de 1fr auto e a mesma que o
   endereco do estabelecimento usa. No celular a fileira desmonta: dois campos
   lado a lado numa tela de 360px deixam os dois pequenos demais. */
.settings-field-row { align-items: end; display: grid; gap: .6rem; grid-template-columns: minmax(0, 1fr) auto; }
.settings-field-row--ddi { grid-template-columns: auto minmax(0, 1fr); }
.settings-field--uf select { width: 7.5rem; }
.settings-field--ddi select { width: 13rem; }
.settings-field-note { color: var(--hub-mute); font-size: var(--fs-meta); margin: -.4rem 0 0; }
.settings-field > small { color: var(--hub-mute); font-size: var(--fs-meta); }
.settings-field-count { justify-self: end; }
.settings-field-actions { align-items: center; display: flex; flex-wrap: wrap; gap: .5rem; }
.settings-field-actions small { color: var(--hub-mute); font-size: var(--fs-meta); }
.settings-field-actions .is-available { color: var(--hub-green); }
.settings-field-actions .is-unavailable { color: var(--hub-red); }

/* O prefixo dentro do campo — o mesmo `#` da tela do mapa. */
/* O campo de @ com prefixo morreu aqui (leva 4 do balanço): quem escreve um @
   usa a peça PublicHandleInput, a mesma de criar conta. */

.settings-avatar--row { flex: none; font-size: var(--fs-avatar-compact); height: 34px; width: 34px; }

.settings-pagination { align-items: center; display: flex; gap: .6rem; justify-content: center; }
.settings-pagination span { color: var(--hub-mute); font: var(--fs-meta) var(--hub-mono); }

@media (max-width: 720px) {
    .settings-field-row { grid-template-columns: minmax(0, 1fr); }
    .settings-field--uf select,
    .settings-field--ddi select { width: 100%; }
    .settings-card { margin-bottom: 10px; padding: 1rem; }
    .settings-row { align-items: start; }
}

.settings-list { color: var(--hub-body); display: grid; font-size: var(--fs-body); gap: .3rem; list-style: none; margin: 0; padding: 0; }
.settings-list li { padding-left: 1rem; position: relative; }
.settings-list li::before { background: var(--hub-line-strong); content: ""; height: 6px; left: 0; position: absolute; top: .5rem; width: 6px; }

/* O FORMULÁRIO DENTRO DO CARTÃO.
   O cartão é uma grade, e o <form> entra nela como UM filho — sem isto, tudo
   que está dentro dele volta ao empilhamento padrão do navegador e perde o
   ritmo do resto do cartão. */
.settings-form { display: grid; gap: .75rem; }
/* O par de salvar mora À DIREITA nas três telas de edição (adequação de
   15/08): secundário à esquerda do primário amarelo, no mesmo canto. */
.settings-form-actions { align-items: center; display: flex; flex-wrap: wrap; gap: .5rem; justify-content: flex-end; }
.settings-validation { color: var(--hub-red); font-size: var(--fs-sm); }
.settings-validation ul { margin: 0; padding-left: 1.1rem; }

/* O CAMPO DE CÓDIGO — seis dígitos, e ele diz isso pelo desenho: monoespaçado,
   largo entre as letras e curto o bastante para não parecer que cabe uma frase. */
.settings-code-field input {
    font: 600 var(--fs-h3)/var(--lh-tight) var(--hub-mono);
    /* ALTURA CRAVADA, e não `min-height`. O navegador ignora a entrelinha
       declarada dentro de um <input> de uma linha e usa a caixa natural da
       fonte: em 16,8px de mono isso dá 22px, e o campo saía com 44,8 — ao lado
       de todos os outros campos da casa, que têm 42. */
    height: var(--field-h);
    letter-spacing: var(--ls-caps-wide);
    max-width: 220px;
    padding-block: 0;
    text-align: center;
}

/* ==========================================================================
   O CARTÃO DE CATÁLOGO — comunidade e estabelecimento
   ==========================================================================
   Ele nasceu no catálogo de comunidades e virou peça da casa quando os lugares
   ganharam folha própria: eram duas listas da mesma coisa — nome, retrato,
   descrição, quem participa e uma ação — desenhadas com dois cartões
   diferentes, e a diferença aparecia lado a lado no menu amarelo.

   A FITA DO TOPO É SÓ DO COMPUTADOR. Ela sai do id, em rodízio de três, e é
   decoração assumida — não codifica estado nem tipo. Numa grade de cartões ela
   quebra a monotonia; empilhados numa coluna de celular, os mesmos cartões
   viravam um zebrado, e por isso ela some lá embaixo. */

.community-discovery-card--yellow::before { background: var(--hub-yellow); }
.community-discovery-card--blue::before { background: var(--hub-blue); }
.community-discovery-card--purple::before { background: var(--hub-purple); }

.community-square--yellow { background: var(--hub-yellow); }
.community-square--blue { background: var(--hub-blue); }
.community-square--purple { background: var(--hub-purple); }

.community-name {
    color: var(--hub-title);
    display: block;
    font-size: var(--fs-h3);
    font-weight: 600;
    overflow: hidden;
    text-decoration: none;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.community-description {
    color: var(--hub-body);
    font-size: var(--fs-body);
    line-height: var(--lh-body);
    margin: 0;
    text-wrap: pretty;
}

.community-tags { color: var(--hub-blue); font: var(--fs-sm) var(--hub-mono); margin: 0; }

.community-join {
    align-items: center;
    background: transparent;
    border: 1px solid var(--hub-line-strong);
    color: var(--hub-body);
    cursor: pointer;
    display: inline-flex;
    flex: none;
    font-size: var(--fs-sm);
    justify-content: center;
    min-height: 30px;
    padding: .35rem .8rem;
    text-decoration: none;
}

.community-join:hover,
.community-join.is-joined {
    border-color: var(--hub-yellow);
    color: var(--hub-yellow);
}

.community-join:disabled { cursor: wait; opacity: .55; }

/* ==========================================================================
   A BARRA DE SALVAR DE UM EDITOR — cartão próprio, descolado do de cima
   ==========================================================================
   As três telas de edição (perfil comercial, comunidade e gerenciar local)
   tinham três desenhos para a mesma barra: uma era um `border-top` DENTRO do
   cartão do formulário, outra um cartão colado no de cima, a terceira um
   cartão com a frase de contexto à esquerda. Salvar é o mesmo gesto nas três,
   e a barra é o lugar mais previsível da tela — tinha de ser a mesma.

   A frase à esquerda é opcional: quando existe, ela explica o que o salvar
   faz (o de Gerenciar local avisa que a mudança vai ao Terminal). A ação
   principal fica na ponta direita, e o que não é principal vem antes dela. */
.hub-save-bar {
    align-items: center;
    background: var(--hub-card);
    border: 1px solid var(--hub-line);
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    justify-content: space-between;
    margin-top: 1rem;
    padding: .9rem 1.1rem;
}

/* Sem frase, a barra continua com a ação na direita: `margin-left: auto` no
   grupo, e não `justify-content` trocado — assim a frase pode aparecer depois
   sem a barra mudar de comportamento. */
.hub-save-bar__actions { align-items: center; display: flex; flex-wrap: wrap; gap: .6rem; margin-left: auto; }
.hub-save-bar > p { color: var(--hub-mute); font-size: var(--fs-meta); margin: 0; max-width: 52ch; }

@media (max-width: 720px) {
    .hub-save-bar { align-items: stretch; flex-direction: column; }
    .hub-save-bar__actions { flex-direction: column-reverse; margin-left: 0; }
    .hub-save-bar__actions a,
    .hub-save-bar__actions button { width: 100%; }
}

/* ==========================================================================
   A FAIXA DE UMA COMUNIDADE OU DE UM LUGAR — retrato, nome com o metadado,
   descrição em duas linhas, os retratos de quem participa e a ação na ponta.
   ==========================================================================
   Ela existia DUAS VEZES, com os mesmos nomes de classe, em duas folhas de
   tela: o catálogo de comunidades e o de estabelecimentos. Copiadas assim, as
   duas passam a divergir na primeira mudança — e a terceira tela que quisesse
   a mesma faixa (a aba "Comunidades" do perfil) não tinha como alcançá-la,
   porque CSS isolado não atravessa componente. */
.communities-rows { display: grid; gap: 10px; }

.communities-row {
    grid-template-columns: auto minmax(0, 1fr) auto auto;
    position: relative;
}

/* O nome é o degrau de destaque da faixa; o metadado mono ao lado vem da
   régua compartilhada de .activity-title-line. */
.communities-row .activity-title-line strong { font-size: var(--fs-lead); }
.communities-row .activity-title-line strong a { color: inherit; text-decoration: none; }
.communities-row .activity-title-line strong a:hover { color: var(--hub-yellow); }

/* Descrição em no máximo duas linhas — a faixa é lista, não leitura. */
.communities-row .activity-content p {
    display: -webkit-box;
    overflow: hidden;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
}

.communities-row-strip { min-width: 0; }
.communities-row-action { align-items: center; display: flex; gap: .5rem; }

/* O que já sigo/participo fica aceso em amarelo — o mesmo acorde do "participo"
   dos filtros. */
.communities-row-action .btn.is-joined { border-color: var(--hub-yellow); color: var(--hub-yellow); }

@media (max-width: 900px) {
    .communities-row { grid-template-columns: auto minmax(0, 1fr) auto; }
    .communities-row-strip { display: none; }
}

/* O MENU DE CORTESIA É UM BOTÃO (decisão do dono, 17/08/2026). Ele era um
   "•••" solto no canto de cima do cartão — sem moldura, sem tamanho de botão e
   fora de qualquer alinhamento com o "Abrir perfil"/"Abrir comunidade" que fica
   na mesma faixa. Agora ele veste `.btn .btn-sm .btn-icon` como qualquer outro
   e mora na coluna da ação, ao lado do irmão.

   O wrapper deixa de ser absoluto na faixa e passa a ser só a âncora do menu
   que abre por baixo dele. */
.community-card-admin { position: relative; }

.community-card-more { letter-spacing: var(--ls-label); line-height: var(--lh-tight); }
.community-card-more[aria-expanded="true"] { border-color: var(--hub-yellow); color: var(--hub-yellow); }

/* O MENU DO "···" É UM SÓ (dono, 17/08/2026): "tudo que for '...' no nosso
   sistema deve se comportar e abrir tal qual esse daí".

   Eram três folhas com três caras — a do catálogo em `--hub-deep` com sombra
   difusa e texto de corpo, a da publicação sem sombra nenhuma e com texto
   menor, e a da conversa em `--hub-card` com sombra dura de 6px. O mesmo gesto
   abria três coisas diferentes conforme a tela.

   O que continua sendo de cada uma é só ONDE ela ancora: o catálogo pendura no
   `.community-card-admin`, a publicação no cabeçalho dela e a conversa na
   linha. Posição é do lugar; aparência é da casa. */
.community-card-menu,
.social-post__menu,
.messages-row-menu__items {
    background: var(--hub-deep);
    border: 1px solid var(--hub-line-strong);
    box-shadow: 0 12px 28px rgb(0 0 0 / 35%);
    display: grid;
    min-width: 172px;
    position: absolute;
    z-index: 6;
}

.community-card-menu { right: 0; top: calc(100% + .25rem); }

.community-card-menu a,
.community-card-menu button,
.social-post__menu a,
.social-post__menu button,
.messages-row-menu__items a,
.messages-row-menu__items button {
    background: transparent;
    border: 0;
    border-bottom: 1px solid var(--hub-line-soft);
    color: var(--hub-body);
    cursor: pointer;
    font: var(--fs-body) var(--hub-font);
    padding: .7rem .8rem;
    text-align: left;
    text-decoration: none;
}

.community-card-menu > :last-child,
.social-post__menu > :last-child,
.messages-row-menu__items > :last-child { border-bottom: 0; }

.community-card-menu a:hover,
.community-card-menu button:hover,
.social-post__menu a:hover,
.social-post__menu button:hover,
.messages-row-menu__items a:hover,
.messages-row-menu__items button:hover { background: var(--hub-card); color: var(--hub-title); }

.community-card-menu .is-danger,
.social-post__menu .is-danger,
.messages-row-menu__items .is-danger { color: var(--hub-red); }

/* O CARTÃO DE CATÁLOGO NO CELULAR — linha, e não cartão.
   Numa coluna de 412px o cartão com descrição vira um bloco de seis linhas por
   item, e a lista deixa de ser lista. Aqui ele encolhe para nome, retrato, quem
   participa e a ação — as mesmas regras para comunidade e para estabelecimento,
   que é o ponto de a peça ter subido para cá. */
@media (max-width: 680px) {
    /* Sem a fita: numa coluna unica ela vira zebrado. */
    .community-square--yellow,
    .community-square--blue,
    .community-square--purple { background: var(--hub-purple); }
    .community-name { font-size: var(--fs-lead); }
    .community-description { display: none; }
    .community-join { font-size: var(--fs-sm); padding: .3rem .6rem; }
    /* O DESLOCAMENTO MORREU (dono, 17/08/2026). `right`/`top` sobraram de
       quando o "···" era `position: absolute` no canto do cartao; com ele em
       fluxo e `position: relative`, o `top` continuava valendo e empurrava o
       botao 7px para baixo — era isso que deixava o "···" fora de linha com
       "Abrir comunidade" e "Abrir perfil" no celular. */
    .community-card-menu { right: -.15rem; }
}

/* O CABEÇALHO DE UMA SEÇÃO DE AJUSTES É UMA LINHA — e só.
   Cada seção dizia o nome dela de um jeito: umas com sobretexto em caixa alta
   mais título gordo, outras só com o título, e todas repetindo o que a aba (no
   computador) e a barra (no celular) já dizem. Fica a frase que explica, que é
   a única informação nova do bloco. */
.settings-heading { margin-bottom: 4px; }
.settings-heading p { color: var(--hub-dim); font-size: var(--fs-lead); line-height: var(--lh-body); margin: 0; }

/* ==========================================================================
   O CABEÇALHO DE PERFIL — retrato, nome, bio, contadores e ações
   ==========================================================================
   Nasceu de TRÊS cópias quase literais (leva 6 do balanço de UX): o meu perfil,
   o perfil visto por outra pessoa e a comunidade reescreviam o mesmo desenho
   com três famílias de classe — a cópia era tão literal que uma delas tinha os
   rem convertidos para px na mão (1.35rem virou 22px, .75rem virou 12px).
   Mudar o retrato numa tela era esquecer as outras duas.

   O que é de UMA tela continua na tela: o botão Seguir/Mensagem do perfil
   público, o selo SEGUE VOCÊ, a linha de autor e privacidade da comunidade.
   Aqui mora só o que as três diziam em coro. */
.hub-profile-header {
    align-items: start;
    display: grid;
    gap: 1.35rem;
    grid-template-columns: auto minmax(0, 1fr) auto;
}

/* O CABEÇALHO É UM CARTÃO COMO OS OUTROS (17/08/2026). Ele era a única coisa
   solta da tela: retrato e nome flutuando sobre o fundo enquanto tudo abaixo
   tinha moldura. Quem põe a faixa colorida é `.hub-card--*` no markup, para a
   cor continuar sendo escolha explícita de quem monta a tela; o que a peça
   garante é o respiro por dentro, que um cartão sem recuo não teria. */
.hub-profile-header.hub-card { padding: 1.35rem 1.5rem; }

/* Quem não tem foto aparece sobre a cor gerada — sempre de --avatar-color,
   que HubAvatarPresentation.Style escreve; roxo é só o repouso de quem não
   passa estilo nenhum (a comunidade). */
.hub-profile-header__avatar {
    align-items: center;
    background: var(--avatar-color, var(--hub-purple));
    color: var(--hub-on-accent);
    display: flex;
    flex: 0 0 112px;
    font-family: var(--hub-mono);
    font-size: var(--fs-avatar-xl);
    font-weight: 600;
    height: 112px;
    justify-content: center;
    overflow: hidden;
    position: relative;
    width: 112px;
}

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

/* "Trocar foto": o dono vê a faixa no pé do retrato, e o retrato inteiro é o
   alvo do toque. No celular a faixa some — o editar mora no cabeçalho da tela. */
.hub-profile-header__avatar-edit {
    align-items: flex-end;
    display: flex;
    inset: 0;
    position: absolute;
    text-decoration: none;
}

.hub-profile-header__avatar-edit span {
    background: color-mix(in srgb, var(--hub-deep) 92%, transparent);
    color: var(--hub-body);
    font-family: var(--hub-font);
    font-size: var(--fs-avatar-meta);
    font-weight: 400;
    padding: .3rem;
    text-align: center;
    width: 100%;
}

.hub-profile-header__avatar-edit:hover span { color: var(--hub-yellow); }

.hub-profile-header__copy { min-width: 0; }

.hub-profile-header__name-line {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: .75rem;
}

.hub-profile-header__name-line h1 {
    color: var(--hub-title);
    font-size: var(--fs-h1);
    font-weight: 600;
    letter-spacing: var(--ls-tight);
    margin: 0;
}

.hub-profile-header__name-line > span {
    color: var(--hub-mute);
    font-family: var(--hub-mono);
    font-size: var(--fs-body);
    /* O @ vai ate 30 caracteres e nao tem espaco onde quebrar: num telefone
       estreito ele empurraria a largura da pagina inteira. Corta. */
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A bio existe duas vezes no markup — dentro do cabeçalho para o computador e
   fora dele para o celular, onde ela vira uma faixa de largura inteira. */
.hub-profile-header__bio {
    color: var(--hub-body);
    font-size: var(--fs-lead);
    line-height: var(--lh-body);
    margin: .5rem 0 0;
    max-width: 560px;
    text-wrap: pretty;
}

.hub-profile-header__bio--mobile { display: none; }

.hub-profile-header__counters {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: .65rem 1.35rem;
    margin-top: .85rem;
}

.hub-profile-header__counters > a,
.hub-profile-header__counters > div {
    align-items: baseline;
    color: inherit;
    display: inline-flex;
    gap: .3rem;
    text-decoration: none;
}

.hub-profile-header__counters strong {
    color: var(--hub-title);
    font-family: var(--hub-mono);
    font-size: var(--fs-h3);
    font-weight: 600;
}

.hub-profile-header__counters span { color: var(--hub-dim); font-size: var(--fs-body); }

.hub-profile-header__counters > a:hover span,
.hub-profile-header__counters > a:hover strong { color: var(--hub-yellow); }

/* A fileira de retratos (prévia de seguidores / participantes). */
.hub-profile-header__strip { margin-top: .85rem; max-width: 560px; }

.hub-profile-header__actions {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    justify-content: flex-end;
}

/* A ação neutra do cabeçalho (Compartilhar, Editar, Regras). Botão com cara
   própria — Seguir, por exemplo — é da tela, e não desta classe. */
.hub-profile-header__action {
    align-items: center;
    background: transparent;
    border: 1px solid var(--hub-line-strong);
    color: var(--hub-body);
    cursor: pointer;
    display: inline-flex;
    font-size: var(--fs-body);
    min-height: var(--btn-h-sm);
    padding: var(--btn-pad-md);
    text-decoration: none;
}

.hub-profile-header__action:hover { border-color: var(--hub-yellow); color: var(--hub-yellow); }

@media (max-width: 720px) {
    .hub-profile-header {
        align-items: center;
        gap: .8rem 1rem;
        grid-template-columns: auto minmax(0, 1fr);
    }

    .hub-profile-header__avatar {
        flex-basis: 76px;
        font-size: var(--fs-avatar-md);
        height: 76px;
        width: 76px;
    }

    .hub-profile-header__avatar-edit { display: none; }
    .hub-profile-header__name-line { display: block; }
    .hub-profile-header__name-line h1 { font-size: var(--fs-h1-compact); }
    .hub-profile-header__name-line > span { display: block; font-size: var(--fs-sm); margin-top: .12rem; }
    .hub-profile-header__bio--desktop { display: none; }
    .hub-profile-header__bio--mobile { display: block; margin: 0; max-width: none; }

    .hub-profile-header__counters { gap: .85rem; margin-top: .5rem; }
    .hub-profile-header__counters strong { font-size: var(--fs-lead); }
    .hub-profile-header__counters span { font-size: var(--fs-sm); }
    .hub-profile-header__strip { margin-top: .6rem; }
}

@media (max-width: 390px) {
    .hub-profile-header { gap: .75rem; }
    .hub-profile-header__avatar { flex-basis: 70px; height: 70px; width: 70px; }
    .hub-profile-header__counters { gap: .6rem; }
}

/* ==========================================================================
   OS TRÊS CARTÕES DE ESTATÍSTICA — rótulo, número grande e contexto
   ==========================================================================
   Mesma leva e mesma história do cabeçalho acima: três telas, três famílias de
   classe, as MESMAS declarações valor a valor — cartão com faixa de 3px no
   topo, rótulo mono em caixa alta, número mono --fs-h1, e o achatamento do
   celular (fundo transparente, divisor à direita, número colorido).

   A COR É MODIFICADOR EXPLÍCITO, nunca a posição do cartão: a comunidade usa
   vermelho onde os perfis usam azul, e uma regra por ordem esconderia isso. */
.hub-highlights {
    display: grid;
    gap: .85rem;
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.hub-highlight {
    background: var(--hub-card);
    border: 1px solid var(--hub-line);
    min-width: 0;
    padding: 1rem 1.1rem;
    position: relative;
}

.hub-highlight::before {
    content: "";
    height: 3px;
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
}

/* O CARTÃO DE ESTATÍSTICA SEGUE A RÉGUA DA FAIXA (ver o bloco do .hub-card):
   os três eram roxos, e eram eles a "fileira toda rosa" que o dono apontou —
   três faixas de uma cor que não dizia nada, entre o cabeçalho e o compositor.
   Os modificadores continuam existindo porque a cor é EXPLÍCITA e nunca sai da
   ordem; o que mudou foi qual delas o app usa. */
.hub-highlight--yellow::before { background: var(--hub-yellow); }
.hub-highlight--red::before { background: var(--hub-red); }
.hub-highlight--green::before { background: var(--hub-green); }

.hub-highlight > span {
    color: var(--hub-mute);
    display: block;
    font-family: var(--hub-mono);
    font-size: var(--fs-micro);
    font-weight: 400;
    letter-spacing: var(--ls-caps-wide);
}

.hub-highlight > strong {
    color: var(--hub-title);
    display: block;
    font-family: var(--hub-mono);
    font-size: var(--fs-h1);
    font-weight: 600;
    margin-top: .35rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.hub-highlight > p {
    color: var(--hub-dim);
    font-size: var(--fs-body);
    margin: .1rem 0 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* O CARTÃO DE CARAS. Um dos três destaques mostra QUEM segue em vez de um
   número — os retratos entram no lugar onde os outros põem o `<strong>`, e por
   isso ele repõe na mão o respiro que o número trazia. `::deep` não cabe aqui:
   esta folha é global, e a fita é um componente com escopo próprio.

   O "VER TODOS" DESCE PARA A LINHA DE BAIXO, onde os outros dois cartões põem
   a frase de contexto ("Saldo atual no Terminal", "Discussões no fórum"). Ao
   lado dos retratos ele ocupava a linha do número e os três cartões deixavam
   de rimar — que é justamente o que o cartão de caras veio para manter.

   O `body` na frente é o que faz a regra valer: a fita tem folha ISOLADA, onde
   o Razor a reescreve como `.community-participant-strip[b-xxxx]` — mesma
   especificidade que a regra daqui, e o pacote isolado carrega depois. Sem ele
   o empate se resolve pela ordem e o "ver todos" fica ao lado dos retratos. */
body .hub-highlight--faces .community-participant-strip {
    align-items: flex-start;
    display: grid;
    gap: .3rem;
    justify-items: start;
    margin-top: .55rem;
}

body .hub-highlight--faces .community-participant-strip__all { font-size: var(--fs-body); }
.hub-highlight--faces > p { margin-top: .55rem; }

/* Rótulo e número podem ter uma versão curta para o celular: "RECORDES ATIVOS"
   vira "RECORDES", "1.234.567" vira "1,2k". O par mora no mesmo cartão e a
   folha escolhe qual aparece. */
.hub-highlight .hub-highlight__label--mobile,
.hub-highlight .hub-highlight__value--mobile { display: none; }

@media (max-width: 720px) {
    .hub-highlights { border-bottom: 1px solid var(--hub-line-soft); gap: 0; }

    .hub-highlight {
        background: transparent;
        border: 0;
        border-right: 1px solid var(--hub-line-soft);
        padding: .85rem .7rem;
    }

    .hub-highlight:last-child { border-right: 0; }
    .hub-highlight::before { display: none; }
    .hub-highlight > span { font-size: var(--fs-nano); }
    .hub-highlight > strong { font-size: var(--fs-h2); margin-top: .2rem; }
    /* Sem a faixa, quem diz a cor do cartão é o próprio número. O azul fica na
       cor de título de propósito — era assim nas três telas. */
    .hub-highlight--yellow > strong { color: var(--hub-yellow); }
    .hub-highlight--red > strong { color: var(--hub-red); }
    .hub-highlight--green > strong { color: var(--hub-green); }
    .hub-highlight > p { display: none; }
    .hub-highlight .hub-highlight__label--desktop,
    .hub-highlight .hub-highlight__value--desktop { display: none; }
    .hub-highlight .hub-highlight__label--mobile,
    .hub-highlight .hub-highlight__value--mobile { display: block; }
}
