@import url('https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;1,6..72,400&family=Instrument+Sans:wght@400;500;600&display=swap');

:root {
  --bg: #FAFAF9;
  --surface: #FFFFFF;
  --ink: #171613;
  --ink-soft: #65635B;
  --accent: #6E1E24;
  --line: #E9E7E0;
  --danger: #7A2E2E;

  /* Linha do tempo de atividade (perfil público) — 4 cores categóricas
     validadas (contraste, banda de luminosidade, separação CVD) com
     scripts/validate_palette.js da skill dataviz. Não trocar sem
     revalidar: node validate_palette.js "<hex,hex,hex,hex>" --mode light/dark.
     --activity-user (verde) adicionada em 2026-09-03 pra "perfil
     visitado" — CVD contra --activity-comment fica na faixa WARN (6-8,
     legal só com codificação secundária): a timeline já tem isso, cada
     ponto colorido sempre vem ao lado do texto do verbo/título, nunca só
     a cor. */
  --activity-book: #A8434B;
  --activity-library: #B08A2E;
  --activity-comment: #1580AC;
  --activity-user: #2E7D46;
}

/* ---------- Modo escuro: mesma paleta, elementos de fundo trocados ---------- */
:root[data-theme="dark"] {
  --bg: #171613;
  --surface: #201F1B;
  --ink: #FAFAF9;
  --ink-soft: #A6A399;
  --accent: #C1585F;
  --line: #34322B;
  --danger: #D98686;

  --activity-book: #C1585F;
  --activity-library: #AD8A2C;
  --activity-comment: #2E90BC;
  --activity-user: #43955A;
}

* { box-sizing: border-box; }

/* Sticky footer real — evita que o footer sobreponha o conteúdo
   quando a página é curta, sem depender de position:absolute. */
html, body {
  height: 100%;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  background: var(--bg);
  color: var(--ink);
  font-family: 'Instrument Sans', system-ui, sans-serif;
  line-height: 1.6;
  letter-spacing: 0.005em;
}

.page-content {
  flex: 1 0 auto;
}

h1, h2 { font-weight: 500; letter-spacing: -0.01em; }
h1 { font-size: 1.9rem; margin-bottom: 1.5rem; }
h2 {
  font-size: 1rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
  border-bottom: none;
  margin-top: 3rem;
  padding-bottom: 0;
}

a { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--line); }
a:hover { color: var(--accent); border-color: var(--accent); }

/* ---------- Navbar: chrome mínimo, sem sombra/borda pesada ---------- */
.navbar {
  background: var(--bg) !important;
  border-bottom: 1px solid var(--line) !important;
  box-shadow: none !important;
  padding: 1.25rem 0;
  margin-bottom: 3rem;
}
.navbar-brand {
  font-family: 'Newsreader', serif;
  font-size: 1.3rem;
  color: var(--ink) !important;
  border-bottom: none;
}
.navbar .nav-link {
  color: var(--ink-soft) !important;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 500;
}
.navbar .nav-link:hover { color: var(--accent) !important; }

/* ---------- Navbar: toggler mobile, ações à direita, dropdown de conta ---------- */
.navbar-toggler {
  border-radius: 0;
  border-color: var(--line);
  padding: 0.35rem 0.6rem;
}
.navbar-toggler:focus { box-shadow: 0 0 0 2px var(--accent); }
.navbar-toggler-icon {
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba(23,22,19,0.85)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}
:root[data-theme="dark"] .navbar-toggler-icon {
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba(250,250,249,0.85)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}

/* Sempre visível na linha compacta do topo (avatar/tema não ficam presos
   dentro do painel que abre/fecha) — só os links de texto colapsam. */
.navbar-actions {
  display: flex;
  align-items: center;
  gap: 0.85rem;
}
@media (min-width: 576px) {
  .navbar-actions { gap: 1.25rem; margin-left: 1.25rem; order: 2; }
  .navbar-collapse { order: 1; }
  .navbar-actions .navbar-toggler { display: none; }
}

/* Perfil/Sair como links diretos, sempre visíveis — de propósito, sem
   dropdown: com só 2 opções, esconder atrás de um clique no avatar custa
   mais em descoberta do que economiza em espaço (só compensa com 5+
   opções). No mobile o rótulo de texto some do avatar (cabe só o ícone
   na barra compacta) mas os mesmos links aparecem por extenso dentro do
   menu que abre — nunca ficam só atrás do avatar. */
.navbar-account-link {
  display: inline-flex;
  align-items: center;
  border-bottom: none;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 500;
  color: var(--ink-soft);
}
.navbar-account-link:hover { color: var(--accent); }
.navbar-account-link .avatar-sm { margin-right: 0; }
.navbar-account-label { display: none; }
@media (min-width: 576px) {
  .navbar-account-label { display: inline; margin-left: 0.5rem; }
}

/* ---------- Botões: retos, sem sombra, texto tracked ---------- */
.btn {
  border-radius: 0;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 500;
  padding: 0.6rem 1.4rem;
}
.btn-primary {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--bg);
}
.btn-primary:hover { background: var(--accent); border-color: var(--accent); color: var(--bg); }

.btn-outline-secondary {
  color: var(--ink-soft);
  border-color: var(--line);
}
.btn-outline-secondary:hover { background: transparent; color: var(--ink); border-color: var(--ink); }

.btn-outline-danger { border-radius: 0; }
.btn-link { color: var(--ink-soft); text-transform: uppercase; font-size: 0.78rem; letter-spacing: 0.06em; }

/* ---------- Login: cartão centralizado + botão Google padrão oficial
   (foge do estilo flat do resto do site de propósito — a marca do Google
   exige o botão dela reconhecível, não teria porque re-estilizar) ---------- */
.auth-page {
  display: flex;
  justify-content: center;
  padding: 3.5rem 1rem;
}
.auth-card {
  width: 100%;
  max-width: 380px;
  border: 1px solid var(--line);
  padding: 2.5rem 2rem;
  text-align: center;
}
.auth-title {
  font-family: 'Newsreader', serif;
  margin-bottom: 0.5rem;
}
.auth-subtitle {
  color: var(--ink-soft);
  font-size: 0.9rem;
  margin-bottom: 2rem;
}
.btn-google {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  width: 100%;
  padding: 0.7rem 1.25rem;
  background: #FFFFFF;
  border: 1px solid #DADCE0;
  border-radius: 4px;
  color: #3C4043;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
  cursor: pointer;
  transition: box-shadow 0.15s ease, border-color 0.15s ease;
}
.btn-google:hover {
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
  border-color: #C6C6C6;
}
.btn-google svg { width: 18px; height: 18px; flex-shrink: 0; }

:root[data-theme="dark"] .btn-google {
  background: #131314;
  border-color: #8E918F;
  color: #E3E3E3;
}
:root[data-theme="dark"] .btn-google:hover {
  background: #1E1F20;
  border-color: #A6A399;
}

/* ---------- Cards: sem borda, sem sombra — só espaço ---------- */
.card {
  background: transparent;
  border: none;
  border-radius: 0;
  box-shadow: none;
  height: 100%;
}

/* .catalog-card carrega o conteúdo E o divisor inferior. Como todo .card
   dentro de row-cols-* já estica para a altura da linha (h-100 + flex do
   Bootstrap), colocar a borda aqui — não no .col — garante que a linha
   de divisão fique alinhada entre colunas, independente do conteúdo. */
.catalog-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding-bottom: 1.5rem;
  border-bottom: 1px solid var(--line);
}

.row.row-cols-1 > .col,
.row.row-cols-sm-2 > .col,
.row.row-cols-md-3 > .col {
  margin-bottom: 1.5rem;
  display: flex;
}

.catalog-cover-link {
  display: block;
  border-bottom: none;
  margin-bottom: 0.75rem;
}

/* ---------- Mosaico de capa da biblioteca: mesma caixa 4:5 de um livro,
   dividida em NxN ladrilhos com a capa de cada livro que ela contém ---------- */
.catalog-cover-mosaic {
  display: grid;
  width: 100%;
  aspect-ratio: 4 / 5;
  gap: 1px;
  background: var(--line);
  overflow: hidden;
}
.catalog-cover-mosaic-cell {
  position: relative;
  overflow: hidden;
  background: var(--surface);
}
.catalog-cover-mosaic-cell img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.catalog-cover-mosaic-more {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(23, 22, 19, 0.6);
  color: #FAFAF9;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-size: 0.85rem;
  font-weight: 600;
}

.catalog-cover {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  background: var(--surface);
  display: block;
}

/* ---------- Avatar de perfil (foto do Google no login) ----------
   Tamanho de avatar de blog: pequeno o bastante pra nunca dominar a
   linha de texto ao lado, com fallback silencioso (sem <img> quebrada)
   quando o usuário não tem foto — ver _Layout, _BookCard, Feed/*. */
.avatar-xs, .avatar-sm, .avatar-lg {
  border-radius: 50%;
  object-fit: cover;
  vertical-align: middle;
  display: inline-block;
  background: var(--surface);
}
.avatar-xs { width: 18px; height: 18px; margin-right: 0.35rem; }
.avatar-sm { width: 28px; height: 28px; margin-right: 0.5rem; }
.avatar-lg { width: 64px; height: 64px; }

/* Precisa vir DEPOIS de .avatar-xs/.avatar-sm/.avatar-lg (mesma
   especificidade — quem vier por último na cascata é que vale), senão o
   fundo var(--surface) de lá vence e a inicial fica quase invisível
   (bug real, achado testando visualmente antes de publicar). */
.avatar-fallback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--accent);
  color: var(--bg);
  font-family: 'Newsreader', serif;
  font-size: 0.85rem;
}
.avatar-lg.avatar-fallback { font-size: 1.8rem; }

/* ---------- Perfil: cabeçalho com identidade + números glanceable ---------- */
.profile-header {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 1.5rem;
  padding-bottom: 2rem;
  border-bottom: 1px solid var(--line);
  margin-bottom: 0.5rem;
}
.profile-header-main {
  display: flex;
  align-items: center;
  gap: 1rem;
}
.profile-name {
  font-family: 'Newsreader', serif;
  font-size: 1.6rem;
  margin: 0;
}
.profile-email {
  color: var(--ink-soft);
  font-size: 0.85rem;
  margin: 0.15rem 0 0;
}
.profile-stats {
  display: flex;
  gap: 2rem;
}
.stat {
  text-align: center;
}
.stat-value {
  display: block;
  font-family: 'Newsreader', serif;
  font-size: 1.8rem;
  line-height: 1;
  color: var(--ink);
}
.stat-label {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.2rem;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
  margin-top: 0.35rem;
}

/* ---------- Listas de gerenciamento (Meu perfil: bibliotecas/livros/
   comentários) ----------
   Sem foto/card de propósito — pesquisa de UX confirma: card grid é pra
   navegar/descobrir (Feed, perfil público), lista densa é pra
   gerenciar/editar (ver uxpatterns.dev, "avoid card grids when the task
   is editing rather than interpretation"). Mesmo padrão de linha usado no
   feed de atividade (.activity-feed-item), com a diferença de que aqui
   cada linha tem DUAS ações (Editar/Excluir) em vez de ser um link único
   — por isso o conteúdo principal e as ações são elementos irmãos, não a
   linha inteira dentro de um <a>. */
.profile-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.profile-list-item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1rem;
  padding: 0.75rem 0;
}
.profile-list-item + .profile-list-item { border-top: 1px solid var(--line); }

.profile-list-main {
  display: flex;
  flex-direction: column;
  flex: 1 1 240px;
  min-width: 0;
  border-bottom: none; /* sobrescreve o "a { border-bottom }" global */
  color: var(--ink);
}
.profile-list-main:hover .profile-list-title { color: var(--accent); }
.profile-list-title {
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.profile-list-meta {
  font-size: 0.8rem;
  color: var(--ink-soft);
}

.profile-list-actions {
  display: flex;
  gap: 0.5rem;
  flex: none;
  position: relative;
}

/* Menu de ações (3 pontinhos) — substitui os botões Editar/Excluir
   lado a lado, que tomavam largura demais numa lista densa com muitas
   linhas. Mesma lógica de "progressive disclosure" do resto do site
   (ver ESTILO.md), só que via dropdown do Bootstrap em vez de collapse,
   porque aqui o conteúdo é uma lista de ações, não uma seção de tela. */
.profile-actions-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border: 1px solid transparent;
  border-radius: 0;
  background: transparent;
  color: var(--ink-soft);
  padding: 0;
}
.profile-actions-toggle:hover,
.profile-actions-toggle:focus,
.profile-actions-toggle[aria-expanded="true"] {
  border-color: var(--line);
  color: var(--ink);
}

.profile-actions-menu {
  border: 1px solid var(--line);
  border-radius: 0;
  box-shadow: none;
  background: var(--surface);
  padding: 0;
  min-width: 9rem;
}
.profile-actions-menu .dropdown-item {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 500;
  color: var(--ink-soft);
  padding: 0.55rem 0.9rem;
  background: transparent;
}
.profile-actions-menu .dropdown-item:hover,
.profile-actions-menu .dropdown-item:focus {
  background: var(--bg);
  color: var(--accent);
}
.profile-actions-menu .dropdown-item-danger { color: var(--danger); }
.profile-actions-menu .dropdown-item-danger:hover,
.profile-actions-menu .dropdown-item-danger:focus {
  background: var(--bg);
  color: var(--danger);
}
.profile-actions-menu li + li { border-top: 1px solid var(--line); }

/* ---------- Página "Sobre": texto corrido, largura de leitura ---------- */
.about-page {
  max-width: 640px;
}
.about-page .lead {
  font-family: 'Newsreader', serif;
  font-style: italic;
  font-size: 1.3rem;
  color: var(--ink);
  margin-bottom: 1.75rem;
}
.about-page p:not(.lead) {
  color: var(--ink-soft);
}

/* ---------- Reordenar fotos na edição do livro ---------- */
.photo-thumb-wrapper {
  position: relative;
}
.cover-badge {
  position: absolute;
  top: 0.35rem;
  left: 0.35rem;
  background: var(--accent);
  color: var(--bg);
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.15rem 0.5rem;
}

/* ---------- Cartões com ações do dono (editar/excluir) ---------- */
.card-description {
  color: var(--ink-soft);
  font-size: 0.85rem;
  margin-bottom: 0.75rem;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.card-actions {
  display: flex;
  gap: 0.5rem;
  margin-top: auto;
  padding-top: 0.9rem;
  border-top: 1px solid var(--line);
}
.card-actions form { margin: 0; }
.card-actions .btn { flex: 1; }

/* ---------- Linha do tempo de atividade (perfil público) ---------- */
.activity-timeline-wrap {
  border: 1px solid var(--line);
  padding: 1.25rem;
  margin-bottom: 1rem;
}

.activity-filter-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  margin-bottom: 1rem;
  font-size: 0.85rem;
}
.activity-filter-custom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
}
.activity-filter-select,
.activity-filter-row input[type="date"] {
  width: auto;
}

/* Escondidas até "Ver mais" expandir #activityFeed — já vieram na mesma
   resposta (ActivityEntry.IsExtra), então revelar é só CSS. */
.activity-feed:not(.is-expanded) .activity-feed-item--extra { display: none; }

.activity-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  margin-bottom: 1rem;
  font-size: 0.78rem;
  color: var(--ink-soft);
}
.activity-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border: none;
  background: none;
  padding: 0;
  margin: 0;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-size: 0.78rem;
  color: var(--ink-soft);
  cursor: pointer;
}
.activity-legend-item:hover { color: var(--ink); }
.activity-legend-item.is-off {
  opacity: 0.45;
  text-decoration: line-through;
}
.activity-legend-swatch {
  display: inline-block;
  width: 14px;
  height: 3px;
  border-radius: 2px;
}

/* ---------- Feed de atividade (lista cronológica) ----------
   Segunda versão: a primeira era um grafo de branches em SVG (estilo
   git), trocado por lista — ver o porquê no comentário de
   ActivityTimelineBuilder.cs. Cresce em altura de forma previsível (uma
   linha por evento, até MaxEntries) e nunca precisa de rolagem própria —
   é responsivo "de graça", o texto só quebra linha em telas estreitas. */
.activity-feed {
  list-style: none;
  margin: 0;
  padding: 0;
}
.activity-feed-item + .activity-feed-item { border-top: 1px solid var(--line); }
.activity-feed-item.is-hidden { display: none; }

.activity-feed-link {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  padding: 0.6rem 0;
  border-bottom: none; /* sobrescreve o "a { border-bottom }" global */
  color: var(--ink);
}
.activity-feed-link:hover,
.activity-feed-link:focus-visible { color: var(--accent); }
.activity-feed-link:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }

.activity-feed-dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  transition: transform 0.15s ease;
}
.activity-feed-link:hover .activity-feed-dot { transform: scale(1.4); }

.activity-feed-text {
  flex: 1 1 auto;
  font-size: 0.88rem;
  color: var(--ink-soft);
}
.activity-feed-text strong { color: var(--ink); font-weight: 500; }
.activity-feed-link:hover .activity-feed-text,
.activity-feed-link:hover .activity-feed-text strong { color: var(--accent); }

.activity-feed-date {
  flex: none;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
}

/* ---------- Comentários no perfil público do usuário ---------- */
.comment-item {
  padding: 1rem 0;
  border-bottom: 1px solid var(--line);
}
.comment-item:first-child { padding-top: 0; }
.comment-book-link {
  font-family: 'Newsreader', serif;
  font-size: 1rem;
  display: inline-block;
  margin-bottom: 0.35rem;
}

/* ---------- Comentários em árvore (livro/biblioteca), _CommentsSection/_CommentNode ----------
   Indentação + linha fina à esquerda por nível, em vez de caixa por
   comentário — mesmo idioma "sem caixas" do resto do site (ver ESTILO.md). */
.comment-thread-list, .comment-node-children {
  list-style: none;
  margin: 0;
  padding: 0;
}
.comment-node {
  padding: 0.85rem 0;
  border-top: 1px solid var(--line);
}
.comment-thread-list > .comment-node:first-child { border-top: none; }
.comment-node-children {
  margin-top: 0.5rem;
  padding-left: 1.1rem;
  border-left: 1px solid var(--line);
}
.comment-node-children > .comment-node:first-child { border-top: none; padding-top: 0; }
.comment-node-tombstone {
  color: var(--ink-soft);
  font-style: italic;
}

/* ---------- Zona de risco: separada visualmente, sem competir com o resto ---------- */
.danger-zone {
  margin-top: 4rem;
  padding: 1.5rem;
  border: 1px solid var(--line);
}
.danger-zone h2 { margin-top: 0; }

/* ---------- Ícone de info (popover explicativo) ---------- */
.info-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  margin-left: 0.35rem;
  border: 1px solid var(--ink-soft);
  border-radius: 50%;
  background: transparent;
  color: var(--ink-soft);
  font-family: 'Newsreader', serif;
  font-style: italic;
  font-size: 0.65rem;
  line-height: 1;
  padding: 0;
  cursor: help;
}
.info-icon:hover, .info-icon:focus {
  border-color: var(--accent);
  color: var(--accent);
  outline: none;
}

.popover {
  --bs-popover-max-width: 320px;
  --bs-popover-border-color: var(--line);
  --bs-popover-bg: var(--surface);
  font-family: 'Instrument Sans', system-ui, sans-serif;
}
.popover-header {
  background: var(--surface);
  border-bottom-color: var(--line);
  color: var(--ink);
  font-size: 0.85rem;
  font-weight: 600;
}
.popover-body {
  color: var(--ink);
  font-size: 0.82rem;
}
.popover-body ul { font-size: 0.8rem; }
.score-fraud-warning { color: var(--danger); }

.catalog-label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
  display: block;
  margin-bottom: 0.5rem;
}

/* Sinaliza livro/biblioteca à venda — texto na cor de destaque (nunca fundo,
   ver ESTILO.md), uppercase/letter-spacing no mesmo idioma do
   .catalog-label, em vez de virar um badge/pill (.badge é desligado de
   propósito no site inteiro, ver regra logo abaixo). Usada tanto dentro de
   um .catalog-label existente (cards) quanto sozinha (título de detalhe). */
.selling-flag {
  color: var(--accent);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-family: 'Instrument Sans', system-ui, sans-serif;
}

.badge { display: none; } /* substituído pelo .catalog-label acima */

.card-title a {
  font-family: 'Newsreader', serif;
  font-size: 1.15rem;
  color: var(--ink);
  border-bottom: none;
}
.card-title a:hover { color: var(--accent); }

.card-subtitle {
  color: var(--ink-soft) !important;
  font-size: 0.85rem;
}

.meta-mono {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-soft);
}

.meta-line {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  align-items: center;
}

.user-byline {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  border-bottom: none;
}
.user-byline:hover .meta-mono { color: var(--accent); }

/* ---------- Forms ---------- */
.form-control, .form-select {
  border-radius: 0;
  border-color: var(--line);
  background: var(--surface);
  color: var(--ink);
  font-size: 0.95rem;
}
.form-control:focus, .form-select:focus {
  border-color: var(--ink);
  background: var(--surface);
  color: var(--ink);
  box-shadow: none;
}
.form-control::placeholder {
  color: var(--ink-soft);
  opacity: 0.7;
}
.form-control:disabled, .form-select:disabled {
  background: var(--line);
  color: var(--ink-soft);
  opacity: 1;
}

.text-muted, .form-text {
  color: var(--ink-soft) !important;
}

/* ---------- Listas ---------- */
.list-group-item {
  background: var(--surface);
  color: var(--ink);
  border-color: var(--line);
}
.form-label {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
}
.table { font-size: 0.9rem; --bs-table-bg: transparent; --bs-table-color: var(--ink); border-color: var(--line); }
.table th { color: var(--ink-soft); font-weight: 500; text-transform: uppercase; font-size: 0.72rem; letter-spacing: 0.05em; }
.table > :not(caption) > * > * { border-bottom-color: var(--line); }

/* ---------- Paginação ---------- */
.pagination .page-link {
  color: var(--ink-soft);
  border: none;
  background: transparent;
  font-size: 0.85rem;
}
.pagination .page-item.active .page-link { color: var(--ink); font-weight: 600; text-decoration: underline; }
.pagination .page-link:hover { color: var(--accent); }

/* ---------- Spinner de envio (trava de duplo clique, ver site.js) ----------
   Prepende ao botão sem tocar no conteúdo original (texto, ícone do
   Google etc.) — por isso é sempre um "+ spinner", nunca uma troca de
   innerHTML. Cor herda do próprio botão (currentColor), então funciona
   igual em .btn-primary, .btn-outline-secondary etc. sem CSS extra. */
.submit-spinner { margin-right: 0.4rem; vertical-align: -0.125em; }

/* ---------- Alertas ---------- */
.alert { border-radius: 0; border-width: 0 0 0 3px; background: transparent; }
.alert-danger { border-color: var(--danger); color: var(--danger); }
.alert-success { border-color: var(--ink); color: var(--ink); }

/* ---------- Banner de conversão (Feed, visitante anônimo) ----------
   Mesma linguagem visual dos .alert (borda de acento à esquerda, sem
   cantos arredondados), mas com fundo de superfície pra se destacar
   como um convite, não como aviso/erro. Fechável — grava a escolha no
   localStorage do próprio visitante (ver site.js), então não reaparece
   a cada página do feed depois de dispensado. */
.cta-banner {
  position: relative;
  border-radius: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  padding: 1rem 2.75rem 1rem 1.25rem;
}
.cta-banner p { margin-bottom: 0.75rem; }
.cta-banner-actions { display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; align-items: center; }
.cta-banner-close {
  position: absolute;
  top: 0.4rem;
  right: 0.6rem;
  background: none;
  border: none;
  font-size: 1.4rem;
  line-height: 1;
  padding: 0.25rem;
  color: var(--ink-soft);
  cursor: pointer;
}
.cta-banner-close:hover { color: var(--accent); }

/* ---------- Zoom ao passar o mouse nas fotos de livro (cards e detalhe) ----------
   .zoom-frame é o contêiner que recorta (overflow:hidden); a <img> dentro
   escala no hover e o JS (site.js) atualiza transform-origin conforme o
   cursor, criando o efeito de lupa acompanhando o mouse. */
.zoom-frame {
  overflow: hidden;
  cursor: zoom-in;
}
.zoom-frame img {
  transition: transform 0.2s ease;
}
.zoom-frame:hover img {
  transform: scale(1.8);
}
@media (hover: none) {
  /* Touch não tem hover de verdade — não trava o dedo num cursor errado
     nem deixa a imagem "presa" ampliada depois do toque. */
  .zoom-frame { cursor: default; }
  .zoom-frame:hover img { transform: none; }
}

/* ---------- Visualizador de zoom em tela cheia (photo-zoom.js) ----------
   Fundo escuro fixo, independente do tema claro/escuro do site — é a
   mesma convenção do .btn-google (ver seção Login): um componente que
   deliberadamente sai da paleta normal porque o contexto (examinar foto)
   pede contraste máximo, não harmonia com o resto da página. */
.photo-lightbox {
  position: fixed;
  inset: 0;
  z-index: 1080;
  background: rgba(10, 9, 8, 0.94);
  touch-action: none; /* pan/pinch são decididos pelo JS, não pelo navegador */
}
.photo-lightbox-stage {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  cursor: grab;
  touch-action: none;
}
.photo-lightbox-stage.is-dragging { cursor: grabbing; }
.photo-lightbox-stage img {
  max-width: 92vw;
  max-height: 88vh;
  user-select: none;
  -webkit-user-drag: none;
  will-change: transform;
}
.photo-lightbox-close,
.photo-lightbox-nav {
  position: absolute;
  background: none;
  border: none;
  color: #FAFAF9;
  cursor: pointer;
  line-height: 1;
  padding: 0.6rem;
}
.photo-lightbox-close { top: 0.75rem; right: 1rem; font-size: 2rem; }
.photo-lightbox-nav { top: 50%; transform: translateY(-50%); font-size: 2rem; }
.photo-lightbox-prev { left: 0.25rem; }
.photo-lightbox-next { right: 0.25rem; }
.photo-lightbox-close:hover,
.photo-lightbox-nav:hover { color: #C1585F; }
.photo-lightbox-hint {
  position: absolute;
  bottom: 1rem;
  left: 0;
  right: 0;
  margin: 0;
  text-align: center;
  color: rgba(250, 250, 249, 0.65);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  pointer-events: none;
}
@media (max-width: 576px) {
  .photo-lightbox-nav { font-size: 1.5rem; padding: 0.5rem; }
  .photo-lightbox-hint { font-size: 0.65rem; padding: 0 3.25rem; }
}

/* ---------- Carrossel de fotos do livro ---------- */
.book-photo-carousel .carousel-item img {
  width: 100%;
  height: min(60vh, 480px);
  object-fit: contain;
  background: var(--surface);
}

.book-photo-carousel .carousel-indicators {
  position: static;
  margin: 0.75rem 0 0;
  margin-inline: 0;
}

.book-photo-carousel .carousel-indicators [data-bs-target] {
  background-color: var(--ink-soft);
}

.book-photo-carousel .carousel-indicators .active {
  background-color: var(--ink);
}

.book-photo-carousel {
  --bs-carousel-control-icon-width: 2.25rem;
}

.book-photo-carousel .carousel-control-prev,
.book-photo-carousel .carousel-control-next {
  opacity: 0.85;
}

.book-photo-carousel .carousel-control-prev-icon,
.book-photo-carousel .carousel-control-next-icon {
  background-color: var(--ink);
  background-size: 55%;
  border-radius: 50%;
}

/* ---------- Toggle de tema (cápsula) ---------- */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  margin: 0;
  cursor: pointer;
}

.theme-toggle-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  overflow: hidden;
}

.theme-toggle-track {
  display: inline-block;
  position: relative;
  width: 2.75rem;
  height: 1.5rem;
  background: var(--line);
  border-radius: 999px;
  transition: background 0.2s ease;
}

.theme-toggle-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 1.25rem;
  height: 1.25rem;
  background: var(--surface);
  border-radius: 50%;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
  transition: transform 0.2s ease, background 0.2s ease;
}

/* Sol e lua ocupam o mesmo lugar dentro do thumb — só a opacidade troca,
   sem precisar de dois elementos entrando/saindo do layout. */
.theme-toggle-icon {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0.7rem;
  height: 0.7rem;
  transform: translate(-50%, -50%);
  color: var(--ink);
  transition: opacity 0.2s ease;
}
.theme-toggle-icon-sun { opacity: 1; }
.theme-toggle-icon-moon { opacity: 0; }

.theme-toggle-input:checked + .theme-toggle-track {
  background: var(--ink);
}

.theme-toggle-input:checked + .theme-toggle-track .theme-toggle-thumb {
  transform: translateX(1.25rem);
  background: var(--bg);
}
.theme-toggle-input:checked + .theme-toggle-track .theme-toggle-icon-sun { opacity: 0; }
.theme-toggle-input:checked + .theme-toggle-track .theme-toggle-icon-moon { opacity: 1; }

.theme-toggle-input:focus-visible + .theme-toggle-track {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---------- Modais ---------- */
/* Bootstrap não sabe da nossa paleta (var(--ink)/--surface trocam com
   data-theme, mas as variáveis --bs-* do modal não) — sem isso o modal fica
   sempre claro (fundo branco fixo do Bootstrap) e, se o texto ao redor virar
   claro no tema escuro, o conteúdo do modal fica ilegível. */
.modal-content {
  background: var(--surface);
  color: var(--ink);
  border-radius: 0;
  border-color: var(--line);
}
.modal-header, .modal-footer {
  border-color: var(--line);
}
:root[data-theme="dark"] .btn-close {
  filter: invert(1) grayscale(100%) brightness(200%);
}

/* ---------- Footer ---------- */
.footer {
  position: static;
  flex-shrink: 0;
  margin-top: 3rem;
  padding: 1.5rem 0;
  border-top: 1px solid var(--line);
  background: var(--bg);
  font-size: 0.8rem;
  color: var(--ink-soft);
}