/* Viewer Pixel ES — tilt-shift + mapa.
   UI (redesign 2026-11-10, clean/shadcn + motion Amicro, vanilla):
   tema claro branco (tokens shadcn: zinc), dark mode = noite do mapa +
   interface escura (body.dark), rail enxuto (zoom, noite, mais), menu
   "mais" em bottom sheet, carrossel recolhível, drawer branco.
   Motion (linguagem Amicro — "Small motion. Big difference.",
   https://amicro.dev): só transform/opacity (GPU), durações curtas
   200–350ms, ease cubic-bezier(0.16, 1, 0.3, 1), press feedback
   (scale .94 ao tocar), ícones que transitam (lua↔sol), sheets com
   spring leve (overshoot). prefers-reduced-motion minimiza tudo.
   Fonte do sistema. */
[hidden] { display: none !important; }

:root {
  /* shadcn light (zinc) */
  --bg: rgba(255, 255, 255, .92);
  --bg-solid: #ffffff;
  --bg-soft: rgba(255, 255, 255, .72);
  --text: #09090b;
  --text-2: #52525b;
  --text-3: #a1a1aa;
  --border: rgba(0, 0, 0, .08);
  --border-strong: rgba(0, 0, 0, .14);
  --shadow: 0 1px 2px rgba(0, 0, 0, .05), 0 4px 16px rgba(0, 0, 0, .08);
  --shadow-lg: 0 12px 40px rgba(0, 0, 0, .18);
  --accent: #eab308; /* amarelo Tiny SP (2026-11-10): acento quente, não verde */
  --accent-soft: rgba(234, 179, 8, .12);
  --accent-fg: #422006;
  --primary: #18181b;
  --primary-fg: #fafafa;
  --hover: rgba(0, 0, 0, .05);
  --active: rgba(0, 0, 0, .08);
  --ring: rgba(234, 179, 8, .45);
  /* Botões estilo Tiny SP (v=k, 2026-11-10): jogo, não SaaS — borda
     grossa escura (navy), preenchimento branco (amarelo p/ ativo),
     raio generoso, negrito, sombra. Nada de círculo fino. */
  --game-border: #1e293b;
  --game-ink: #0f172a;
  --backdrop: rgba(0, 0, 0, .28);
  /* Motion Amicro: ease [0.16, 1, 0.3, 1], 200–350ms, transform/opacity. */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-spring: cubic-bezier(0.34, 1.25, 0.64, 1); /* overshoot leve p/ sheets */
  --dur: .25s;
  --dur-fast: .18s;
  --dur-sheet: .35s;
  /* Safari 26 (2026-11-10): bleed p/ o mapa se estender sob as barras.
     Era 62/136/62 no celular — REMOVIDO no v=ab (o scroll quebrava a
     tabbar). Hoje é 0 em todo lugar; as vars ficam p/ compatibilidade. */
  --safari-top-bleed: 0px;
  --safari-bottom-bleed: 0px;
  --safari-scroll-offset: 0px;
}
body.dark {
  /* shadcn dark (zinc) */
  --bg: rgba(24, 24, 27, .92);
  --bg-solid: #18181b;
  --bg-soft: rgba(24, 24, 27, .72);
  --text: #fafafa;
  --text-2: #a1a1aa;
  --text-3: #71717a;
  --border: rgba(255, 255, 255, .1);
  --border-strong: rgba(255, 255, 255, .18);
  --shadow: 0 1px 2px rgba(0, 0, 0, .35), 0 4px 16px rgba(0, 0, 0, .45);
  --shadow-lg: 0 12px 40px rgba(0, 0, 0, .65);
  --accent: #facc15; /* amarelo Tiny SP no dark */
  --accent-soft: rgba(250, 204, 21, .16);
  --accent-fg: #422006;
  --primary: #fafafa;
  --primary-fg: #18181b;
  --hover: rgba(255, 255, 255, .08);
  --active: rgba(255, 255, 255, .14);
  --ring: rgba(250, 204, 21, .45);
  --backdrop: rgba(0, 0, 0, .5);
}

html, body { margin: 0; height: 100%; height: 100vh; height: 100dvh; overflow: hidden; background: var(--bg-solid); }
/* Safety net p/ safe areas (2026-11-10): se algum filete do fundo aparecer
   atrás do mapa (notch / home indicator), que seja verde-escuro do mapa,
   nunca branco. O body era branco no light mode — era a fonte da faixa
   branca quando o #map não cobria a viewport. */
html { background: #16241c; }
body { position: relative; font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; color: var(--text); background: #16241c; min-height: calc(100dvh + var(--safari-scroll-offset)); touch-action: manipulation; /* v=ac: desliga o zoom da página por duplo toque em qualquer área fora do mapa (o #map tem touch-action:none e o OSD manda lá; sheet/carrossel têm o próprio touch-action) */ }
/* iOS — barra branca (2026-11-10, Safari 26 / Liquid Glass): o problema
   NÃO é a toolbar (ela pode ficar). É a faixa branca em cima (status bar)
   e embaixo, onde o mapa não chegava. O conserto inicial era #map em
   FLUXO NORMAL (absolute, não fixed), mais alto que a tela (bleed 62px
   em cima + 136px embaixo), documento com scroll e pin no offset no
   load (o JS fazia o scrollTo). v=ab (2026-11-11, pedido do usuário):
   o scroll fazia a página rolar e a tabbar subir pro meio da tela —
   REMOVIDO. O #map volta a preencher o body (100dvh) e o documento
   não rola; o fundo atrás das barras do Safari é o verde-escuro do
   mapa (#16241c), nunca branco. */
#map { position: absolute; inset: 0; background: #16241c; touch-action: none; /* v=ac: o OSD controla todos os gestos no mapa (drag, pinch, duplo toque p/ zoom) — o navegador não faz nada aqui, nem o zoom da página */ }
@media (max-width: 760px) {
  html { overflow: hidden; overscroll-behavior: none; }
  body { overflow: hidden; overflow-x: hidden; }
}

/* Press feedback (Amicro): todo botão responde ao toque.
   touch-action: manipulation (v=ac): desliga o ZOOM DA PÁGINA por
   duplo toque no Safari (iOS ignora user-scalable=no / maximum-scale=1
   do viewport desde o iOS 10 — o CSS é o conserto real). O pinch zoom
   do mapa continua (manipulation permite pinch-zoom; o #map tem
   touch-action:none e o OSD controla os gestos lá). */
button { -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
button:active { transform: scale(.94); }

/* Canvases de overlay (animação: carros em #anim; névoa/nuvens em
   #sky). REGRA DO IPHONE (bug do site de SP): <canvas> é elemento
   substituído — inset:0 NÃO o estica; o tamanho CSS é o intrínseco
   (o atributo width). Por isso width/height 100% explícitos aqui, e
   os canvases vivem DENTRO do #map (o JS faz appendChild). O backing
   store é medido pelo #map × DPR, NUNCA pelo clientWidth do próprio
   canvas (isso alimenta um loop que dobra o backing store a cada
   frame até 2^26 e estoura a memória). */
#anim { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 5; }
#sky { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 12; }
/* Mapa em volta (contexto cinza, estilo Tiny RJ): o canvas mais baixo
   dos overlays (z 1 — acima do canvas do OSD, abaixo das luzes). O JS
   o recorta p/ fora do polígono mapeado, então nunca cobre os blocos.
   Entra no tint da noite (escurece junto com o mapa). */
#context { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1; }
/* Luzes da noite (item 9): entre o mapa e os carros (mapa → luzes →
   carros → pins). Vivem DENTRO do #map como #anim/#sky (o JS faz
   appendChild). O tint da noite NÃO atinge as luzes: a regra abaixo
   exclui #lights (`:not(#lights)`) — os halos ficam quentes, e o
   mapa/carros/névoa escurecem junto. Só tem conteúdo quando a noite
   está ativa; de dia, custo zero. */
#lights { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 3; }
/* Sombra assada + AO (depth map, passo 3): multiply sobre o chão,
   abaixo dos carros. Só tem conteúdo de dia (45° foto/pixel art);
   à noite e a 30° (híbrido), o canvas fica vazio. Entra no tint. */
#shadow { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1; }
/* Camada ACIMA (depth map, passo 1): segundo viewer OpenSeadragon
   com os tiles transparentes dos prédios (WebP + alpha). Fica ACIMA
   dos carros (#anim, z 5) e ABAIXO do céu (#sky, z 12) — o carro
   some atrás do prédio e reaparece na rua. pointer-events none: a
   entrada (pan/zoom) vai p/ o viewer de baixo; os pins (DOM, z 30)
   ficam acima dele e continuam clicáveis. O canvas do OSD é
   transparente onde não há prédio (o OSD só limpa o canvas). */
#mapTop { position: absolute; inset: 0; pointer-events: none; z-index: 8; background: transparent; }
#mapTop canvas { background: transparent; }
/* Veículos em ponte (depth map, passo 1): acima da camada ACIMA
   (o carro na Terceira Ponte anda SOBRE o tabuleiro, não atrás
   dele). Só tem conteúdo quando há veículo em ponte na tela. */
#animTop { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 9; }
/* Noite: o tint do #map atinge os canvases de overlay também
   (estão dentro do #map) — névoa e carros escurecem junto, como no SP.
   EXCETO #lights: o tint azulava os halos quentes (por isso o canvas
   ficava fora do #map antes de 2026-11-10; mover p/ dentro + excluir
   aqui resolve o posicionamento sem azular a luz). */

/* Pixel nítido acima de 1,25x de zoom, suavizado abaixo (artigo).
   O OpenSeadragon aplica a classe conforme o zoom; o JS alterna
   `crisp` no #map. */
#map.crisp canvas { image-rendering: pixelated; }
#map:not(.crisp) canvas { image-rendering: auto; }
/* Saturação do pixel art (v=k, 2026-11-10): o LoRA tiny-london +
   filtro A sai apagado no iPhone (mar verde-acinzentado, cidade
   terrosa) — o Tiny SP é vívido. Boost leve SÓ no canvas do OSD
   (chão + camada ACIMA, os dois são o mesmo pixel art) e SÓ no
   pixel art de dia: o :not(.dark) desliga o seletor à noite, e o
   tint noturno (#map.night ...) vale sozinho. A foto não leva o
   boost. O minimapa não é afetado (fica fora do #map). Composição
   pela GPU no iPhone; custo medido no headless antes de manter. */
body.pixelart:not(.dark) #map .openseadragon-container canvas { filter: saturate(1.18) brightness(1.02); }

/* Tilt-shift: duas faixas empilhadas com backdrop-filter.
   REGRA DO ARTIGO (bug "o blur só funcionava em dev"): o CSS minifier
   manteve só o -webkit-backdrop-filter, que o Chrome ignora. Por isso
   as duas declarações estão em REGRAS SEPARADAS abaixo. NÃO juntar
   numa regra só. */
.tilt {
  position: absolute; left: 0; right: 0; height: 32vh;
  pointer-events: none; z-index: 10;
}
.tilt-top { top: 0; }
.tilt-bottom { bottom: 0; }
/* PERF (2026-11-10): o blur(12px) nas duas faixas (64% da tela) era
   re-renderizado a CADA frame — o conteúdo embaixo (os canvases de
   animação) muda sempre, então o navegador re-blurra 64% da tela 60×/s.
   Medido (headless): anim ON 7–12 fps, anim OFF 47–60 fps. Sem o blur,
   o tilt-shift vira um vinhete suave (gradiente, sem custo por frame).
   Se o usuário sentir falta do blur, dá p/ voltar com blur menor (2–4px)
   ou só quando a animação pausa. */
.tilt-top { background: linear-gradient(to bottom, rgba(255,255,255,.22), rgba(255,255,255,0)); }
.tilt-bottom { background: linear-gradient(to top, rgba(0,0,0,.20), rgba(0,0,0,0)); }
/* Máscara: blur mais forte para as bordas (a faixa some no meio). */
.tilt-top {
  -webkit-mask-image: linear-gradient(to bottom, black, transparent);
  mask-image: linear-gradient(to bottom, black, transparent);
}
.tilt-bottom {
  -webkit-mask-image: linear-gradient(to top, black, transparent);
  mask-image: linear-gradient(to top, black, transparent);
}

/* Status: pílula mínima, branca, que some sozinha depois de carregar
   (o texto continua no DOM p/ o hook de teste). Embaixo à esquerda,
   acima do minimapa (redesign 2026-11-10: antes ficava no topo, sobre
   a área de contexto). Desce junto com o minimapa quando o carrossel
   recolhe. */
#hud {
  position: absolute; left: 12px; bottom: calc(248px + env(safe-area-inset-bottom, 0px)); z-index: 20;
  font-size: 11px; line-height: 1.4; color: var(--text-2);
  background: var(--bg-soft);
  -webkit-backdrop-filter: blur(12px) saturate(1.2);
  backdrop-filter: blur(12px) saturate(1.2);
  padding: 4px 10px; border-radius: 999px; border: 2px solid var(--game-border); font-weight: 600;
  box-shadow: var(--shadow);
  max-width: calc(100vw - 24px); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  opacity: 1; transition: opacity .6s var(--ease), transform var(--dur-sheet) var(--ease);
  pointer-events: none;
}
body.car-collapsed #hud { transform: translateY(82px); }
#hud strong, #hud .hud-desc { display: none; }
#hud.fade { opacity: 0; }
#progress {
  display: block; height: 3px; margin-top: 3px;
  background: var(--border); border-radius: 2px; overflow: hidden;
}
#progress-fill { display: block; height: 100%; width: 0; background: var(--accent); border-radius: 2px; transition: width .2s var(--ease); }

/* Noite: tint azul por cima do canvas do mapa. Não são tiles
   noturnos — o botão avisa isso no title e no toast. O tint tem DUAS
   partes (redesign 2026-11-10): (1) o filtro CSS escurece e
   dessatura SEM inverter matiz (o hue-rotate(180deg) antigo virava
   verde em roxo — era o cast roxo da noite); (2) a camada #night-tint
   (div azul, multiply, z 2) dá o azul escuro por cima do mapa, sem
   tocar nas luzes (#lights, z 3, fica por cima dela). */
#map.night canvas:not(#lights) { filter: brightness(.62) saturate(.5); }
#night-tint { position: absolute; inset: 0; z-index: 2; pointer-events: none; display: none; background: rgba(16, 34, 80, .28); mix-blend-mode: multiply; }
#map.night #night-tint { display: block; }
/* Tilt-shift à noite: a faixa de cima era branca (.22) sobre o mapa
   escuro — vira azul-escuro, como o resto da noite. */
body.dark .tilt-top { background: linear-gradient(to bottom, rgba(8, 14, 30, .30), rgba(8, 14, 30, 0)); }
body.dark .tilt-bottom { background: linear-gradient(to top, rgba(0, 0, 0, .32), rgba(0, 0, 0, 0)); }

/* Marca (Tiny SP): logotipo forte no canto superior esquerdo; tocar
   volta à vista inteira do mapa. Texto nu sobre o mapa (sem pílula),
   com sombra p/ ler sobre qualquer fundo; compacta em telas médias. */
#brand {
  position: absolute; left: calc(12px + env(safe-area-inset-left, 0px)); top: calc(12px + env(safe-area-inset-top, 0px) + var(--safari-scroll-offset)); z-index: 35;
  display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
  background: transparent; border: 0; padding: 2px 4px; cursor: pointer; text-align: left;
}
#brand strong { font-size: 20px; font-weight: 800; letter-spacing: .06em; line-height: 1; color: #fff; text-shadow: -1.5px -1.5px 0 var(--game-border), 1.5px -1.5px 0 var(--game-border), -1.5px 1.5px 0 var(--game-border), 1.5px 1.5px 0 var(--game-border), 0 2px 8px rgba(0, 0, 0, .45); }
#brand span { font-size: 11px; font-weight: 700; line-height: 1.2; color: #fff; background: rgba(15, 23, 42, .88); padding: 3px 9px; border-radius: 999px; box-shadow: 0 1px 4px rgba(0, 0, 0, .3); text-shadow: none; }
body.dark #brand strong { color: #fff; text-shadow: -1.5px -1.5px 0 var(--game-border), 1.5px -1.5px 0 var(--game-border), -1.5px 1.5px 0 var(--game-border), 1.5px 1.5px 0 var(--game-border), 0 2px 8px rgba(0, 0, 0, .45); }
body.dark #brand span { color: #fff; background: rgba(15, 23, 42, .88); text-shadow: none; }
@media (max-width: 900px) { #brand strong { font-size: 16px; } #brand span { font-size: 10px; padding: 2px 7px; } }

/* Pílulas do topo direito (Tiny SP): estilo atual a 1 toque + Sobre.
   Brancas, arredondadas, sombra suave — o mapa é o herói, a UI sai
   do caminho. A pílula de estilo mostra o estilo ATUAL; .on (pixel
   art, o padrão) ganha borda amarela. Escondidas no modo captura. */
#top-pills {
  position: absolute; right: calc(12px + env(safe-area-inset-right, 0px)); top: calc(12px + env(safe-area-inset-top, 0px) + var(--safari-scroll-offset)); z-index: 36;
  display: flex; gap: 8px;
}
#top-pills button {
  height: 36px; padding: 0 14px; border-radius: 999px;
  background: #fff; border: 3px solid var(--game-border);
  color: var(--game-ink); font: 700 13px/1 system-ui, sans-serif;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .20); cursor: pointer; white-space: nowrap;
  transition: transform var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
#top-pills button:hover { transform: translateY(-1px); }
#top-pills button:active { transform: scale(.94); }
#top-pills button:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
#top-pills button.on { background: var(--accent); border-color: var(--game-border); color: var(--accent-fg); box-shadow: 0 2px 8px rgba(0, 0, 0, .20); }

/* Busca em pill branca centralizada no topo (shadcn): ícone à
   esquerda, input transparente. Frosted glass. O container NÃO pega
   clique (item 9): ele é largo e cobre a área do rail no celular —
   só o box, os resultados e a mensagem são clicáveis. */
#search {
  position: absolute; top: calc(12px + env(safe-area-inset-top, 0px) + var(--safari-scroll-offset)); left: 50%; transform: translateX(-50%); z-index: 35;
  font-size: 14px; line-height: 1.4; width: min(480px, calc(100vw - 24px));
  pointer-events: none;
}
#search .search-box, #search #search-results, #search #search-msg { pointer-events: auto; }
.search-box {
  display: flex; align-items: center; height: 44px;
  background: #fff;
  border: 3px solid var(--game-border); border-radius: 999px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .20);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.search-box:focus-within { border-color: var(--ring); box-shadow: 0 0 0 3px var(--ring), var(--shadow); }
.search-icon { flex: 0 0 auto; padding-left: 16px; font-size: 15px; opacity: .6; }
#search-input {
  flex: 1; min-width: 0; height: 100%; border: 0; outline: none;
  background: transparent; color: var(--text); font: inherit;
  padding: 0 16px 0 10px; border-radius: 999px;
}
#search-input::placeholder { color: var(--text-3); }
/* Dica de interação (Tiny SP): texto cinza pequeno abaixo da busca;
   some quando o usuário digita ou abre os resultados. */
#search-hint {
  margin-top: 6px; text-align: center; font-size: 11px; font-weight: 700; line-height: 1.4;
  color: rgba(255, 255, 255, .95); text-shadow: 0 1px 3px rgba(0, 0, 0, .65);
  transition: opacity var(--dur) var(--ease);
}
#search:focus-within #search-hint { opacity: 0; }
#search:has(#search-results:not([hidden])) #search-hint, #search:has(#search-msg:not([hidden])) #search-hint { display: none; }
/* Dica adaptada por dispositivo (item 8 do plano): no toque não existe
   "role para zoom" (é pinça) nem "← → girar" (girar vive no menu ⋯). */
#search-hint .hint-touch { display: none; }
@media (pointer: coarse) {
  #search-hint .hint-desktop { display: none; }
  #search-hint .hint-touch { display: inline; }
}
#search-results {
  list-style: none; margin: 8px 0 0; padding: 6px;
  background: var(--bg); color: var(--text);
  -webkit-backdrop-filter: blur(12px) saturate(1.2);
  backdrop-filter: blur(12px) saturate(1.2);
  border: 1px solid var(--border); border-radius: 14px;
  /* 320px cabem 5 resultados inteiros (5×~61px + padding) — o 5º era
     cortado com 260px (item 9 do plano). */
  max-height: 320px; overflow: auto; box-shadow: var(--shadow-lg);
}
/* Fade no fim quando há mais resultados abaixo do corte (item 9):
   indica que a lista rola. Ligado pelo JS (classe can-scroll). */
#search-results.can-scroll {
  -webkit-mask-image: linear-gradient(to bottom, black calc(100% - 28px), transparent);
  mask-image: linear-gradient(to bottom, black calc(100% - 28px), transparent);
}
#search-results li { padding: 10px 12px; color: var(--text); cursor: pointer; border-radius: 8px; transition: background-color var(--dur-fast) var(--ease); }
#search-results li:hover { background: var(--hover); }
/* Resultados ricos (Tiny SP): título em negrito + uma linha de descrição. */
#search-results li strong { display: block; font-size: 14px; font-weight: 600; color: var(--text); }
#search-results li span { display: block; font-size: 12px; line-height: 1.35; color: var(--text-2); margin-top: 1px; }
#search-msg {
  margin-top: 8px; padding: 10px 14px; background: var(--bg); color: var(--text-2);
  border-radius: 12px; border: 1px solid var(--border); box-shadow: var(--shadow);
}

/* Rail enxuto à direita: SÓ zoom, noite e "mais". Botões redondos
   brancos (frosted), 44px, com press feedback (Amicro). O .on é o
   verde de acento. */
#rail {
  position: absolute; right: calc(12px + env(safe-area-inset-right, 0px)); top: calc(50% + var(--safari-scroll-offset) / 2); transform: translateY(-50%); z-index: 30;
  display: flex; flex-direction: column; gap: 8px; align-items: center;
}
#rail button {
  width: 44px; height: 44px; border: 3px solid var(--game-border); border-radius: 14px;
  background: #fff; color: var(--game-ink); cursor: pointer;
  font-size: 19px; font-weight: 700; line-height: 39px; text-align: center; padding: 0;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .20);
  transition: transform var(--dur) var(--ease), background-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease);
}
#rail button:hover { transform: scale(1.06); }
#rail button:active { transform: scale(.94); }
#rail button.on { background: var(--accent); border-color: var(--game-border); color: var(--accent-fg); }
#rail button:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
/* Toggle noite: lua ↔ sol com morph (cross-fade + rotação leve). */
#night-btn { position: relative; overflow: hidden; }
#night-btn .ic-moon, #night-btn .ic-sun {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
#night-btn .ic-sun { opacity: 0; transform: rotate(-90deg) scale(.6); }
body.dark #night-btn .ic-moon { opacity: 0; transform: rotate(90deg) scale(.6); }
body.dark #night-btn .ic-sun { opacity: 1; transform: rotate(0deg) scale(1); }
/* "Ir para": o select nativo fica escondido — as linhas do menu
   "mais" disparam .change() nele (o JS e o hook continuam iguais). */
.rail-goto { position: relative; overflow: hidden; }
.rail-goto span { pointer-events: none; font-size: 19px; }
#goto {
  position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0;
  border: 0; cursor: pointer; font-size: 16px;
}

/* Menu "mais" (disclosure): bottom sheet no celular, painel
   centralizado embaixo no desktop — mesma linguagem do Drawer.
   Linhas limpas: ícone + rótulo + valor à direita. */
#menu-backdrop {
  position: absolute; inset: 0; z-index: 44; background: var(--backdrop);
  opacity: 0; transition: opacity var(--dur) var(--ease);
}
#menu-backdrop.in { opacity: 1; }
#menu {
  position: absolute; left: 50%; bottom: calc(12px + env(safe-area-inset-bottom, 0px)); z-index: 45;
  width: min(440px, calc(100vw - 24px));
  transform: translate(-50%, 110%); opacity: 0;
  transition: transform var(--dur-sheet) var(--ease-spring), opacity var(--dur) var(--ease);
  pointer-events: none;
}
#menu.in { transform: translate(-50%, 0); opacity: 1; pointer-events: auto; }
.menu-card {
  background: var(--bg-solid); color: var(--text);
  border-radius: 20px; border: 1px solid var(--border);
  padding: 6px 8px 10px; font-size: 14px; line-height: 1.45;
  box-shadow: var(--shadow-lg);
  max-height: min(72vh, 560px); overflow-y: auto; overflow-x: hidden;
  /* (2026-11-10) O conteúdo NUNCA desloca p/ o lado: overflow-y:auto
     fazia o overflow-x computar p/ auto também, e o card rolava na
     horizontal (o usuário viu o menu deslocado e o texto cortado na
     borda esquerda). overflow-x:hidden + pan-y + contain travam isso:
     o conteúdo só rola verticalmente, dentro do card. */
  overscroll-behavior: contain; touch-action: pan-y;
}
.menu-head {
  position: relative; display: flex; align-items: center; justify-content: center;
  padding: 6px 8px 10px; border-bottom: 1px solid var(--border); margin-bottom: 6px;
  /* Zona do swipe-down-to-dismiss (2026-11-10): touch-action:none p/
     o pointermove do arraste não ser tomado pelo scroll do navegador. */
  touch-action: none;
}
.menu-handle {
  position: absolute; top: 0; left: 50%; transform: translateX(-50%);
  width: 36px; height: 4px; border-radius: 2px; background: var(--text-3); opacity: .6;
}
.menu-head strong { font-size: 14px; font-weight: 600; padding-top: 8px; }
#menu-close {
  position: absolute; right: 4px; top: 8px; width: 32px; height: 32px;
  border: 2px solid var(--game-border); border-radius: 50%; background: #fff; color: var(--game-ink);
  font-size: 13px; font-weight: 700; line-height: 1; cursor: pointer;
  transition: transform var(--dur) var(--ease), background-color var(--dur-fast) var(--ease);
}
#menu-close:active { transform: scale(.9); }
.menu-sec-title {
  display: block; padding: 10px 12px 4px;
  font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-3);
}
.menu-section button {
  display: flex; align-items: center; gap: 12px; width: 100%;
  font: inherit; color: var(--text); text-align: left;
  border: 0; border-radius: 10px; padding: 10px 12px; min-height: 44px;
  background: transparent; cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease), transform var(--dur) var(--ease);
}
.menu-section button:hover { background: var(--hover); }
.menu-section button:active { transform: scale(.98); }
.menu-section button .mi { flex: 0 0 22px; font-size: 17px; text-align: center; }
.menu-section button .ml { flex: 1; min-width: 0; }
.menu-section button .mv { flex: 0 0 auto; font-size: 12px; color: var(--text-3); }
.menu-section button.on .ml { font-weight: 600; }
.menu-section button.on .mi { color: var(--accent); }
#menu-goto button .mi { color: var(--accent); }
/* (2026-11-10) O seletor de graus (.menu-deg) foi removido da UI —
   o viewer travou em 30°. As regras foram junto (o HTML não existe mais). */

/* Minimapa (navigator do OpenSeadragon). O OSD reescreve o position do
   #minimap (inline), então o lugar na tela é o wrapper. Topo direito,
   em LOSANGO (clip-path, estilo Tiny SP), abaixo das pílulas do topo.
   O losango corta os cantos do retângulo — que é onde ficam os wedges
   pretos da costura em L, então as máscaras de wedge viram redundantes
   (mantidas, sem efeito). A borda branca vira um losango atrás
   (::before); a sombra segue a forma (drop-shadow no wrapper). */
#minimap-wrap {
  position: absolute; right: calc(12px + env(safe-area-inset-right, 0px)); top: calc(60px + env(safe-area-inset-top, 0px) + var(--safari-scroll-offset)); z-index: 15;
  width: 132px; height: 82px; /* TAMANHO EXPLÍCITO (= #minimap): o Navigator do
    OSD embrulha o #minimap num div com height:100% — sem altura definida
    no wrapper, o % resolve errado e o wrapper estoura (no celular media
    610 px de altura, um losango vertical). Com tamanho explícito o
    height:100% resolve certo e as máscaras de wedge (% do wrapper)
    voltam ao tamanho desenhado. */
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .05)) drop-shadow(0 4px 16px rgba(0, 0, 0, .08));
}
#minimap-wrap::before {
  content: ""; position: absolute; inset: -2px; z-index: 0;
  background: rgba(255, 255, 255, .85);
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}
#minimap {
  width: 132px; height: 82px;
  border: 0; border-radius: 0;
  overflow: hidden; background: #8b939c;
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
  position: relative; z-index: 1; /* acima do ::before (borda branca) */
}
/* Máscara dos wedges pretos (foto 45° e foto 30°): os mosaicos
   costurados são em L — os 2 cantos fora da união são tiles PRETOS,
   e o navigator do OSD os mostra. As 2 máscaras (cinza neutro, igual
   ao fundo) cobrem os wedges no minimapa. Posições em % do elemento
   (a imagem é ajustada por altura: a 45° ocupa os 80,6% centrais da
   largura; a 30°, os 93,1%). Só visíveis no modo foto (classes
   .foto45/.foto30 no wrapper, postas pelo JS); no pixel art a 45°
   não há wedge (bloco 1 é retângulo cheio). No pixel art a 30° a
   costura é a MESMA (24516×16358, cantos pretos) — a máscara vale
   igual (classe .pixelart30, redesign 2026-11-10: era o bug das
   áreas pretas no minimapa, que é o default). */
.minimap-wedge { position: absolute; background: #8b939c; z-index: 2; display: none; pointer-events: none; }
#minimap-wrap.foto45 .minimap-wedge { display: block; }
#wedge-tl { left: 9.7%; top: 0; width: 26.8%; height: 45.8%; }
#wedge-br { left: 63.5%; top: 54.2%; width: 26.8%; height: 45.8%; }
#minimap-wrap.foto30 .minimap-wedge { display: block; }
#minimap-wrap.foto30 #wedge-tl { left: 3.5%; top: 0; width: 30.9%; height: 37.4%; }
#minimap-wrap.foto30 #wedge-br { left: 65.7%; top: 62.6%; width: 30.9%; height: 37.4%; }
#minimap-wrap.pixelart30 .minimap-wedge { display: block; }
#minimap-wrap.pixelart30 #wedge-tl { left: 3.5%; top: 0; width: 30.9%; height: 37.4%; }
#minimap-wrap.pixelart30 #wedge-br { left: 65.7%; top: 62.6%; width: 30.9%; height: 37.4%; }
body.dark #minimap { border-color: rgba(255, 255, 255, .3); }

/* Atribuição (v=ag + v=ah compacta): barra discreta embaixo à
   esquerda, acima do carrossel — padrão Google Maps (logos + texto +
   links, visível no desktop E no celular). Google Maps logo (16–19dp,
   outlined p/ fundo ocupado) + Cesium ion logo (prominente, ToS
   2.2.3) + data attribution (Google, OSM, Open-Meteo). O container
   não bloqueia o pan (pointer-events: none); só os links recebem
   clique. v=ah: logos empilhados numa coluna à esquerda + texto ao
   lado (era logos + texto em fluxo livre, 3 linhas no celular, 53px)
   — barra bem mais baixa mantendo os 2 logos + os 4 créditos. */
#attr {
  position: absolute; left: calc(12px + env(safe-area-inset-left, 0px)); bottom: calc(156px + env(safe-area-inset-bottom, 0px)); z-index: 15;
  display: flex; align-items: center; gap: 3px 8px;
  max-width: calc(50vw - 80px);
  background: rgba(15, 23, 42, 0.62); border-radius: 6px; padding: 3px 8px;
  font-size: 10px; line-height: 1.3; color: rgba(255, 255, 255, .88);
  pointer-events: none;
}
#attr a { pointer-events: auto; color: #fff; text-decoration: underline; text-underline-offset: 2px; }
#attr .attr-logos { display: flex; flex-direction: column; gap: 2px; flex: none; }
#attr .attr-logo { display: block; height: 15px; width: auto; }
#attr .attr-logo-cesium { height: 13px; }
#attr .attr-text { flex: 1; min-width: 0; }

/* Toggle do carrossel: pílula branca acima da faixa; quando recolhido,
   desce p/ o rodapé (transform, não bottom — Amicro: só transform). */
#car-toggle {
  position: absolute; left: 50%; bottom: calc(156px + env(safe-area-inset-bottom, 0px)); z-index: 33;
  transform: translateX(-50%);
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 700; line-height: 1; color: var(--game-ink);
  border: 3px solid var(--game-border); border-radius: 999px; padding: 0 12px; height: 28px;
  background: #fff; cursor: pointer; box-shadow: 0 2px 8px rgba(0, 0, 0, .20); white-space: nowrap;
  transition: transform var(--dur-sheet) var(--ease), background-color var(--dur-fast) var(--ease);
}
#car-toggle:hover { background: var(--bg-solid); }
#car-toggle:active { transform: translateX(-50%) scale(.94); }
#car-toggle .car-chev { transition: transform var(--dur) var(--ease); display: inline-block; }
body.car-collapsed #car-toggle { transform: translateX(-50%) translateY(144px); }
body.car-collapsed #car-toggle .car-chev { transform: rotate(180deg); }

/* Carrossel de landmarks: faixa embaixo, cards BRANCOS com miniatura
   + nome. Scroll horizontal com snap; setas no desktop. Recolhe com
   transform (não some de repente). */
#carousel {
  position: absolute; left: calc(12px + env(safe-area-inset-left, 0px)); right: calc(12px + env(safe-area-inset-right, 0px)); bottom: calc(12px + env(safe-area-inset-bottom, 0px)); z-index: 32;
  /* 132px: miniatura 76px + título de 2 linhas (2×12px×1,3 + padding
     15px = 46,2px) + borda do card 2×2px + padding do track 2×2px —
     com 118px a 2ª linha era cortada (item 10 do plano). */
  height: 132px; display: flex; align-items: stretch; gap: 8px;
  transition: transform var(--dur-sheet) var(--ease), opacity var(--dur) var(--ease);
}
body.car-collapsed #carousel { transform: translateY(130%); opacity: 0; pointer-events: none; }
#carousel-track {
  flex: 1; display: flex; gap: 10px; overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x mandatory; scrollbar-width: none; padding: 2px;
  -webkit-mask-image: linear-gradient(to right, transparent, black 24px, black calc(100% - 24px), transparent);
  mask-image: linear-gradient(to right, transparent, black 24px, black calc(100% - 24px), transparent);
}
#carousel-track::-webkit-scrollbar { display: none; }
#car-prev, #car-next {
  flex: 0 0 32px; border: 3px solid var(--game-border); border-radius: 10px; align-self: center;
  width: 32px; height: 32px; background: #fff; color: var(--game-ink);
  font-size: 20px; font-weight: 700; line-height: 26px; cursor: pointer; z-index: 1;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .20);
  transition: transform var(--dur) var(--ease), background-color var(--dur-fast) var(--ease);
}
#car-prev:hover, #car-next:hover { background: var(--bg-solid); }
#car-prev:active, #car-next:active { transform: scale(.9); }
.car-card {
  flex: 0 0 164px; scroll-snap-align: start; border: 2px solid var(--game-border);
  border-radius: 14px; overflow: hidden; padding: 0; cursor: pointer; text-align: left;
  background: var(--bg-solid); color: var(--text);
  box-shadow: 0 2px 8px rgba(0, 0, 0, .20);
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), border-color var(--dur-fast) var(--ease);
}
.car-card:hover { transform: translateY(-2px); }
.car-card:active { transform: scale(.97); }
.car-card img { display: block; width: 100%; height: 76px; object-fit: cover; }
.car-card span {
  display: block; padding: 7px 10px 8px; font-size: 12px; font-weight: 600; line-height: 1.3; color: var(--text);
  white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.car-card.on { border-color: var(--accent); box-shadow: 0 0 0 2px var(--ring), var(--shadow); }

/* Pins dos lugares: botões numerados, alvo de toque >= 24px. */
.lm-pin {
  width: 28px; height: 28px; padding: 0; border: 2px solid #fff; border-radius: 50%;
  background: var(--accent); color: var(--accent-fg); font: bold 14px/24px system-ui, sans-serif;
  text-align: center; cursor: pointer; pointer-events: auto;
  box-shadow: 0 0 0 1.5px var(--game-border), 0 1px 6px rgba(0, 0, 0, .6);
  transition: transform var(--dur) var(--ease);
  /* Acima da camada ACIMA (#mapTop, z 8) e do céu (#sky, z 12): sem
     isso o pin some onde a camada de oclusão é opaca — o pin do Morro
     ficava escondido pela copa das árvores do cume (v=w). O marcador
     vermelho da busca (.pin) já tem z 30 pelo mesmo motivo. */
  z-index: 13;
}
.lm-pin:active { transform: scale(.9); }

/* "Em breve" (próximos blocos, estilo Tiny RJ): pill cinza, apagada,
   sobre o mapa em volta — marca o que vem por aí sem competir com os
   pins coloridos. Nome + badge. Press feedback (Amicro: scale .94). */
.soon-pill {
  display: flex; align-items: center; gap: 6px; padding: 5px 10px;
  border: 2px solid var(--game-border); border-radius: 999px;
  background: rgba(113, 113, 122, .85); color: #fff; cursor: pointer; pointer-events: auto;
  box-shadow: 0 1px 6px rgba(0, 0, 0, .35); backdrop-filter: blur(4px);
  transition: transform var(--dur) var(--ease);
  white-space: nowrap;
}
.soon-pill:active { transform: scale(.94); }
.soon-name { font: 600 12px/1.2 system-ui, sans-serif; }
.soon-badge {
  font: 700 10px/1 system-ui, sans-serif; letter-spacing: .02em;
  background: rgba(255, 255, 255, .25); border-radius: 999px; padding: 3px 6px;
}
body.dark .soon-pill { background: rgba(63, 63, 70, .9); border-color: rgba(255, 255, 255, .4); }

/* Avião decorativo e barquinho: overlays em coordenadas de imagem. */
.boat { background: none; border: 0; padding: 0; pointer-events: auto; }
.boat { cursor: pointer; }
.boat svg { width: 26px; height: 26px; display: block; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .5)); }

/* Drawer (bottom sheet, estilo shadcn): card do lugar / legenda do tour.
   Card COMPACTO estilo Airbnb (v=z): horizontal, ~130 px, foto pixel art
   96×96 à esquerda, nome + "Categoria · Bairro" + blurb à direita.
   Sem backdrop — o mapa fica visível e navegável com o card aberto.
   Fecha arrastando a alça (ou o card) para baixo, pelo ✕, por toque
   fora do card ou Escape. Animação: o container desliza de baixo (.in);
   o card interno volta sozinho depois do arraste (transform dele,
   separado do container). Motion Amicro: spring leve (overshoot). */
#sheet-backdrop {
  position: absolute; inset: 0; z-index: 38; background: var(--backdrop);
  pointer-events: none; opacity: 0; transition: opacity var(--dur) var(--ease);
}
#sheet-backdrop.in { opacity: 1; }
#sheet {
  position: absolute; left: 12px; bottom: calc(12px + env(safe-area-inset-bottom, 0px)); z-index: 40;
  width: min(420px, calc(100vw - 24px));
  transform: translateY(140%); opacity: 0;
  transition: transform var(--dur-sheet) var(--ease-spring), opacity var(--dur) var(--ease);
  pointer-events: none;
}
#sheet.in { transform: translateY(0); opacity: 1; pointer-events: auto; }
.sheet-card {
  background: var(--bg-solid); color: var(--text); border-radius: 20px;
  border: 1px solid var(--border);
  padding: 6px 12px 8px; font-size: 14px; line-height: 1.45;
  box-shadow: var(--shadow-lg);
  transition: transform .2s var(--ease);
  overflow-x: hidden; /* mesma classe de bug do menu: nada desloca p/ o lado */
  position: relative; /* âncora do ✕ */
  display: flex; flex-direction: column;
}
#sheet-handle {
  width: 40px; height: 4px; border-radius: 2px; margin: 0 auto 6px;
  background: var(--text-3); opacity: .6; cursor: grab; touch-action: none;
  flex: 0 0 auto;
}
#sheet-handle:active { cursor: grabbing; }
.sheet-row { display: flex; gap: 12px; align-items: flex-start; }
#sheet-img {
  display: block; width: 96px; height: 96px; object-fit: cover; flex: 0 0 96px;
  border-radius: 12px; margin: 0; background: var(--hover);
}
#sheet-img[hidden] { display: none; }
.sheet-body { flex: 1; min-width: 0; padding-right: 30px; /* não passar por baixo do ✕ */ }
.sheet-body strong { display: block; font-size: 15px; line-height: 1.3; font-weight: 700; letter-spacing: -0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#sheet-sub { display: block; font-size: 12px; line-height: 1.3; color: var(--text-2); margin-top: 1px; }
.sheet-body p { margin: 2px 0 6px; color: var(--text-2); font-size: 12.5px; line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.sheet-actions { display: flex; gap: 6px; }
.sheet-actions button {
  font: inherit; font-size: 12.5px; border: 0; border-radius: 10px; padding: 5px 9px; min-height: 28px;
  background: var(--hover); color: var(--text); cursor: pointer; white-space: nowrap;
  transition: transform var(--dur) var(--ease), background-color var(--dur-fast) var(--ease);
}
.sheet-actions button:hover { background: var(--active); }
.sheet-actions button:active { transform: scale(.96); }
/* ✕ no canto do card: fecha sem rolar até o botão. */
#sheet-close-x {
  position: absolute; top: 8px; right: 8px; z-index: 2;
  width: 28px; height: 28px; border: 2px solid #fff; border-radius: 50%;
  background: rgba(0, 0, 0, .55); color: #fff; font-size: 12px; font-weight: 700; line-height: 1;
  cursor: pointer; backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  transition: transform var(--dur-fast) var(--ease);
}
#sheet-close-x:active { transform: scale(.94); }

/* Toast: mensagens curtas (link copiado, barquinho, noite). Abaixo da
   pílula de status (top 68px) para não sobrepor. */
#toast {
  position: absolute; top: calc(112px + env(safe-area-inset-top, 0px) + var(--safari-scroll-offset)); left: 50%; transform: translateX(-50%);
  z-index: 50; max-width: calc(100vw - 32px);
  background: #fff; color: var(--game-ink); border: 2px solid var(--game-border);
  border-radius: 12px; box-shadow: 0 2px 8px rgba(0, 0, 0, .20);
  padding: 10px 14px; font-size: 13px; font-weight: 600; line-height: 1.4; text-align: center;
  pointer-events: none;
}

/* Intro: cartão de boas-vindas (primeira visita). */
#intro {
  position: absolute; inset: 0; z-index: 60; display: flex;
  align-items: center; justify-content: center; padding: 16px;
  background: var(--backdrop); pointer-events: auto;
}
.intro-card {
  position: relative; width: min(440px, calc(100vw - 32px));
  background: var(--bg-solid); color: var(--text); border-radius: 20px;
  border: 1px solid var(--border);
  padding: 20px 20px 16px; font-size: 14px; line-height: 1.5;
  box-shadow: var(--shadow-lg);
}
.intro-title { font-size: 19px; font-weight: 600; letter-spacing: -0.01em; display: block; margin-bottom: 6px; }
.intro-sub { margin: 0 0 10px; color: var(--text-2); }
.intro-keys { margin: 0 0 14px; color: var(--text-3); font-size: 13px; }
.intro-keys kbd {
  background: var(--hover); border: 1px solid var(--border); border-radius: 6px; padding: 1px 6px;
  font-size: 12px; line-height: 1.5; color: var(--text-2);
}
#intro-go {
  width: 100%; font: inherit; font-weight: 600; border: 0; border-radius: 12px;
  padding: 12px; min-height: 44px; background: var(--primary); color: var(--primary-fg); cursor: pointer;
  transition: transform var(--dur) var(--ease), opacity var(--dur-fast) var(--ease);
}
#intro-go:active { transform: scale(.98); }
#intro-close {
  position: absolute; top: 10px; right: 10px; width: 32px; height: 32px;
  border: 0; border-radius: 50%; background: var(--hover);
  color: var(--text-2); font-size: 13px; line-height: 1; cursor: pointer;
  transition: transform var(--dur) var(--ease), background-color var(--dur-fast) var(--ease);
}
#intro-close:active { transform: scale(.9); }
.intro-attr { margin: 12px 0 0; font-size: 11px; color: var(--text-3); text-align: center; }
.intro-attr a { color: var(--text-2); text-decoration: underline; text-underline-offset: 2px; }

@media (max-width: 640px) {
  /* Busca: pill quase total no topo. */
  #search { width: calc(100vw - 24px); }
  /* HUD: pílula mínima abaixo da busca. (v=k: bottom:auto — a regra
     base fixa bottom:248px; com top+bottom o #hud ESTICAVA ~530px
     no celular, um oval branco gigante com o "pronto — N tiles"
     cortado no topo. Bug visto no iPhone do usuário.) */
  #hud { top: calc(64px + env(safe-area-inset-top, 0px) + var(--safari-scroll-offset)); bottom: auto; max-width: calc(100vw - 24px); font-size: 11px; }
  /* Rail: mesma coluna, encostada na borda direita. */
  #rail { right: calc(8px + env(safe-area-inset-right, 0px)); gap: 8px; }
  /* Minimapa: menor, no topo direito abaixo das pílulas (losango). */
  #minimap-wrap { top: calc(56px + env(safe-area-inset-top, 0px) + var(--safari-scroll-offset)); right: calc(8px + env(safe-area-inset-right, 0px)); width: 88px; height: 55px; }
  #minimap { width: 88px; height: 55px; }
  /* Pílulas do topo: só a de estilo no celular (compacta); a Sobre
     fica no menu. Escondem quando a busca está aberta (ela ocupa o
     topo inteiro). */
  #top-pills { right: calc(8px + env(safe-area-inset-right, 0px)); top: calc(12px + env(safe-area-inset-top, 0px) + var(--safari-scroll-offset)); }
  #top-pills #about-pill { display: none; }
  #top-pills button { height: 32px; padding: 0 11px; font-size: 12px; }
  body.search-open #top-pills { display: none; }
  /* Attribution no celular (v=ag + v=ah compacta): VISÍVEL (antes
     era display:none — o mapa não tinha attribution nenhuma no
     iPhone). Acima do carrossel + tabbar (o carrossel chega a 184px
     do fundo); logos empilhados + texto ao lado em 3 linhas no
     máximo, sem alcançar o chip do clima. */
  #attr {
    left: calc(8px + env(safe-area-inset-left, 0px));
    bottom: calc(192px + env(safe-area-inset-bottom, 0px));
    max-width: calc(100vw - 160px);
    font-size: 9px; line-height: 1.2; padding: 2px 6px; gap: 2px 6px;
  }
  #attr .attr-logo { height: 13px; }
  #attr .attr-logo-cesium { height: 11px; }
  /* Toggle do carrossel: acima da faixa. (Escondido no celular — a
     tabbar tem o botão Lugares — mas os valores ficam geometricamente
     certos caso volte a aparecer.) */
  #car-toggle { bottom: calc(196px + env(safe-area-inset-bottom, 0px)); }
  body.car-collapsed #car-toggle { transform: translateX(-50%) translateY(184px); }
  /* Carrossel: mais baixo, cards menores. */
  #carousel { height: 120px; left: calc(8px + env(safe-area-inset-left, 0px)); right: calc(8px + env(safe-area-inset-right, 0px)); bottom: calc(8px + env(safe-area-inset-bottom, 0px)); }
  .car-card { flex-basis: 128px; }
  .car-card img { height: 64px; }
  #car-prev, #car-next { display: none; } /* no telefone, rola por toque */
  /* Toast: abaixo da busca (não embaixo, onde está o carrossel). */
  #toast { top: calc(112px + env(safe-area-inset-top, 0px)); }
  /* Menu vira bottom sheet de verdade: largura total, cantos de cima
     arredondados. */
  #menu { left: 0; right: 0; bottom: 0; width: 100%; transform: translateY(110%); }
  #menu.in { transform: translateY(0); }
  .menu-card { border-radius: 20px 20px 0 0; padding-bottom: calc(10px + env(safe-area-inset-bottom, 0px)); max-height: 72vh; }
  /* Card compacto estilo Airbnb (v=z): flutuante acima da tabbar, no
     lugar do carrossel (que recolhe) — sem 70vh, sem ocupar a tela. */
  #sheet { left: 8px; right: 8px; bottom: calc(64px + env(safe-area-inset-bottom, 0px)); width: auto; transform: translateY(140%); }
  #sheet.in { transform: translateY(0); }
  .sheet-card { border-radius: 20px; padding-bottom: 8px; max-height: none; overflow: visible; }
  .sheet-actions button { min-height: 28px; }
  /* Intro vira bottom-sheet no celular (não cobre o mapa inteiro). */
  #intro { align-items: flex-end; padding: 0; }
  .intro-card { width: 100%; border-radius: 20px 20px 0 0; padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }
  /* Busca: input com altura de toque; resultados legíveis. */
  .search-box { height: 44px; }
  /* Resultados NÃO cobrem o rail no celular (item 9): o painel é quase
     total (100vw-24px) e o rail fica à direita (8px + 44px) — com
     margem de 60px à direita o "+" e o "−" ficam livres. */
  #search-results { margin-right: 60px; }
  #search-results li { padding: 12px; }
}

/* Busca: pin no mapa. */
.pin { position: absolute; z-index: 30; pointer-events: none; transform: translate(-50%, -50%); }
.pin-dot {
  display: block; width: 18px; height: 18px; margin: 0 auto;
  background: #e33; border: 3px solid #fff; border-radius: 50%;
  box-shadow: 0 1px 6px rgba(0, 0, 0, .6);
}
.pin-label {
  position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
  display: block; margin-top: 6px; white-space: nowrap;
  background: #fff; color: var(--game-ink); font-size: 13px; font-weight: 700; line-height: 1.3;
  padding: 4px 8px; border-radius: 8px; border: 2px solid var(--game-border); box-shadow: 0 2px 8px rgba(0, 0, 0, .20);
}

/* Motion reduzido (Amicro: respeitar prefers-reduced-motion). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: .01ms !important;
    transition-delay: 0s !important;
    animation-duration: .01ms !important;
  }
  #sheet, #menu { transition-timing-function: ease !important; }
}

/* =====================================================================
   FEATURES 1/2/3/5/6 (2026-11-10) — sol, clima, rota, pássaros/nuvens,
   compartilhar. Bloco próprio no fim do arquivo para não colidir com
   o redesign (que edita as seções acima). Reusa as variáveis do tema
   (shadcn light/dark) e o padrão de bottom sheet do #sheet/#menu.
   ===================================================================== */

/* FEATURE 2 — chip do clima: pílula pequena embaixo à direita, acima
   do carrossel. Não some com o HUD (é persistente). */
#wx-chip {
  position: absolute; right: calc(12px + env(safe-area-inset-right, 0px)); bottom: calc(156px + env(safe-area-inset-bottom, 0px)); z-index: 34;
  font-size: 12px; font-weight: 700; line-height: 1; color: var(--game-ink);
  border: 3px solid var(--game-border); border-radius: 999px; padding: 0 12px; height: 28px;
  background: #fff; cursor: pointer; box-shadow: 0 2px 8px rgba(0, 0, 0, .20); white-space: nowrap;
  transition: transform var(--dur) var(--ease), background-color var(--dur-fast) var(--ease);
}
#wx-chip:hover { background: var(--bg-solid); }
#wx-chip:active { transform: scale(.94); }
/* Efeitos de clima: o chip É o toggle (2026-11-10). OFF (padrão) =
   apagado/cinza; ON = cheio, com borda de acento — o estado se lê só
   olhando. A temperatura continua visível nos dois estados (é
   informação, não efeito). */
#wx-chip.off { opacity: .55; box-shadow: none; }
#wx-chip:not(.off) { border-color: var(--game-border); background: var(--accent); color: var(--accent-fg); }
body.car-collapsed #wx-chip { transform: translateY(82px); }

/* FEATURE 3 — painel de rota e FEATURE 6 — sheet de compartilhar:
   mesmo padrão do Drawer (#sheet): bottom sheet centrado no desktop,
   largura total no celular, slide-up com spring leve. */
#route-panel, #share-sheet {
  position: absolute; left: 50%; bottom: calc(12px + env(safe-area-inset-bottom, 0px)); z-index: 46;
  width: min(440px, calc(100vw - 24px));
  transform: translate(-50%, 140%); opacity: 0;
  transition: transform var(--dur-sheet) var(--ease-spring), opacity var(--dur) var(--ease);
  pointer-events: none;
}
#route-panel.in, #share-sheet.in { transform: translate(-50%, 0); opacity: 1; pointer-events: auto; }
.route-card, .share-card {
  background: var(--bg-solid); color: var(--text); border-radius: 20px;
  border: 1px solid var(--border);
  padding: 8px 16px 14px; font-size: 14px; line-height: 1.45;
  box-shadow: var(--shadow-lg);
  max-height: min(72vh, 560px); overflow-y: auto;
}
.share-head {
  position: relative; display: flex; align-items: center; justify-content: center;
  padding: 6px 8px 10px; border-bottom: 1px solid var(--border); margin-bottom: 10px;
}
.share-head strong { font-size: 14px; font-weight: 600; padding-top: 8px; }
.share-head button {
  position: absolute; right: 4px; top: 8px; width: 32px; height: 32px;
  border: 0; border-radius: 50%; background: var(--hover); color: var(--text-2);
  font-size: 13px; line-height: 1; cursor: pointer;
}
.route-field { margin-bottom: 10px; }
.route-field label { display: block; font-size: 12px; font-weight: 600; color: var(--text-2); }
.route-field select, .share-row select {
  display: block; width: 100%; margin-top: 4px; height: 40px;
  font: inherit; font-size: 14px; color: var(--text);
  background: var(--bg); border: 1px solid var(--border-strong); border-radius: 10px;
  padding: 0 10px; outline: none;
}
.route-field select:focus, .share-row select:focus { border-color: var(--ring); box-shadow: 0 0 0 3px var(--ring); }
#route-info, #share-status {
  font-size: 13px; line-height: 1.45; color: var(--text-2);
  background: var(--bg-soft); border: 1px solid var(--border); border-radius: 10px;
  padding: 8px 12px; margin-bottom: 10px;
}
#share-preview {
  display: block; width: 100%; max-height: 300px; object-fit: contain;
  border-radius: 12px; border: 1px solid var(--border); margin-bottom: 10px;
  background: #1a2420;
}
.share-ratios { display: flex; gap: 8px; margin-bottom: 10px; }
.share-ratios button {
  flex: 1; font: inherit; font-size: 13px; font-weight: 600; min-height: 40px;
  border: 1px solid var(--border-strong); border-radius: 10px;
  background: var(--bg); color: var(--text); cursor: pointer;
  transition: transform var(--dur) var(--ease), background-color var(--dur-fast) var(--ease);
}
.share-ratios button.on { background: var(--accent); border-color: transparent; color: var(--accent-fg); }
.share-ratios button:active { transform: scale(.97); }
.share-row { margin-bottom: 10px; }
.share-row label { display: block; font-size: 12px; font-weight: 600; color: var(--text-2); margin-bottom: 4px; }
#share-caption {
  display: block; width: 100%; box-sizing: border-box; resize: none;
  font: inherit; font-size: 13px; line-height: 1.4; color: var(--text);
  background: var(--bg); border: 1px solid var(--border-strong); border-radius: 10px;
  padding: 8px 10px; margin-bottom: 8px; outline: none;
}
#share-copy-caption {
  font: inherit; font-size: 13px; border: 0; border-radius: 10px; padding: 8px 12px; min-height: 36px;
  background: var(--hover); color: var(--text); cursor: pointer;
}
.share-actions { display: flex; gap: 8px; }
.share-actions button {
  flex: 1; font: inherit; font-weight: 600; border: 0; border-radius: 10px; padding: 10px 12px; min-height: 44px;
  background: var(--primary); color: var(--primary-fg); cursor: pointer;
  transition: transform var(--dur) var(--ease), opacity var(--dur-fast) var(--ease);
}
.share-actions button:disabled { opacity: .45; cursor: default; }
.share-actions button:not(:disabled):active { transform: scale(.98); }
#route-clear, #share-web { background: var(--hover); color: var(--text); font-weight: 400; }

/* FEATURE 3 — marcadores A/B da rota (overlays do OSD, como os pins). */
.route-marker {
  width: 26px; height: 26px; padding: 0; border: 2px solid #fff; border-radius: 50%;
  color: #fff; font: bold 13px/22px system-ui, sans-serif; text-align: center;
  pointer-events: none; box-shadow: 0 1px 6px rgba(0, 0, 0, .6);
}
.route-marker-a { background: #16a34a; }
.route-marker-b { background: #dc2626; }

/* Botão flutuante de fallback (só aparece se o menu "mais" não existir
   para receber as linhas de Rota/Compartilhar). */
.fx-fallback-btn {
  position: absolute; right: calc(12px + env(safe-area-inset-right, 0px)); bottom: calc(180px + env(safe-area-inset-bottom, 0px)); z-index: 34;
  width: 44px; height: 44px; border: 1px solid var(--border); border-radius: 50%;
  background: var(--bg); color: var(--text); font-size: 19px; cursor: pointer;
  box-shadow: var(--shadow);
  -webkit-backdrop-filter: blur(12px) saturate(1.2);
  backdrop-filter: blur(12px) saturate(1.2);
}
#share-fallback-btn { bottom: calc(232px + env(safe-area-inset-bottom, 0px)); }

@media (max-width: 640px) {
  /* Painéis de rota/share viram bottom sheet de verdade no celular. */
  #route-panel, #share-sheet { left: 0; right: 0; bottom: 0; width: 100%; transform: translateY(110%); }
  #route-panel.in, #share-sheet.in { transform: translateY(0); }
  .route-card, .share-card { border-radius: 20px 20px 0 0; padding-bottom: calc(14px + env(safe-area-inset-bottom, 0px)); }
  /* Chip do clima: acima do carrossel no celular. */
  #wx-chip { right: calc(8px + env(safe-area-inset-right, 0px)); bottom: calc(124px + env(safe-area-inset-bottom, 0px)); }
  body.car-collapsed #wx-chip { transform: translateY(82px); }
}

/* ================================================================
   Redesign v=h (2026-11-10) — barra inferior, modo captura,
   foto no cartão de lugar, busca mobile.
   ================================================================ */

/* --- Foto no cartão de lugar (Tiny SP): imagem no topo do sheet. --- */
/* (A foto do card compacto — 96×96 — está nas regras do #sheet acima;
   a foto grande de 180 px do sheet antigo saiu no v=z.) */

/* --- Barra inferior (Tiny SP, só no celular): Lugares / Buscar /
       Ver tudo — sempre ao alcance do polegar. --- */
#tabbar { display: none; }

/* --- Modo captura (modo câmera do Compartilhar): o mapa vira o
       visor; o guia mostra exatamente o que vai sair na foto. --- */
#capture-ui { position: absolute; inset: 0; z-index: 70; pointer-events: none; }
#capture-ui[hidden] { display: none; }
#capture-guide { position: absolute; inset: 0; overflow: hidden; }
.cg-mask { position: absolute; background: rgba(0, 0, 0, .45); }
.cg-frame {
  position: absolute; border: 2px solid rgba(255, 255, 255, .95); border-radius: 6px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .3), inset 0 0 0 1px rgba(0, 0, 0, .15);
  /* v=o: border-box — a borda de 2 px fica DENTRO da largura/altura
     setada (content-box empurrava o quadro 4 px p/ fora: a borda
     direita saía 4 px da tela no celular). Com border-box, a borda
     externa do quadro é exatamente o `sel` que o render captura. */
  box-sizing: border-box;
}
#capture-close {
  position: absolute; top: calc(12px + env(safe-area-inset-top, 0px) + var(--safari-scroll-offset)); right: calc(12px + env(safe-area-inset-right, 0px));
  width: 38px; height: 38px; border: 0; border-radius: 50%;
  background: rgba(0, 0, 0, .55); color: #fff; font-size: 15px; line-height: 1;
  cursor: pointer; pointer-events: auto; backdrop-filter: blur(8px);
  transition: transform var(--dur) var(--ease);
}
#capture-close:active { transform: scale(.9); }
#capture-bar {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: calc(28px + env(safe-area-inset-bottom, 0px));
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  pointer-events: none;
}
.capture-ratios {
  display: flex; gap: 4px; padding: 4px; border-radius: 999px;
  background: rgba(0, 0, 0, .55); backdrop-filter: blur(8px); pointer-events: auto;
}
.capture-ratios button {
  border: 0; border-radius: 999px; padding: 8px 14px;
  font: inherit; font-size: 13px; font-weight: 600; white-space: nowrap;
  background: transparent; color: rgba(255, 255, 255, .85); cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.capture-ratios button.on { background: #fff; color: #111; }
/* Tilt-shift (v=ab): pílula na barra de captura, mesmo estilo dos
   formatos. "on" = o snapshot sai com o efeito de miniatura. */
#capture-tilt {
  border: 0; border-radius: 999px; padding: 8px 14px;
  font: inherit; font-size: 13px; font-weight: 600; white-space: nowrap;
  background: rgba(0, 0, 0, .55); color: rgba(255, 255, 255, .85); cursor: pointer;
  backdrop-filter: blur(8px); pointer-events: auto;
  transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
#capture-tilt.on { background: #fff; color: #111; }
#capture-btn {
  width: 74px; height: 74px; border-radius: 50%; padding: 0;
  border: 4px solid #fff; background: rgba(255, 255, 255, .22);
  cursor: pointer; pointer-events: auto;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 2px 16px rgba(0, 0, 0, .45);
  transition: transform var(--dur) var(--ease);
}
#capture-btn:active { transform: scale(.9); }
#capture-btn span { display: block; width: 56px; height: 56px; border-radius: 50%; background: #fff; }
/* No modo captura a HUD some (só obturador + ✕ + formato). O avião,
   o barquinho e o marcador da busca NÃO entram na foto — somem do
   visor também (o que está no visor é o que sai na foto). v=ab: os
   pins dos landmarks também somem no modo captura (modo foto) — a
   foto sai limpa, sem pins. */
body.capture-mode #search, body.capture-mode #rail, body.capture-mode #carousel,
body.capture-mode #car-toggle, body.capture-mode #minimap-wrap, body.capture-mode #wx-chip,
body.capture-mode #hud, body.capture-mode #brand, body.capture-mode #tabbar,
body.capture-mode #attr, body.capture-mode #toast, body.capture-mode #top-pills { display: none !important; }
body.capture-mode .boat, body.capture-mode .pin, body.capture-mode .lm-pin, body.capture-mode .soon-pill { display: none !important; }
/* Esconder pins no mapa ao vivo (v=ab, toggle no menu ⋯ — "Esconder
   pins"): p/ tirar um screenshot limpo com o celular, sem entrar no
   modo captura. */
body.pins-hidden .lm-pin, body.pins-hidden .soon-pill { display: none !important; }

/* --- Carrossel: a máscara desbotava 24 px nas bordas (o card da
       ponta parecia cortado). Suaviza p/ 12 px + respiro no fim. --- */
#carousel-track {
  -webkit-mask-image: linear-gradient(to right, transparent, black 12px, black calc(100% - 12px), transparent);
  mask-image: linear-gradient(to right, transparent, black 12px, black calc(100% - 12px), transparent);
  padding-right: 12px;
}

@media (max-width: 640px) {
  /* Barra inferior fixa no celular. */
  #tabbar {
    display: flex; gap: 6px;
    position: absolute; left: 50%; transform: translateX(-50%);
    bottom: calc(8px + env(safe-area-inset-bottom, 0px)); z-index: 34;
    background: rgba(18, 24, 20, .92); border-radius: 999px; padding: 5px;
    box-shadow: var(--shadow-lg);
  }
  #tabbar button {
    border: 3px solid var(--game-border); border-radius: 999px; padding: 10px 13px;
    font: inherit; font-size: 13px; font-weight: 700; white-space: nowrap;
    background: #fff; color: var(--game-ink); cursor: pointer;
    box-shadow: 0 2px 8px rgba(0, 0, 0, .20);
    transition: transform var(--dur) var(--ease);
  }
  #tabbar button:active { transform: scale(.94); }
  /* A busca some do topo no celular e abre pela tabbar (largura total). */
  body:not(.search-open) #search { display: none; }
  body.search-open #search { display: block; }
  /* A pílula "Lugares" do carrossel some no celular — a tabbar tem
     o botão Lugares, que faz o mesmo. */
  #car-toggle { display: none; }
  /* A pilha do rodapé sobe p/ dar lugar à tabbar (46 px + respiro). */
  #carousel { bottom: calc(64px + env(safe-area-inset-bottom, 0px)); }
  #minimap-wrap { bottom: calc(196px + env(safe-area-inset-bottom, 0px)); }
  body.car-collapsed #minimap-wrap { transform: translateY(132px); }
  #wx-chip { bottom: calc(196px + env(safe-area-inset-bottom, 0px)); }
  body.car-collapsed #wx-chip { transform: translateY(132px); }
}
