/* =============================================
   fragtext — identidade visual do Scribo
   Herda a paleta e a tipografia do editor_deconto: cyberpunk neon, vidro
   fosco, títulos em Oswald caixa-alta.

   Os nomes das variáveis são os mesmos de css/style.css do deconto, de
   propósito: é o vocabulário que já existe.

   Uma diferença deliberada de escala: lá o h1 tem 3.8rem, tamanho de landing
   page. Aqui é ferramenta de escrita — o neon fica nos acentos, nas bordas e
   nos estados, e o texto que você escreve é quem ocupa a tela.
   ============================================= */

/* -- 1. Variáveis (tema escuro padrão) -- */
:root {
    --color-background: #0a0a0a;
    --color-surface: #1a1a1a;
    --color-text: #f0f0f0;
    --color-text-muted: #a0a0a0;
    --glass-bg: rgba(20, 20, 35, 0.5);
    --glass-border: rgba(255, 255, 255, 0.1);

    --color-primary: #00ffff;    /* Azul Neon  */
    --color-secondary: #39ff14;  /* Verde Neon */
    --color-accent: #ff1493;     /* Rosa Choque */
    --color-danger: #ff4d6d;

    --shadow-primary: 0 0 8px var(--color-primary), 0 0 16px rgba(0, 255, 255, .5);
    --shadow-secondary: 0 0 8px var(--color-secondary), 0 0 16px rgba(57, 255, 20, .5);
    --shadow-accent: 0 0 8px var(--color-accent), 0 0 16px rgba(255, 20, 147, .5);

    --font-main: 'Roboto', sans-serif;
    --font-headings: 'Oswald', sans-serif;
    --font-logo: 'Bebas Neue', sans-serif;
    --font-leitura: 'Lora', Georgia, serif;

    --raio: .5rem;
    --largura: 54rem;
    /* So onde se LE (pagina publica, ensaio, convite): linha de 54rem
       cansa o olho. 42rem da ~75 caracteres na fonte de leitura — e e
       por que a versao de celular "fica bonita": coluna estreita. */
    --largura-leitura: 42rem;
}

/* -- 2. Tema claro -- */
[data-theme="light"] {
    --color-background: #f4f7f9;
    --color-surface: #ffffff;
    --color-text: #2c3e50;
    --color-text-muted: #7f8c8d;
    --glass-bg: rgba(255, 255, 255, .7);
    --glass-border: #e0e6ed;

    --color-primary: #0093b8;
    --color-secondary: #2eb82e;
    --color-accent: #ff1493;
    --color-danger: #d62246;

    --shadow-primary: 0 0 6px rgba(0, 195, 255, .55);
    --shadow-secondary: 0 0 6px rgba(57, 255, 20, .45);
    --shadow-accent: 0 0 6px rgba(255, 20, 147, .5);
}

/* -- 2b. Visuais (#22) --
   O visual e um segundo eixo, independente do claro/escuro: no site e
   preferencia de quem usa (localStorage `fragtext_visual`); na pagina
   publica vem congelado na foto (`data-visual` impresso pelo p.php).
   O catalogo mora em ft_themes — este arquivo so tem os blocos de
   variaveis correspondentes. */

/* Neon azul: o mesmo neon, com o rosa trocado por azul. */
[data-visual="neon-azul"] {
    --color-accent: #1e90ff;
    --shadow-accent: 0 0 8px var(--color-accent), 0 0 16px rgba(30, 144, 255, .5);
}
[data-theme="light"][data-visual="neon-azul"] {
    --color-accent: #1273e6;
    --shadow-accent: 0 0 6px rgba(18, 115, 230, .5);
}

/* Papiro: papel envelhecido, serifas, nada de neon. E aparencia UNICA:
   este bloco vem DEPOIS do tema claro de proposito — com os dois
   atributos no <html>, o empate de especificidade e decidido pela
   ordem, e o papiro vence tanto o escuro quanto o claro. */
[data-visual="papiro"] {
    --color-background: #efe5cf;
    --color-surface: #f7f0df;
    --color-text: #3a2f20;
    --color-text-muted: #7d6f56;
    --glass-bg: rgba(247, 240, 223, .72);
    --glass-border: #d9cba8;

    --color-primary: #7a5c2e;
    --color-secondary: #5e6e46;
    --color-accent: #8c3b2e;
    --color-danger: #a03030;

    --shadow-primary: 0 1px 3px rgba(58, 47, 32, .25);
    --shadow-secondary: 0 1px 3px rgba(58, 47, 32, .2);
    --shadow-accent: 0 1px 3px rgba(140, 59, 46, .3);

    --font-main: 'Lora', Georgia, serif;
    --font-headings: 'Lora', Georgia, serif;
    --font-logo: 'Lora', Georgia, serif;
}

/* -- 3. Globais -- */
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }

body {
    background-color: var(--color-background);
    font-family: var(--font-main);
    color: var(--color-text);
    line-height: 1.6;
    overflow-x: hidden;
    transition: background-color .4s ease, color .4s ease;
}

h1, h2, h3 {
    font-family: var(--font-headings);
    text-transform: uppercase;
    letter-spacing: .02em;
    font-weight: 500;
}
a { color: var(--color-primary); }

.neon-text-primary { color: var(--color-primary); text-shadow: var(--shadow-primary); }
.neon-text-accent  { color: var(--color-accent);  text-shadow: var(--shadow-accent); }

/* -- 4. Topo em vidro -- */
.topo {
    position: sticky; top: 0; z-index: 100;
    display: flex; align-items: center; gap: 1rem;
    padding: .8rem 1.25rem;
    background: var(--glass-bg);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--glass-border);
}
.topo .marca {
    font-family: var(--font-logo); font-size: 1.8rem; letter-spacing: 1px;
    text-decoration: none; color: var(--color-accent);
    text-shadow: var(--shadow-accent);
    line-height: 1;
}
.topo .espaco { flex: 1; }

.envelope { max-width: var(--largura); margin: 0 auto; padding: 1.75rem 1.25rem 6rem; }

/* -- 5. Botões -- */

/* O display:none do atributo `hidden` vem da folha do NAVEGADOR, e
   qualquer display de autor (o inline-flex logo abaixo) passa por cima
   dela — sem esta regra, nenhum <button hidden> do app fica escondido
   de verdade (#61: "Converter em texto" aparecendo em documento texto).
   EXCETO `hidden="until-found"` (#123): esse valor é a primitiva de
   "recolhido mas achável pelo Ctrl+F" — a folha do navegador já dá a ele
   `display:block` + `content-visibility:hidden`, sem que a página precise
   de nada. Um `!important` sem esta exceção derruba isso: o elemento vira
   display:none de verdade, e o algoritmo de busca do navegador PULA
   display:none sempre — nem entra para procurar. Medido: com a exceção,
   `window.find()` acha o texto dentro; sem ela, retorna falso. Foi a causa
   do dono relatar "o ctrl+f não entra no recolhido" depois da #123. */
[hidden]:not([hidden="until-found"]) { display: none !important; }

button, .botao {
    font-family: var(--font-main); font-size: .95rem; cursor: pointer;
    border: 1px solid var(--glass-border);
    background: var(--color-surface);
    color: var(--color-text);
    padding: .5rem .9rem;
    border-radius: var(--raio);
    display: inline-flex; align-items: center; gap: .4rem;
    text-decoration: none;
    transition: border-color .2s, box-shadow .2s, color .2s;
}
button:hover, .botao:hover {
    border-color: var(--color-primary);
    box-shadow: var(--shadow-primary);
    color: var(--color-primary);
}
button:disabled { opacity: .4; cursor: not-allowed; box-shadow: none; border-color: var(--glass-border); color: var(--color-text-muted); }

.botao-principal {
    font-family: var(--font-headings); text-transform: uppercase; letter-spacing: .04em;
    background: transparent;
    border-color: var(--color-accent);
    color: var(--color-accent);
    text-shadow: var(--shadow-accent);
}
.botao-principal:hover {
    border-color: var(--color-accent); color: var(--color-accent);
    box-shadow: var(--shadow-accent);
}
.botao-discreto { border-color: transparent; background: transparent; color: var(--color-text-muted); }
.botao-perigo:hover { border-color: var(--color-danger); color: var(--color-danger); box-shadow: 0 0 8px rgba(255,77,109,.5); }

/* -- 6. Campos -- */
input, select, textarea {
    font-family: var(--font-main); font-size: 1rem;
    color: var(--color-text);
    background: var(--color-surface);
    border: 1px solid var(--glass-border);
    border-radius: var(--raio);
    padding: .55rem .75rem;
    width: 100%;
    transition: border-color .2s, box-shadow .2s;
}
input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: var(--shadow-primary);
}
label {
    display: block; font-family: var(--font-headings); text-transform: uppercase;
    font-size: .75rem; letter-spacing: .06em;
    color: var(--color-text-muted); margin-bottom: .3rem;
}

/* -- 7. Avisos -- */
.aviso {
    padding: .75rem .95rem; border-radius: var(--raio);
    border: 1px solid var(--glass-border); background: var(--glass-bg);
    backdrop-filter: blur(6px);
    margin-bottom: 1rem;
}
.aviso-erro { border-color: var(--color-danger); color: var(--color-danger); }

/* Dica de instalação no iOS (#46). Fixa no rodapé porque ela aparece
   sobre qualquer página do app, sem lugar reservado no layout de
   nenhuma. `env(safe-area-inset-bottom)` mantém ela acima da barra de
   gestos do iPhone — que é justamente o aparelho onde ela aparece.
   `gap` separa ELEMENTOS: o texto vai num <span> em pwa.js, senão ele
   virava nó anônimo e grudava no botão (armadilha já paga). */
.dica-instalar {
    position: fixed;
    left: 1rem; right: 1rem;
    bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
    z-index: 50;
    display: flex; align-items: center; gap: .75rem;
    font-size: .9rem;
    margin-bottom: 0;
}
.dica-instalar button { flex-shrink: 0; }
.vazio { color: var(--color-text-muted); text-align: center; padding: 3.5rem 1rem; }
.carregando { color: var(--color-text-muted); text-align: center; padding: 2.5rem; }

/* -- 8. Toast -- */
/* No TOPO, não no rodapé (#112): embaixo é onde mora o fragmento em foco
   e, no celular, o teclado -- um toast ali cai em cima de quem está
   escrevendo. `top` fica abaixo do `.topo` sticky (z-index 100), que
   ocupa uns 3,4rem; 4.5rem sobra folga sem depender do tamanho exato. */
#toasts { position: fixed; top: 4.5rem; right: 1rem; z-index: 200; display: flex; flex-direction: column; gap: .5rem; }
.toast {
    background: var(--color-surface); border: 1px solid var(--glass-border);
    border-radius: var(--raio); padding: .65rem .9rem;
    box-shadow: 0 8px 24px rgba(0,0,0,.5);
    animation: entra .18s ease-out; max-width: 22rem;
}
.toast-erro { border-color: var(--color-danger); box-shadow: 0 0 10px rgba(255,77,109,.35); }
.toast-ok   { border-color: var(--color-secondary); box-shadow: 0 0 10px rgba(57,255,20,.3); }
@keyframes entra { from { opacity: 0; transform: translateY(8px); } }

/* -- 9. Listagem -- */
.filtros { display: grid; gap: .7rem; margin-bottom: 1.35rem; grid-template-columns: 1fr; }
@media (min-width: 42rem) {
    /* Dentro da sanfona (#54) são os quatro que se ESCOLHE mais Ordenar.
       A grade declarava 5 colunas desde antes de categoria e ambiente
       existirem (#16) e ninguém acertou o número depois — sobravam dois
       campos quebrando em linha extra. `auto-fit` acaba com a contagem
       manual: quem acrescentar o sexto filtro não precisa lembrar disto. */
    .filtros { grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); align-items: end; }

    /* Buscar continua com o dobro do botão: é o campo em que se digita. */
    .filtros-topo { grid-template-columns: 2fr auto; }
}

/* A sanfona em si. `<details>` nativo — abre e fecha sem JS, responde ao
   teclado e ao leitor de tela sozinho. O JS só decide o estado INICIAL
   por largura e mantém o resumo de filtros ligados. */
.filtros-sanfona { margin-bottom: 1.35rem; }
.filtros-sanfona > summary {
    cursor: pointer;
    font-family: var(--font-headings); text-transform: uppercase;
    font-size: .8rem; letter-spacing: .05em;
    color: var(--color-text-muted);
    padding: .5rem .2rem;   /* alvo de dedo sem desenhar caixa */
    list-style-position: inside;
}
.filtros-sanfona > summary:hover,
.filtros-sanfona[open] > summary { color: var(--color-primary); }
/* Some a margem de baixo do bloco interno: quem espaça aqui é a sanfona. */
.filtros-sanfona .filtros { margin-bottom: 0; padding-top: .6rem; }
/* O contador de filtros ligados precisa DESTACAR — é ele que impede a
   sanfona fechada de esconder que a lista está filtrada. */
#filtros-ativos { color: var(--color-accent); }

.cartoes { display: flex; flex-direction: column; gap: .7rem; }

.cartao {
    display: block; text-decoration: none; color: inherit;
    /* SEM `backdrop-filter` aqui, e não é escolha de estilo: atrás de um
       cartão só existe `body { background-color }`, cor chapada nos três
       temas. Borrar campo uniforme devolve o mesmo campo uniforme — o
       filtro não mudava um pixel e, em troca, punha CADA cartão numa
       camada composta própria, que o navegador reborrava a cada quadro
       de rolagem. Vinte cartões por página, vinte camadas, zero efeito.
       O `.topo` mantém o dele: lá passa conteúdo por trás de verdade. */
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--raio); padding: 1rem 1.1rem;
    transition: border-color .2s, box-shadow .2s;
}
.cartao:hover { border-color: var(--color-primary); box-shadow: var(--shadow-primary); }
.cartao h3 {
    font-size: 1.15rem; margin-bottom: .35rem;
    text-transform: none; letter-spacing: -.01em;
}
.cartao .previa {
    font-family: var(--font-leitura); font-size: .92rem; color: var(--color-text-muted);
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.cartao .meta {
    display: flex; flex-wrap: wrap; gap: .4rem .85rem;
    margin-top: .6rem; font-size: .78rem; color: var(--color-text-muted); align-items: center;
}

.etiqueta {
    border: 1px solid var(--glass-border); border-radius: 999px;
    padding: .08rem .55rem; font-size: .72rem; letter-spacing: .02em;
}
.etiqueta-tipo {
    border-color: var(--color-accent); color: var(--color-accent);
    font-family: var(--font-headings); text-transform: uppercase;
}

.paginacao {
    display: flex; align-items: center; justify-content: center;
    gap: .8rem; margin-top: 1.75rem; color: var(--color-text-muted); font-size: .9rem;
}

/* Excluir/restaurar em massa (#154, passo 2). A barra fica ACIMA da lista
   (nunca flutuante sobre os cartões, que esconderia o que está sendo
   selecionado) e some por trás do botão "Selecionar" quando o modo está
   desligado — fora do modo, a tela é idêntica à de antes desta issue. */
.barra-selecao {
    display: flex; align-items: center; flex-wrap: wrap;
    gap: .6rem; margin-bottom: .9rem;
}
.barra-selecao .espaco { flex: 1; }
#selecao-contagem { color: var(--color-text-muted); font-size: .85rem; }

/* O checkbox de cada cartão é IRMÃO do `<a>`, nunca filho dele — um
   `<input>` dentro de `<a class="cartao">` disputaria o próprio clique
   com a navegação. Escondido por padrão (`display:none`): fora do modo
   Selecionar a lista fica exatamente como sempre foi, sem reservar
   espaço nem piscar layout quando o modo liga. */
.cartao-linha { display: flex; align-items: flex-start; gap: .6rem; }
.cartao-linha .cartao { flex: 1; min-width: 0; }
.cartao-check {
    display: none; width: 1.15rem; height: 1.15rem; flex-shrink: 0;
    margin-top: .95rem;   /* alinha com a primeira linha do cartão, não com o topo do flex */
}
/* `.cartoes.selecionando`, não `#lista`: a lixeira (perfil.js) reusa o
   mesmo par de classe, em `#lixeira`, outro elemento com `.cartoes`. */
.cartoes.selecionando .cartao-check { display: block; }

/* Lixeira (#154): o checkbox mora DENTRO do cartão (que aqui é `<div>`,
   não `<a>` — sem clique de navegação pra disputar), num `<label>` que
   também envolve o título, pra tocar o título marcar junto. */
.cartao-check-linha { display: flex; align-items: flex-start; gap: .6rem; cursor: pointer; }
.cartao-check-linha h3 { margin-bottom: 0; }
.lixeira-check { margin-top: .2rem; }

/* "Desfazer" (#154): banner fixo no rodapé, não toast — precisa de um
   botão de ação, e o toast desta casa é só texto (ui.js:toast). Reaproveita
   a paleta de aviso já usada em `.aviso`. */
.barra-desfazer {
    position: fixed; left: 50%; bottom: 1.2rem; transform: translateX(-50%);
    display: flex; align-items: center; gap: .9rem;
    padding: .7rem 1.1rem; border-radius: var(--raio);
    background: var(--color-surface); border: 1px solid var(--glass-border);
    box-shadow: var(--shadow-primary); z-index: 50;
}

/* Os meus ambientes (#155). `.ambiente-topo` é o par nome+contagem, em
   cima; `.ambiente-acoes` (reaproveita `.meta`, mesma classe dos cartões
   de documento) leva os botões e o `<select>` de destino embaixo — os
   dois quebram em coluna sozinhos a 390px porque `.cartao .meta` já é
   `flex-wrap: wrap` (linha 323); só o campo de renomear precisava de
   largura própria pra não nascer do tamanho do texto digitado. */
.ambiente-topo {
    display: flex; align-items: center; justify-content: space-between;
    gap: .6rem; margin-bottom: .3rem;
}
.ambiente-topo h3 { margin-bottom: 0; }
.ambiente-editar { width: auto; min-width: 12rem; flex: 1; }
.ambiente-acoes select { width: auto; min-width: 9rem; }

/* -- 10. Mapa da cidade (#33) --
   cidade.php é público, visual fixo (retrô/neon), não segue a
   preferência de tema/visual de quem visita — mesmo raciocínio de
   p.php congelar o tema da FOTO. Reaproveita .cartao/.etiqueta da
   listagem; só falta um grid de verdade (.cartoes é flex-column, uma
   por linha) e o efeito de scanline que dá o ar retrô sem imagem. */
.grade-cidade {
    display: grid; gap: .9rem;
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
}

.cidade-retro { position: relative; }
.cidade-retro::before {
    content: ''; position: absolute; inset: 0; pointer-events: none;
    background: repeating-linear-gradient(
        to bottom, rgba(255,255,255,.035) 0, rgba(255,255,255,.035) 1px,
        transparent 1px, transparent 3px
    );
    mix-blend-mode: overlay;
}

/* Posição real (linha/coluna), não fluxo — diferente de .grade-cidade.
   --unidades-l/--unidades-t (contagem de colunas/linhas) vêm inline do
   PHP; --celula/--quad são a escala (px por unidade), com o valor base
   aqui e o zoom (assets/js/cidade-mapa.js) só reescrevendo essas duas
   variáveis no próprio #mapa-canvas — todo tile e o SVG herdam sem
   precisar recalcular nada individualmente. Base tem que bater com
   CELULA_QUADRADINHO/TAMANHO_QUADRADINHO em cidade.php (22px/18px),
   mesmo espírito de duplicação documentada de COR_REGIAO. */
.mapa-canvas {
    --celula: 22px; --quad: 18px;
    position: relative; overflow: auto; min-height: 18rem; max-width: 100%;
    width: calc(var(--unidades-l) * var(--celula));
    height: calc(var(--unidades-t) * var(--celula));
    border: 1px solid var(--glass-border); border-radius: var(--raio);
    background: var(--color-surface);
}
.mapa-tile { position: absolute; width: 10rem; }
.mapa-tile .cartao { margin: 0; }
.mapa-svg { position: absolute; inset: 0; pointer-events: none; overflow: visible; }
.mapa-svg line { stroke: var(--color-primary); stroke-width: 2; }
.mapa-svg line.tunel { stroke-dasharray: 6 5; stroke: var(--color-accent); }

/* Mapa único (cidade.php sem parâmetro): 1000 terrenos juntos, tile
   vira quadradinho de tamanho fixo (sem nome — não cabe em 1000), com
   um emoji de zona/prédio dentro (aria-hidden — quem lê tela usa o
   aria-label do link, não o glifo). Clique abre a página do terreno;
   hover só clareia a cor, sem tooltip (decisão explícita — nada de
   popup no mapa). --l/--t (unidade de grade, não px) vêm inline por
   tile; a posição final em px é calculada aqui, incluindo o zoom. */
.mapa-tile-quadrado {
    position: absolute;
    left: calc(var(--l) * var(--celula) + (var(--celula) - var(--quad)) / 2);
    top: calc(var(--t) * var(--celula) + (var(--celula) - var(--quad)) / 2);
    width: var(--quad); height: var(--quad); border-radius: 3px;
    display: flex; align-items: center; justify-content: center;
    font-size: calc(var(--quad) * .72); line-height: 1;
}
.mapa-tile-quadrado:hover, .mapa-tile-quadrado:focus-visible {
    filter: brightness(1.4); outline: 2px solid var(--color-text); z-index: 2;
}
/* Sinal de crônica vinculada: anel, não ícone extra — não cabem dois
   símbolos num quadrado de 18px. */
.mapa-tile-quadrado.tem-cronica { box-shadow: 0 0 0 2px var(--color-accent); }
/* Só aparece em cidadeadmin.php — cidade.php nunca manda terreno
   oculto pro MapaCanvas, então a classe nunca é aplicada lá. */
.mapa-tile-quadrado.inativo { opacity: .35; outline: 1px dashed var(--color-text-muted); }

/* Zoom do mapa único — "dedos gordos" pedido pelo dono. Único lugar de
   cidade.php com JavaScript (assets/js/cidade-mapa.js); os botões só
   reescrevem --celula/--quad no #mapa-canvas acima. */
.mapa-zoom {
    display: flex; align-items: center; gap: .6rem; margin-bottom: .6rem;
}
.mapa-zoom button {
    width: 2rem; height: 2rem; border-radius: 999px;
    border: 1px solid var(--glass-border); background: var(--color-surface);
    color: var(--color-text); font-size: 1.1rem; line-height: 1; cursor: pointer;
}
.mapa-zoom button:hover { border-color: var(--color-primary); }
.mapa-zoom span { font-size: .85rem; color: var(--color-text-muted); min-width: 3.2rem; text-align: center; }

/* Legenda de bairros: cor por região (COR_REGIAO) + nome, link pra
   página de texto do bairro (cidade.php?regiao=slug). */
.legenda-bairros {
    display: flex; flex-wrap: wrap; gap: .5rem .9rem;
    list-style: none; margin: 1rem 0;
}
.legenda-bairros a {
    display: inline-flex; align-items: center; gap: .4rem;
    font-size: .88rem; color: var(--color-text);
}
.legenda-cor {
    display: inline-block; width: .8rem; height: .8rem;
    border-radius: 3px; flex-shrink: 0; vertical-align: middle;
}

/* -- 10. Editor -- */
.cabecalho-editor { margin-bottom: 1.4rem; }
.titulo-doc {
    font-family: var(--font-headings); font-size: 1.7rem; text-transform: uppercase;
    letter-spacing: .01em;
    border: 0; background: transparent; padding: .15rem 0;
    border-bottom: 1px solid transparent; border-radius: 0;
}
.titulo-doc:hover { border-bottom-color: var(--glass-border); }
.titulo-doc:focus { box-shadow: none; border-bottom-color: var(--color-accent); }

.barra-doc {
    display: flex; flex-wrap: wrap; gap: .4rem 1rem;
    font-size: .82rem; color: var(--color-text-muted); margin-top: .5rem; align-items: center;
}
.progresso { height: 2px; background: var(--glass-border); border-radius: 999px; overflow: hidden; margin-top: .7rem; }
.progresso > i {
    display: block; height: 100%; background: var(--color-secondary);
    box-shadow: var(--shadow-secondary); transition: width .35s;
}

/* Navegação por fase do desafio (#32) — uma carta por vez, não a lista
   inteira exposta; ver Cartas::pontuar e docs/jogo-de-fragmentos.md. */
.fase-nav {
    display: flex; align-items: center; gap: .75rem;
    margin: 1rem 0; flex-wrap: wrap;
}
.fase-pontos {
    display: flex; gap: .35rem; flex: 1; flex-wrap: wrap; justify-content: center;
}
.fase-ponto {
    width: 1.8rem; height: 1.8rem; border-radius: 999px; font-size: .75rem;
    border: 1px solid var(--glass-border); background: transparent;
    color: var(--color-text-muted); cursor: pointer;
}
.fase-ponto.visitada { border-color: var(--color-accent); color: var(--color-accent); }
.fase-ponto.atual { background: var(--color-accent); color: var(--color-surface); font-weight: 700; }
.fase-ponto.bloqueada { opacity: .35; cursor: not-allowed; }

.fragmento {
    background: var(--color-surface);
    border: 1px solid var(--glass-border);
    border-left: 2px solid transparent;
    border-radius: var(--raio); padding: .8rem 1rem; margin-bottom: .7rem;
    transition: border-color .2s, box-shadow .2s;
}
.fragmento.focado {
    border-color: var(--glass-border);
    border-left-color: var(--color-primary);
    box-shadow: -2px 0 12px rgba(0, 255, 255, .25);
}
.fragmento-topo {
    display: flex; align-items: center; gap: .65rem;
    font-size: .75rem; color: var(--color-text-muted); margin-bottom: .45rem;
}
.fragmento-topo .num {
    font-family: var(--font-headings); font-size: .95rem;
    color: var(--color-accent); line-height: 1;
}
.fragmento-topo .espaco { flex: 1; }
.fragmento-topo .carta-nome {
    color: var(--color-accent); font-weight: 600;
}
.fragmento-topo .credito {
    font-family: var(--font-headings); min-width: 2.8em; text-align: right;
}
.fragmento textarea {
    font-family: var(--font-leitura); font-size: 1.02rem; line-height: 1.7;
    border: 0; background: transparent; padding: 0; resize: none;
    min-height: 4.5rem; overflow: hidden;
}
.fragmento textarea:focus { box-shadow: none; }
.fragmento .acoes { display: flex; gap: .15rem; opacity: 0; transition: opacity .2s; }
.fragmento:hover .acoes, .fragmento.focado .acoes { opacity: 1; }
.fragmento .acoes button { padding: .1rem .4rem; font-size: .8rem; }
.fragmento .acoes button:disabled { opacity: .35; cursor: default; }

/* Marcas de fragmento (#151) — etapa, papel e nota, só do dono: nunca
   conta palavra, nunca aparece na foto pública, no export nem na revisão
   (o servidor nem seleciona estas colunas fora do editor). SEMPRE visível
   (ao contrário de `.acoes`, que só aparece no hover) — é estado, não ação
   de passagem. */
.fragmento-marca {
    display: flex; align-items: center; gap: .4rem; flex-wrap: wrap;
    margin-bottom: .5rem; font-size: .76rem;
}
.marca-etapa {
    padding: .12rem .55rem; border-radius: 999px;
    border: 1px solid var(--glass-border); background: transparent;
    color: var(--color-text-muted); font-size: .76rem;
}
.marca-etapa.tem-marca {
    border-color: var(--color-accent); color: var(--color-accent);
}
.marca-etapa:disabled { opacity: .5; cursor: default; }
.fragmento-marca select {
    width: auto; min-width: 7rem;
    font-size: .76rem; padding: .1rem .3rem; color: var(--color-text-muted);
    background: transparent; border: 1px solid var(--glass-border); border-radius: var(--raio);
}
.marca-nota-toggle {
    font-size: .76rem; color: var(--color-text-muted); background: transparent;
    border: 0; padding: .1rem .2rem; max-width: 16rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.marca-nota-toggle:hover, .marca-nota-toggle:focus-visible { color: var(--color-text); }
.marca-nota-toggle.vazia { opacity: .55; }
.marca-nota-input {
    font-size: .76rem; padding: .1rem .4rem; min-width: 12rem;
    border: 1px solid var(--glass-border); border-radius: var(--raio);
    background: var(--color-surface);
}

/* conto interativo: seletor de kind + campos por peca */
.fragmento-kind {
    margin-top: .55rem; padding-top: .5rem; border-top: 1px dashed var(--glass-border);
    font-size: .78rem; color: var(--color-text-muted);
}
.fragmento-kind select {
    font-size: .8rem; padding: .15rem .4rem; margin-left: .35rem;
}
.fragmento-kind-campos { margin-top: .5rem; display: grid; gap: .4rem; }
.fragmento-kind-campos .kind-linha {
    display: grid; gap: .35rem; grid-template-columns: 1fr 1fr auto;
    align-items: start; padding: .4rem .5rem; border: 1px solid var(--glass-border);
    border-radius: var(--raio); background: var(--glass-bg);
}
.fragmento-kind-campos .kind-linha textarea {
    grid-column: 1 / -1; min-height: 3rem; font-family: var(--font-leitura);
    font-size: .92rem; line-height: 1.5;
    padding: .35rem .5rem; border: 1px solid var(--glass-border); border-radius: var(--raio);
    background: var(--color-surface); resize: vertical;
}
.fragmento-kind-campos input {
    font-size: .82rem; padding: .25rem .5rem;
    border: 1px solid var(--glass-border); border-radius: var(--raio);
    background: var(--color-surface);
}
.fragmento-kind-campos label {
    font-size: .78rem; color: var(--color-text-muted); display: inline-flex;
    align-items: center; gap: .3rem; margin-right: .6rem;
}
.fragmento-kind-campos [data-kind-adicionar] { justify-self: start; }

/* Duas abas no mesmo documento (#150) — o fragmento em conflito para de
   autogravar (o texto continua editável, só não tenta gravar sozinho até
   o dono decidir) e ganha borda de alerta, igual à cor de erro. */
.fragmento.em-conflito { border-left-color: var(--color-danger); }
.fragmento-conflito {
    margin-bottom: .6rem; padding: .6rem .7rem;
    border: 1px solid var(--color-danger); border-radius: var(--raio);
    background: var(--glass-bg); font-size: .85rem;
}
.fragmento-conflito p { margin: 0 0 .4rem; }
.fragmento-conflito-salvo-label {
    color: var(--color-text-muted); font-size: .78rem; margin-bottom: .2rem;
}
.fragmento-conflito-salvo {
    max-height: 8rem; overflow-y: auto; white-space: pre-wrap;
    font-family: var(--font-leitura); padding: .4rem .55rem; margin-bottom: .5rem;
    border: 1px solid var(--glass-border); border-radius: var(--raio);
    background: var(--color-surface);
}
.fragmento-conflito-acoes { display: flex; gap: .5rem; flex-wrap: wrap; }

.fragmento-adiado {
    min-height: 8rem; display: flex; align-items: center; justify-content: center;
    color: var(--color-text-muted); font-size: .82rem;
    border-left-color: transparent;
}

.estado-salvo { font-size: .78rem; min-height: 1.2em; letter-spacing: .02em; }
.estado-salvo.salvando { color: var(--color-primary); }
.estado-salvo.salvo    { color: var(--color-secondary); text-shadow: var(--shadow-secondary); }
.estado-salvo.falhou   { color: var(--color-danger); }

/* -- 11. Respeitar quem prefere menos movimento -- */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* -- 12. Realce de markdown (overlay) ----------------------------------
   O <pre> fica atrás e mostra o texto colorido; o <textarea> fica em cima,
   transparente, e recebe a digitação.

   As métricas dos dois têm que ser IDÊNTICAS — fonte, tamanho, entrelinha,
   espaçamento entre letras, padding, quebra de linha e tabulação. Qualquer
   divergência desalinha o que você vê do que você digita, e o erro cresce ao
   longo do parágrafo. Por isso as propriedades comuns ficam num seletor só.  */

.md-caixa { position: relative; }

.md-caixa > .md-realce,
.md-caixa > .md-entrada {
    font-family: var(--font-leitura);
    font-size: 1.02rem;
    /* Valor absoluto, não razão: um número sem unidade (ex.: "1.7") é herdado
       como razão e cada descendente recalcula pelo PRÓPRIO font-size — é o que
       faz a linha do título (font-size maior em .md-titulo) ficar mais alta só
       no <pre>, já que o <textarea> por trás não tem spans de tamanhos
       diferentes. Fixando em rem, o valor herdado já vem calculado e as duas
       camadas não podem mais divergir linha a linha. */
    line-height: calc(1.02rem * 1.7);
    letter-spacing: normal;
    tab-size: 4;
    margin: 0;
    padding: 0;
    border: 0;
    white-space: pre-wrap;
    word-break: break-word;
    overflow-wrap: break-word;
}

.md-caixa > .md-realce {
    position: absolute; inset: 0;
    overflow: hidden;
    pointer-events: none;
    color: var(--color-text);
    background: transparent;
}

.md-caixa > .md-entrada {
    position: relative;
    display: block;
    width: 100%;
    min-height: 4.5rem;
    resize: none;
    overflow: hidden;
    background: transparent;
    /* o texto vem do <pre> atrás; aqui só o cursor e a seleção aparecem */
    color: transparent;
    caret-color: var(--color-accent);
}
.md-caixa > .md-entrada:focus { outline: none; box-shadow: none; }
.md-caixa > .md-entrada::selection { background: color-mix(in srgb, var(--color-primary) 30%, transparent); }

/* Os marcadores continuam visíveis, só que apagados: o texto na tela é
   caractere a caractere igual ao do textarea, senão o alinhamento quebraria. */
.md-marca { color: var(--color-text-muted); opacity: .45; }

/* NADA que mude a largura de glifo: nem fonte, nem tamanho, nem PESO, nem
   ESTILO. A versão anterior usava font-weight:700 no título/negrito e
   font-style:italic na ênfase, com um comentário afirmando que peso não
   muda a métrica — vale para a altura, não para a largura: medido via
   canvas no site real (Lora 1.02rem, linha de 49 caracteres), o 700 é
   +3,07px e a itálica é −3,35px em relação ao regular do textarea — o
   cursor desalinha e o erro cresce com a linha (#98). O text-stroke
   parecia seguro pela mesma razão (não muda o avanço do glifo), mas o
   dono via ele como "negrito de leve" — #161 tirou o stroke também: só
   cor e opacidade distinguem a marcação agora, sem nada que pareça mudar
   a letra. A ênfase fica marcada pelos asteriscos apagados. */
.md-titulo { color: var(--color-accent); }
.md-h2 { color: var(--color-text); }
.md-h3 { color: var(--color-text); opacity: .85; }

.md-negrito { color: var(--color-primary); }
.md-italico { color: var(--color-secondary); }
.md-riscado { text-decoration: line-through; opacity: .7; }

/* Mesma razão do título acima: sem font-family/font-size próprios, senão a
   largura de cada caractere diverge da fonte de leitura por baixo e o cursor
   desalinha horizontalmente a partir da primeira crase — pior que o título,
   porque aqui pode ter texto normal depois na mesma linha (código inline). */
.md-codigo, .md-codigo-bloco, .md-cerca { color: var(--color-secondary); }
.md-cerca { color: var(--color-text-muted); }

/* Sintaxe colorida por token dentro do bloco ```js (#30) — mesma regra:
   só cor, nunca font-family/font-size/letter-spacing. */
.md-palavra-chave { color: var(--color-primary); }
.md-string { color: var(--color-text); }
.md-numero { color: var(--color-accent); }
.md-comentario { color: var(--color-text-muted); }

/* Sem peso nem estilo — regra do #98, sem exceção: peso e itálica mudam a
   LARGURA dos glifos e desalinham o cursor do textarea. Sem stroke também
   (#161): a lista se distingue só pela cor. */
.md-lista { color: var(--color-accent); }
.md-citacao { color: var(--color-text-muted); }
.md-link { color: var(--color-primary); }
.md-url { color: var(--color-text-muted); opacity: .7; text-decoration: underline; }

/* Redundante hoje (a entrelinha da base já é um valor absoluto, ver acima) —
   mantido explícito para não recriar o bug: "inherit" sobre uma razão sem
   unidade NÃO trava nada, cada descendente recalcula pelo próprio font-size. */
.md-caixa > .md-realce .md-titulo,
.md-caixa > .md-realce .md-codigo,
.md-caixa > .md-realce .md-codigo-bloco { line-height: inherit; }

/* -- 13. Menu de tipo no "Novo texto" ----------------------------------
   O tipo passou a ser escolhido aqui, e não herdado do filtro. Ver #14:
   `min_fragments` difere por tipo, então o documento nasce com 10
   fragmentos ou com 1 — decisão que molda o objeto e não se desfaz
   depois. Por isso ela é explícita, com o nome e a descrição de cada
   tipo à vista.                                                        */

.menu-novo { position: relative; }

/* PRECISA vir junto do `display: flex` abaixo. O atributo `hidden` esconde
   por uma regra do próprio navegador (`[hidden] { display: none }`), e regra
   de autor vence regra do navegador — sem esta linha o `display: flex`
   sobrepuja o `hidden` e o menu nunca fecha. Foi exatamente o que aconteceu:
   ele abria e ficava aberto para sempre, sem erro nenhum no console.        */
.menu-lista[hidden] { display: none; }

.menu-lista {
    position: absolute;
    top: calc(100% + .35rem);
    right: 0;
    z-index: 20;
    min-width: 15rem;
    padding: .3rem;
    display: flex;
    flex-direction: column;
    gap: .15rem;
    background: var(--color-surface);
    border: 1px solid var(--glass-border);
    border-radius: var(--raio);
    box-shadow: 0 .5rem 1.5rem rgba(0, 0, 0, .45);
}

.menu-lista > button {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: .1rem;
    width: 100%;
    text-align: left;
    padding: .5rem .6rem;
    border: 0;
    border-radius: calc(var(--raio) - .2rem);
    background: transparent;
    color: var(--color-text);
}
/* `:focus`, não só `:focus-visible`: aqui o foco é o cursor de seleção do
   menu, e precisa aparecer venha de onde vier. Com `:focus-visible` sozinho,
   navegar por setas movia o foco sem nada mudar na tela.                  */
.menu-lista > button:hover,
.menu-lista > button:focus {
    background: color-mix(in srgb, var(--color-accent) 14%, transparent);
    color: var(--color-text);
    outline: none;
}
.menu-lista > button > strong {
    font-family: var(--font-headings);
    text-transform: uppercase;
    letter-spacing: .04em;
    font-weight: 500;
}
/* `gap` só separa ELEMENTOS: a descrição precisa do <span> para não
   grudar no nome — texto solto viraria um nó anônimo, que o flex ignora. */
.menu-lista > button > span {
    font-size: .8rem;
    color: var(--color-text-muted);
    text-transform: none;
    letter-spacing: normal;
}
.menu-lista > button[aria-disabled="true"] { opacity: .5; pointer-events: none; }

/* -- 14. Tags no editor ------------------------------------------------
   O × fica DENTRO da etiqueta, como <button>: clicável, alcançável por
   teclado e com rótulo próprio para leitor de tela. Um <span> com
   onclick não teria nada disso.                                        */

.tags-campo {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .4rem;
    margin-top: .6rem;
}
.taxonomia-campo {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    margin-top: .4rem;
}
.tags-campo > #tags-lista {
    display: contents;   /* as etiquetas participam do mesmo flex/gap */
}
.etiqueta-tag {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
}
.etiqueta-tag > button {
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font-size: 1rem;
    line-height: 1;
    opacity: .6;
}
.etiqueta-tag > button:hover,
.etiqueta-tag > button:focus-visible {
    opacity: 1;
    color: var(--color-danger);
    box-shadow: none;
}
#tags-nova {
    width: 8rem;
    padding: .2rem .5rem;
    font-size: .85rem;
    background: transparent;
    border: 1px dashed var(--glass-border);
}
#tags-nova:focus { border-style: solid; }

/* -- 15. Página pública ------------------------------------------------
   Render dinâmico, sem gerar arquivo — ver src/Publicacao.php. Aqui só o
   texto importa: sem topo, sem ações, sem nada em que clicar por engano. */

/* Depois de `.envelope` no arquivo de proposito: mesma especificidade,
   quem vem depois ganha — e a leitura fica mais estreita que o app. */
.publicado { max-width: var(--largura-leitura); }

.publicado h1 { font-size: 2rem; margin-bottom: .5rem; text-transform: none; }

.publicado-autor {
    color: var(--color-text-muted);
    font-size: .95rem;
    margin-bottom: .6rem;
}

.publicado-meta {
    display: flex;
    flex-wrap: wrap;
    gap: .9rem;
    color: var(--color-text-muted);
    font-size: .85rem;
    padding-bottom: 1.2rem;
    margin-bottom: 1.6rem;
    border-bottom: 1px solid var(--glass-border);
}

.publicado-fragmento { margin-bottom: 2rem; }
.publicado-fragmento h2 {
    font-size: 1.05rem;
    color: var(--color-text-muted);
    margin-bottom: .5rem;
}
/* Marca a fronteira do fragmento sem virar card (#20 -- a foto e' pra
   leitura, o card e' coisa de editor). So o numero, discreto. */
.fragmento-num {
    display: block;
    font-family: var(--font-headings);
    font-size: .85rem;
    color: var(--color-accent);
    margin-bottom: .3rem;
}

/* `pre-wrap` preserva as quebras que o autor escreveu sem exigir que o
   servidor invente <p>. O texto sai escapado e o realce é aplicado depois,
   por JS — se ele não rodar, continua legível.                          */
.publicado-texto {
    font-family: var(--font-leitura);
    font-size: 1.08rem;
    line-height: 1.75;
    white-space: pre-wrap;
    word-break: break-word;
    overflow-wrap: break-word;
}

/* Saída, no topo (#51). O comentário no início desta seção diz "sem topo,
   sem ações, sem nada em que clicar por engano" — continua valendo, e é
   por isso que isto é um link só, apagado, e não uma barra de app. O
   padding dá alvo de dedo confortável sem desenhar caixa nenhuma. */
.publicado-topo {
    margin-bottom: 1.4rem;
    font-size: .85rem;
}
.publicado-topo a {
    color: var(--color-text-muted);
    text-decoration: none;
    letter-spacing: .03em;
    display: inline-block;
    padding: .4rem .1rem;   /* alvo de dedo sem virar caixa visível */
}
.publicado-topo a:hover, .publicado-topo a:focus-visible {
    color: var(--color-primary);
}

.publicado-rodape {
    margin-top: 3rem;
    padding-top: 1.2rem;
    border-top: 1px solid var(--glass-border);
    color: var(--color-text-muted);
    font-size: .85rem;
}

/* Sentinela de leitura completa (#58) -- 1px de altura, não 0: elemento
   totalmente vazio some da árvore de interseção em alguns navegadores. */
#leitura-sentinela { height: 1px; }

/* O destino de leitura vem antes do crédito e com mais peso que ele: é a
   resposta ao "e agora?", não uma assinatura de rodapé. */
.publicado-mais-autor {
    margin-bottom: .5rem;
    font-size: .95rem;
}

/* Aviso de "está público" dentro do editor. */
.publicado-aviso {
    margin-top: .6rem;
    font-size: .85rem;
    color: var(--color-text-muted);
    word-break: break-all;
}

/* Classificação de conteúdo adulto (#25). */
.rotulo-adulto {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    font-size: .85rem;
    color: var(--color-text-muted);
    cursor: pointer;
    user-select: none;
}
.intersticio-adulto {
    margin: 2.5rem 0;
    padding: 1.6rem 1.4rem;
    text-align: center;
}
.intersticio-adulto p { margin-bottom: 1rem; }
.intersticio-adulto p:last-child { margin-bottom: 0; }
.intersticio-adulto .botao-principal { display: inline-block; text-decoration: none; }

/* Fotos no editor e vitrine na página pública (#19). */
.foto-linha {
    display: block;
    margin-bottom: .2rem;
    word-break: break-all;
}
.foto-linha > button { font-size: .8rem; padding: .1rem .45rem; }
.publicado-irmas {
    margin: -.8rem 0 1.6rem;
    font-size: .85rem;
    color: var(--color-text-muted);
    display: flex;
    flex-wrap: wrap;
    gap: .7rem;
}

/* Perfil: placar mensal e lixeira (#9, #15). */
.envelope section > h2 {
    font-family: var(--font-headings);
    font-size: 1.5rem;
    letter-spacing: .04em;
    margin-bottom: .4rem;
}
.tabela-placar {
    width: 100%;
    border-collapse: collapse;
    font-size: .9rem;
    margin-top: 1rem;
}
.tabela-placar th {
    text-align: left;
    color: var(--color-text-muted);
    font-weight: 400;
    font-size: .8rem;
    text-transform: uppercase;
    letter-spacing: .06em;
}
.tabela-placar th, .tabela-placar td {
    padding: .45rem .8rem .45rem 0;
    border-bottom: 1px solid var(--glass-border);
}

.selo-conto {
    margin-top: 1rem; padding: .8rem 1rem;
    border: 1px solid var(--glass-border); border-radius: var(--raio);
    background: var(--glass-bg);
}
.selo-lista { list-style: none; margin: .4rem 0 0; padding: 0; font-size: .9rem; }
.selo-lista li { padding: .2rem 0; color: var(--color-text-muted); }

/* Revisão pública (#20): proposta nasce na página da foto; selinho é a
   única parte que vira pública, com crédito. */
.selinho {
    font-size: .8rem;
    color: var(--color-secondary);
    margin-top: .4rem;
}
/* Sugerir revisão e comentar são as duas ações possíveis num fragmento --
   ficam na mesma fileira, não empilhadas (o resto -- lista de comentários,
   formulários -- continua vindo abaixo). */
.fragmento-acoes { display: flex; gap: .6rem; align-items: center; margin-top: .4rem; }
.revisao-abrir { font-size: .8rem; }

/* -- Leitura interativa (conto interativo, fatia 2) -------------------- */
.leitura-controles { margin-top: .8rem; }

.fala-citacao { color: var(--color-accent); font-style: italic; }

.leitura-decisao { display: flex; flex-direction: column; gap: .5rem; }
.leitura-decisao button { text-align: left; }
.leitura-decisao button:disabled { opacity: .5; }
.leitura-decisao button.leitura-escolhida {
    opacity: 1; border-color: var(--color-accent); color: var(--color-accent);
}

.leitura-qte-pista {
    position: relative; height: 2.2rem; margin-bottom: .6rem;
    border: 1px solid var(--glass-border); border-radius: var(--raio);
    background: var(--glass-bg); overflow: hidden;
}
.leitura-qte-zona, .leitura-qte-zona-perfeita {
    position: absolute; top: 0; bottom: 0; left: 50%; transform: translateX(-50%);
}
.leitura-qte-zona { background: rgba(255, 20, 147, .12); }
.leitura-qte-zona-perfeita { background: rgba(255, 20, 147, .28); }
.leitura-qte-ponteiro {
    position: absolute; top: 0; bottom: 0; width: 2px;
    background: var(--color-accent); box-shadow: var(--shadow-accent);
}
.leitura-qte-resultado { margin-top: .5rem; font-weight: 600; color: var(--color-accent); }

.leitura-final {
    margin-top: .8rem; padding: 1rem 1.1rem;
    border: 1px solid var(--glass-border); border-radius: var(--raio);
    background: var(--glass-bg);
}
.leitura-final-badge {
    display: inline-block; margin-top: .3rem;
    padding: .3rem .7rem; border: 1px dashed var(--glass-border);
    border-radius: 999px; font-size: .85rem; color: var(--color-text-muted);
}
.leitura-final-badge-msg { margin-top: .4rem; font-size: .82rem; color: var(--color-text-muted); }
.leitura-zerar { margin-top: .8rem; }

/* Ritmo de leitura (#56) — o aviso vem ANTES do primeiro fragmento, e é
   discreto sem ser escondido: quem precisa do texto inteiro (Ctrl+F,
   leitor de tela, quem só quer bater o olho) tem de achar a saída sem
   procurar, mas ela não pode competir com o texto do autor. */
.ritmo-aviso {
    display: flex; flex-wrap: wrap; align-items: center; gap: .5rem;
    margin-bottom: 1.6rem;
    font-size: .85rem; color: var(--color-text-muted);
}
.ritmo-aviso button { font-size: .85rem; padding: .35rem .6rem; }

/* Galeria pública (#52). Grade de verdade: `.cartoes` da listagem é
   flex-column, uma por linha, e aqui os cartões são curtos. */
.galeria-intro {
    color: var(--color-text-muted);
    margin-bottom: 1.4rem;
}
.galeria-filtro {
    display: flex; flex-wrap: wrap; align-items: center; gap: .6rem;
    margin-bottom: 1.6rem;
}
.galeria-filtro select { width: auto; min-width: 10rem; }
.galeria-filtro label {
    display: inline; margin: 0;
    font-family: var(--font-headings); text-transform: uppercase;
    font-size: .8rem; color: var(--color-text-muted);
}
.galeria-grade {
    display: grid; gap: .9rem;
    grid-template-columns: 1fr;
}
@media (min-width: 42rem) {
    .galeria-grade { grid-template-columns: repeat(2, 1fr); }
}
.galeria-cartao h2 {
    font-size: 1.15rem; text-transform: none; margin-bottom: .25rem;
}
.galeria-cartao h2 a { text-decoration: none; }
.galeria-autor {
    font-size: .85rem; color: var(--color-text-muted); margin-bottom: .5rem;
}
.galeria-sinopse {
    font-family: var(--font-leitura); font-size: .95rem; line-height: 1.55;
    margin-bottom: .6rem;
}
/* Foto adulta não leva trecho do texto (mesma regra do preview, #48) —
   o cartão fica com a marca no lugar da sinopse, e a marca precisa ser
   lida como aviso, não como etiqueta decorativa. */
.galeria-adulta {
    font-size: .85rem; color: var(--color-danger);
    margin-bottom: .6rem; text-transform: uppercase; letter-spacing: .04em;
}
.galeria-paginas {
    display: flex; align-items: center; justify-content: center; gap: 1.2rem;
    margin-top: 2rem; font-size: .9rem;
}

/* Ensaio do conto no editor (#53). A caixa NÃO redefine `.publicado-*`
   nem `.leitura-*`: são as mesmas regras da página pública, e é isso que
   faz o teste valer — se aqui tivesse estilo próprio, o autor aprovaria
   uma tela que o leitor nunca vai ver. */
.teste-conto {
    position: fixed; inset: 0; z-index: 100;
    background: rgba(0, 0, 0, .72);
    overflow-y: auto;
    padding: 1.5rem 1rem 4rem;
}
.teste-conto-caixa {
    /* A MESMA largura da pagina publica: o ensaio so vale se mostrar a
       tela que o leitor vai ver. */
    max-width: var(--largura-leitura); margin: 0 auto;
    /* OPACO, e a variável certa é `--color-background` — com o nome errado
       a declaração é inválida, o fundo não existe e o editor aparece por
       trás do conto, ilegível. Não é decoração: a caixa é o que separa
       "estou ensaiando" de "estou editando". */
    background: var(--color-background);
    border: 1px solid var(--glass-border); border-radius: var(--raio);
    padding: 1.1rem 1.25rem 2rem;
}
.teste-conto-topo {
    display: flex; align-items: center; gap: .5rem;
    padding-bottom: .8rem; margin-bottom: .8rem;
    border-bottom: 1px solid var(--glass-border);
}
.teste-conto-aviso {
    font-size: .82rem; color: var(--color-text-muted);
    margin-bottom: 1.4rem;
}
.revisao-form { margin-top: .6rem; display: grid; gap: .5rem; }
.revisao-form .revisao-texto {
    width: 100%;
    font-family: var(--font-leitura);
    font-size: 1rem;
    line-height: 1.7;
    padding: .8rem;
    border: 1px solid var(--glass-border);
    border-radius: var(--raio);
    background: var(--glass-bg);
    color: var(--color-text);
    resize: vertical;
}
.revisao-aviso, .revisao-nota {
    font-size: .8rem;
    color: var(--color-text-muted);
}
.revisao-acoes { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }

.revisoes-titulo { font-family: var(--font-headings); margin: 1rem 0 .5rem; }
.revisao-item {
    border: 1px solid var(--glass-border);
    border-radius: var(--raio);
    background: var(--glass-bg);
    padding: .8rem;
    margin-bottom: .6rem;
    display: grid;
    gap: .5rem;
}
.revisao-item .meta {
    display: flex; gap: .8rem; flex-wrap: wrap;
    font-size: .8rem; color: var(--color-text-muted);
}
.revisao-conteudo {
    font-family: var(--font-leitura);
    white-space: pre-wrap;
    max-height: 16rem;
    overflow-y: auto;
}
.revisao-motivo-lida { font-size: .85rem; font-style: italic; color: var(--color-text-muted); }

/* Painel de revisão (revisao.php) e alternador na página da foto. */
.revisao-lado-a-lado {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: .8rem;
}
@media (max-width: 40rem) {
    .revisao-lado-a-lado { grid-template-columns: 1fr; }
}
.revisao-rotulo {
    font-size: .75rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--color-text-muted);
    margin-bottom: .3rem;
}
.revisao-status-aceita    { color: var(--color-secondary); }
.revisao-status-rejeitada { color: var(--color-danger); }
.revisao-alternar {
    display: inline-flex;
    gap: .4rem;
    margin-left: .6rem;
    flex-wrap: wrap;
}
.revisao-alternar > button { font-size: .75rem; padding: .1rem .45rem; }

/* Revisão por convite (#10): página do convidado (convite.php) e o bloco
   de administração de convites no editor. */
.convite-explica { color: var(--color-text-muted); font-size: .9rem; margin-bottom: 1rem; }
.convite-senha { display: flex; gap: .5rem; flex-wrap: wrap; }
.convite-senha input {
    padding: .55rem .8rem;
    border: 1px solid var(--glass-border);
    border-radius: var(--raio);
    background: var(--glass-bg);
    color: var(--color-text);
}
.convite-sugestao {
    border-left: 2px solid var(--glass-border);
    padding: .4rem 0 .4rem .8rem;
    margin-top: .5rem;
    font-size: .95rem;
}
.convites-bloco { padding-left: 1rem; }
.convite-linha { display: block; margin-bottom: .25rem; word-break: break-all; }
.convite-linha > button { font-size: .8rem; padding: .1rem .45rem; }
.convite-novo input {
    font-size: .85rem;
    padding: .25rem .5rem;
    border: 1px solid var(--glass-border);
    border-radius: var(--raio);
    background: var(--glass-bg);
    color: var(--color-text);
    max-width: 11rem;
}

/* Termos de uso (#24): um documento para ler — tipografia de leitura,
   nada em que clicar por engano. */
.termos { max-width: 46rem; }
.termos h1 { margin-bottom: .3rem; }
.termos h2 { font-size: 1.05rem; margin: 1.6rem 0 .5rem; }
.termos p, .termos li {
    font-family: var(--font-leitura);
    line-height: 1.7;
}
.termos p { margin-bottom: .8rem; }
.termos ul, .termos ol { padding-left: 1.4rem; margin-bottom: .8rem; }

/* -- 16. Toque (#49) ----------------------------------------------------

   Vai no FIM do arquivo de propósito: sobrescreve padding e font-size de
   regras de mesma especificidade lá em cima, e só a ordem decide.

   `pointer: coarse` é o ponteiro PRIMÁRIO — notebook com tela sensível e
   mouse continua `fine`, e não entra aqui. Não é largura de tela: tablet
   grande tem dedo, e janela estreita no desktop não tem.

   Dois defeitos, a mesma causa — os controles do editor foram desenhados
   para o mouse:

   1. `.acoes` vive em `opacity: 0` até `:hover`. No toque não existe
      hover, então os botões só apareciam com o fragmento focado — e
      sumiam DEBAIXO DO DEDO ao serem tocados, porque tocar o botão tira
      o foco do textarea. O clique até acontecia (opacidade não bloqueia
      toque), mas quem está usando não tem como saber disso.
   2. Alvos de ~22px, onde a recomendação de toque é ~44px (2.75rem).

   No desktop nada muda: as regras de cima continuam valendo sozinhas. */
@media (pointer: coarse) {
    /* Sempre visíveis: sem hover, esconder é esconder para sempre. */
    .fragmento .acoes { opacity: 1; gap: .3rem; }
    .fragmento .acoes button {
        min-width: 2.75rem; min-height: 2.75rem;
        padding: .3rem; font-size: 1.05rem;
        justify-content: center;
    }
    /* Quatro alvos de 44px não cabem ao lado da contagem numa tela de
       360px — sem isto o `.palavras` seria espremido até sumir. */
    .fragmento-topo { flex-wrap: wrap; }

    /* O × da tag era o alvo mais fino da tela inteira: `padding: 0` num
       glifo de 1rem. A pílula cresce junto, e é ela que o dedo mira. */
    .etiqueta-tag { padding-right: .2rem; }
    .etiqueta-tag > button {
        min-width: 2rem; min-height: 2rem;
        justify-content: center; opacity: .85;
    }
    /* Marcas de fragmento (#151): mesmo alvo mínimo de 44px do resto desta
       seção — o botão de etapa cicla a cada toque, e um alvo fino faria
       ciclar demais de propósito. */
    .marca-etapa, .marca-nota-toggle { min-height: 2.2rem; padding: .3rem .6rem; }
    .fragmento-marca select { min-height: 2.2rem; }
    /* Excluir/restaurar em massa (#154): o checkbox nativo tem uns 16px —
       o alvo real é a área ao redor dele, alargada pra 44px sem mudar o
       glifo visível (padding cresce, o quadradinho em si não). */
    .cartao-check { width: 1.6rem; height: 1.6rem; margin: .7rem; }
    .barra-selecao button { min-height: 2.75rem; padding: .4rem .8rem; }
    /* Os meus ambientes (#155): mesmo alvo mínimo do resto desta seção. */
    .ambiente-acoes button, .ambiente-acoes select { min-height: 2.75rem; padding: .4rem .7rem; }
}
.termos li { margin-bottom: .35rem; }
.termos-versao { color: var(--color-text-muted); font-size: .85rem; margin-bottom: 1.4rem; }
.termos-contato {
    margin-top: 2rem;
    padding-top: 1.2rem;
    border-top: 1px solid var(--glass-border);
}
.termos-aceite {
    margin-top: 1.6rem;
    padding: 1rem;
    border: 1px solid var(--glass-border);
    border-radius: var(--raio);
    background: var(--glass-bg);
}
.termos-aceite p { margin-bottom: .6rem; }
.revisao-alternar > button[aria-pressed="true"] {
    border-color: var(--color-secondary);
    color: var(--color-secondary);
}

/* Topo responsivo: a MESMA navegação em duas apresentações, decididas por
   media query. No desktop, links inline e o ☰ some; no mobile, os links
   somem e o ☰ abre tudo — quatro botões + logo estouravam a largura. */
.topo-nav { display: flex; align-items: center; gap: 1rem; }
.topo-burger { display: none; }
@media (max-width: 44rem) {
    .topo { gap: .5rem; padding: .6rem .8rem; }
    .topo-nav { display: none; }
    .topo-burger { display: inline-flex; }
}

/* Itens de navegação dentro de .menu-lista são <a>, não <button> — link é
   link. Mesmo visual dos botões do menu. */
.menu-lista > a {
    display: block;
    width: 100%;
    padding: .5rem .6rem;
    border-radius: calc(var(--raio) - .2rem);
    text-decoration: none;
    color: var(--color-text);
}
.menu-lista > a:hover,
.menu-lista > a:focus {
    background: color-mix(in srgb, var(--color-accent) 14%, transparent);
    outline: none;
}
.menu-lista > a > strong,
.menu-lista > button[data-sair] > strong {
    font-family: var(--font-headings);
    text-transform: uppercase;
    letter-spacing: .04em;
    font-weight: 500;
}

/* Comentários na foto (#17): conversa pública ancorada no fragmento. */
.comentarios { margin-top: .8rem; display: grid; gap: .5rem; }
.comentario {
    border-left: 2px solid var(--glass-border);
    padding: .3rem 0 .3rem .8rem;
    display: grid;
    gap: .3rem;
}
.comentario .meta {
    display: flex; gap: .8rem; flex-wrap: wrap; align-items: center;
    font-size: .8rem; color: var(--color-text-muted);
}
.comentario .meta > button { font-size: .75rem; padding: .1rem .45rem; }
.comentario .meta > button[aria-pressed="true"] {
    border-color: var(--color-secondary);
    color: var(--color-secondary);
}
.comentario-texto { font-family: var(--font-leitura); white-space: pre-wrap; }
.comentario-oculto { opacity: .55; }
.comentario-abrir { font-size: .8rem; justify-self: start; }
.comentario-form { display: grid; gap: .5rem; }
.comentario-form textarea {
    width: 100%;
    min-height: 5rem;
    font-family: var(--font-leitura);
    padding: .8rem;
    border: 1px solid var(--glass-border);
    border-radius: var(--raio);
    background: var(--glass-bg);
    color: var(--color-text);
    resize: vertical;
}
.comentarios-gerais { margin-top: 2.5rem; }
.comentarios-gerais > h2 {
    font-family: var(--font-headings);
    font-size: 1.3rem;
    margin-bottom: .5rem;
}

/* Aviso em linha de campo (#74) — nunca toast: o autosave grava a cada
   tecla, e um toast por tecla enche a tela enquanto a pessoa digita. */
.campo-aviso { display: block; margin-top: .25rem; color: var(--color-danger); font-size: .8rem; }
.campo-aviso:empty { display: none; }

/* -- Fragmento de imagem no conto interativo (#74) --
   Tres layouts, duas filosofias: `faixa` e `retrato` PADRONIZAM a forma
   (`aspect-ratio` + `object-fit: cover` — o corte e do enquadramento);
   `lado` respeita o conteudo e mostra a imagem inteira, porque la ela
   divide a cena com o texto em vez de emoldura-lo. */
.fragmento-imagem { margin: 1.4rem 0; }
.fragmento-imagem figure { margin: 0; }
.fragmento-imagem img {
    display: block; width: 100%; height: auto;
    border-radius: var(--raio);
    background: var(--color-surface);
}
.fragmento-imagem figcaption {
    margin-top: .4rem;
    color: var(--color-text-muted);
    font-size: .85rem; font-style: italic;
}

/* FAIXA: a imagem vira uma tira larga, sempre da mesma altura. */
.imagem-faixa img { aspect-ratio: 21 / 9; object-fit: cover; }

/* LADO A LADO: a imagem flutua e o texto respeita o conteudo. Sem
   `aspect-ratio` aqui — o enquadramento forcado decapitava retratos no
   celular (pedido do dono, 2026-08-04). A imagem aparece INTEIRA, no
   proprio formato, reduzida a meia coluna; o texto corre ao lado e,
   quando passa da altura dela, desce preenchendo a largura toda — o
   float faz os tres movimentos sozinho, em qualquer largura de tela. */
.imagem-lado figure { float: left; width: min(45%, 20rem); margin: 0 1.1rem .5rem 0; }
.imagem-lado::after { content: ''; display: block; clear: both; }
/* Espelhado: imagem a direita, texto a esquerda. So inverte o float e a
   margem; todo o resto vem de `.imagem-lado`, que o JS mantem junto. */
.imagem-lado-direita figure { float: right; margin: 0 0 .5rem 1.1rem; }

/* RETRATO: o icone de dialogo de jogo. Tamanho FIXO, nao proporcional —
   e' o que faz dele um icone e nao uma ilustracao: a imagem para de
   competir com o texto e vira quem esta falando.
   Continua lado a lado no celular, ao contrario do `lado`: 5rem cabem em
   qualquer tela, e empilhar quebraria justamente a leitura de dialogo. */
.imagem-retrato { display: grid; grid-template-columns: 6.5rem 1fr; gap: 1rem; align-items: start; }
.imagem-retrato img {
    aspect-ratio: 1; object-fit: cover;
    border: 2px solid var(--glass-border);
}
.imagem-retrato .imagem-texto { align-self: center; }
@media (max-width: 42rem) {
    .imagem-retrato { grid-template-columns: 5rem 1fr; gap: .8rem; }
}

/* Imagem que morreu (o Imgur apaga, e a foto e imutavel): quadro sobrio
   com a descricao, nunca o icone quebrado do navegador — feio e mudo. */
.imagem-quebrada {
    display: flex; align-items: center; justify-content: center;
    min-height: 8rem; padding: 1rem; margin: 0;
    border: 1px dashed var(--glass-border); border-radius: var(--raio);
    color: var(--color-text-muted); font-style: italic; text-align: center;
}
.campo-nota { display:block; margin-top:.3rem; color: var(--color-text-muted); font-size: .8rem; }

/* -- Paleta da fala (#74) --
   Duas versoes por cor: a de cima vale no escuro, a de baixo o tema claro
   sobrescreve. Uma cor so nao serve aos dois — o que le bem sobre preto
   some sobre branco, e a foto e IMUTAVEL: fala ilegivel publicada nao se
   conserta, so se tira outra foto. Por isso paleta e nao seletor livre.
   Cor nova aqui exige a linha correspondente em src/Fala.php. */
.fala-cor-ambar    .fala-citacao { color: #f0b429; text-shadow: none; }
.fala-cor-turquesa .fala-citacao { color: #2ec4b6; text-shadow: none; }
.fala-cor-lilas    .fala-citacao { color: #b388ff; text-shadow: none; }
.fala-cor-coral    .fala-citacao { color: #ff7a6b; text-shadow: none; }
.fala-cor-verde    .fala-citacao { color: #7bd88f; text-shadow: none; }
.fala-cor-ceu      .fala-citacao { color: #6ec1ff; text-shadow: none; }

[data-theme="light"] .fala-cor-ambar    .fala-citacao { color: #8a5a00; }
[data-theme="light"] .fala-cor-turquesa .fala-citacao { color: #0f6f66; }
[data-theme="light"] .fala-cor-lilas    .fala-citacao { color: #5b3ea8; }
[data-theme="light"] .fala-cor-coral    .fala-citacao { color: #b03a2e; }
[data-theme="light"] .fala-cor-verde    .fala-citacao { color: #2e7d43; }
[data-theme="light"] .fala-cor-ceu      .fala-citacao { color: #1565a0; }

/* -- Caixa de marcar dentro dos campos de peca (#73) --
   Duas regras da folha base atrapalham um checkbox aqui: `input {width:100%}`
   estica a caixinha ate a linha inteira, e `label {display:block;
   text-transform:uppercase}` joga o texto para a linha de baixo, em caixa
   alta, como se fosse rotulo de campo. Isso e classe, e nao estilo inline
   como nas outras telas: aqui ha mais de um uso, e inline se repete errado. */
.campo-corte {
    display: inline-flex; align-items: center; gap: .45rem;
    margin: .1rem 0 .6rem; cursor: pointer;
    font-family: var(--font-main); text-transform: none;
    font-size: .85rem; color: var(--color-text-muted);
}
.campo-corte input { width: auto; margin: 0; flex: none; }
.campo-corte[hidden] { display: none; }
/* Ouvir e corte seco pertencem a MESMA decisao (a trilha da cena), entao
   moram na mesma linha — soltos, pareciam dois campos sem relacao. */
.linha-trilha { display: flex; align-items: center; gap: .8rem; flex-wrap: wrap; margin-bottom: .6rem; }

/* ======================================================================
   Coluna de referências (#122) — comparar é ler, nunca edita.

   GAVETA EM QUALQUER LARGURA, SEMPRE — sem exceção de desktop largo (a
   versão anterior tinha um `@media` que virava a coluna num grid
   estático ali, e SÓ NO COMENTÁRIO dizia "fixed sempre"; a frase era
   falsa, o CSS é que mandava. Removido porque o dono, vendo a coluna
   funcionando, preferiu a gaveta em toda largura: um grid reservando
   20rem permanentemente é largura de escrita paga o tempo todo, mesmo
   sem nenhuma referência fixada.

   `position: fixed` de verdade agora — nunca entra no fluxo que
   `.envelope`/`#fragmentos` usa pra medir (autoAltura, #101). "Nunca
   empurra o editor" vem de CONSTRUÇÃO, e agora sem condição nenhuma pra
   quebrar essa garantia por engano. Ao abrir, quem se move é o EDITOR,
   por `transform` (nunca largura/margem) em `.pagina-com-referencias >
   .envelope` — transform não gera reflow, o autoAltura nem fica
   sabendo. Fechada: coluna fora da tela por `transform`, não
   `display:none` — troca de estado é só CSS.
   ====================================================================== */

.pagina-com-referencias { position: relative; overflow-x: hidden; }
.pagina-com-referencias > .envelope { transition: transform .22s ease; }
.pagina-com-referencias.referencias-abertas > .envelope { transform: translateX(-10rem); }

.referencias-coluna {
    position: fixed; top: 0; right: 0; bottom: 0; z-index: 150;
    width: 20rem; max-width: 88vw;
    display: flex; flex-direction: column; gap: .7rem;
    padding: 1rem; overflow-y: auto;
    background: var(--color-surface);
    border-left: 1px solid var(--glass-border);
    box-shadow: -8px 0 24px rgba(0,0,0,.35);
    transform: translateX(100%);
    transition: transform .22s ease;
}
.referencias-coluna[data-aberta="1"] { transform: translateX(0); }

.referencias-topo { display: flex; align-items: center; gap: .5rem; }
.referencias-topo strong { flex: 1; font-family: var(--font-headings); letter-spacing: .02em; }

#referencias-busca { width: 100%; margin: 0; }
#referencias-resultados:not(:empty) {
    display: flex; flex-direction: column; gap: .3rem;
    padding-bottom: .7rem; border-bottom: 1px solid var(--glass-border);
}
.referencia-resultado { display: block; width: 100%; text-align: left; }

/* Mesma peça de `.filtros-sanfona` (#54): `<details>` nativo, JS só liga
   o clique de remover. O corpo fica pre-wrap/font de leitura como
   `.publicado-texto` (p.php) — é leitura de verdade, não rascunho. */
.referencia-item { border-bottom: 1px solid var(--glass-border); padding-bottom: .4rem; }
.referencia-item > summary {
    cursor: pointer; list-style-position: inside;
    display: flex; align-items: center; gap: .4rem;
    padding: .4rem 0; font-size: .92rem;
}
.referencia-item > summary:hover { color: var(--color-primary); }
.referencia-item > summary span { flex: 1; }
.referencia-remover { flex: none; }
.referencia-item-corpo { margin-top: .3rem; }

/* Segundo nível de sanfona (#123) — o fragmento, dentro do documento.
   NÃO é um segundo <details> aninhado: esta sessão não conseguiu provar
   em navegador nenhum (nem sandbox, nem o Chrome real do dono — toda
   aba chegou "hidden", sem compositor ativo rodando; screenshot chegou
   a estourar timeout) que dois níveis de <details> aninhados abrem
   juntos no Ctrl+F. Sem prova, usa-se a alternativa que a Clarice já
   tinha aprovado para este caso: `hidden="until-found"` no corpo, a
   primitiva feita exatamente para isto, independente de aninhar
   <details>. `text-overflow:ellipsis` só CORTA VISUALMENTE o resumo —
   o corpo inteiro segue no DOM, e quem garante o Ctrl+F com ele fechado
   é o `hidden="until-found"`, não o corte visual. */
.referencia-fragmento-item {
    padding-bottom: .5rem; margin-bottom: .5rem;
    border-bottom: 1px dashed var(--glass-border);
}
.referencia-fragmento-item:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }
.referencia-fragmento-resumo {
    display: block; width: 100%; text-align: left;
    background: none; border: none; font: inherit;
    cursor: pointer; color: var(--color-text-muted);
    font-size: .82rem; padding: .3rem 0;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.referencia-fragmento-resumo:hover { color: var(--color-primary); }
.referencia-fragmento-corpo {
    font-family: var(--font-leitura); font-size: .92rem; line-height: 1.65;
    white-space: pre-wrap; word-break: break-word;
    margin-top: .3rem;
}

.referencias-flutuante {
    position: fixed; right: 1rem; bottom: 1rem; z-index: 140;
    border-radius: 999px; padding: .7rem 1.15rem;
    box-shadow: 0 8px 24px rgba(0,0,0,.4);
}
