/* ===== v2026 · iframe overlay =====
   .desktop-overlay  → janela de tela cheia reaproveitada: o desktop Ubuntu
   (iframe cross-origin em /) e as estações de /labs (alice, llms.txt,
   embedding), trocadas por openOverlay() em js/panels.js.
   z-index acima do `.panel.panel-full` (60): a estação de lab mantém o painel
   aberto embaixo, e com valores iguais o painel — que vem depois no DOM —
   pintaria por cima do overlay. */
.desktop-overlay {
    position: fixed;
    inset: 0;
    z-index: 70;
    display: flex;
    flex-direction: column;
    background: rgba(3, 6, 15, 0.96);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.35s ease;
}
.desktop-overlay[data-open="true"] {
    opacity: 1;
    pointer-events: auto;
}
.desktop-bar {
    flex: 0 0 auto;
    display: flex; align-items: center; gap: 14px;
    padding: 10px 16px;
    border-bottom: 1px solid var(--border);
    background: linear-gradient(180deg, rgba(8, 14, 28, 0.92), rgba(5, 9, 20, 0.82));
    font-family: var(--font-mono);
    font-size: 12px;
    letter-spacing: 0.06em;
}
.desktop-traffic {
    display: inline-flex; gap: 8px;
    align-items: center;
}
.desktop-traffic .tl {
    appearance: none;
    width: 13px; height: 13px;
    padding: 0;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.22);
    box-shadow: inset 0 0 0 0.5px rgba(255, 255, 255, 0.18);
    display: inline-flex;
    align-items: center; justify-content: center;
    font: 700 9px/1 var(--font-mono);
    color: rgba(0, 0, 0, 0.55);
    text-decoration: none;
    cursor: pointer;
    transition: filter 0.2s ease, transform 0.12s ease;
}
.desktop-traffic .tl::before {
    content: "";
    opacity: 0;
    transition: opacity 0.15s ease;
}
.desktop-traffic:hover .tl-r::before { content: "×"; opacity: 1; }
.desktop-traffic:hover .tl-y::before { content: "−"; opacity: 1; }
.desktop-traffic:hover .tl-g::before { content: "↗"; opacity: 1; font-size: 8px; }
.desktop-traffic .tl-r { background: #ff5f56; }
.desktop-traffic .tl-y { background: #ffbd2e; cursor: default; }
.desktop-traffic .tl-g { background: #27c93f; }
.desktop-traffic .tl-r:hover,
.desktop-traffic .tl-g:hover { filter: brightness(1.15); transform: scale(1.08); }
.desktop-traffic .tl-r:focus-visible,
.desktop-traffic .tl-g:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.desktop-title {
    flex: 1 1 auto;
    display: inline-flex; align-items: baseline; gap: 8px;
    color: var(--fg-dim);
    text-transform: lowercase;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.desktop-prompt {
    color: var(--accent);
    font-weight: 700;
}
.desktop-name {
    color: var(--fg);
    font-weight: 600;
    letter-spacing: 0.08em;
}
.desktop-sep { color: var(--fg-mute); }
.desktop-host { color: var(--fg-mute); font-size: 11px; }
.desktop-frame {
    flex: 1 1 auto;
    position: relative;
    overflow: hidden;
    background: #03060f;
}
#desktop-iframe {
    position: absolute;
    inset: 0;
    width: 100%; height: 100%;
    border: 0;
    background: transparent;
    /* let the iframe receive all its own input */
    touch-action: auto;
}

@media (max-width: 640px) {
    .desktop-bar  { padding: 8px 10px; gap: 10px; }
    .desktop-host { display: none; }
    .desktop-sep  { display: none; }
}

/* ===== v2026 · overlay do percurso =====
   Tela cheia, mesma moldura das estações de lab (.desktop-overlay): o cartão de
   760 px que existia aqui antes espremia um traço de 100 km em meia tela, e os
   nomes das cidades ao redor — que é justamente o que situa o percurso —
   ficavam pequenos demais para ler. z-index 75 fica acima do overlay de iframe
   (70): os dois nunca abrem juntos, mas se abrissem o mapa é o de cima porque
   foi o último pedido. */
/* O overlay começa ABAIXO do header e do menu — o mesmo chrome que fica visível
   quando um painel de laboratório abre. `--trip-top` é medido em runtime por
   `anchorBelowChrome()`, porque o menu some no mobile e o `--pad` é um `clamp`:
   qualquer número fixo aqui erraria em algum tamanho de tela. O fallback `0px`
   cobre o caso de o JS não ter rodado ainda. */
.trip-overlay {
    position: fixed;
    top: var(--trip-top, 0px);
    right: 0; bottom: 0; left: 0;
    /* Acima do painel (60) e das estações de lab. Já esteve em 25 — abaixo do `.hud`
       (30), para o chrome ficar clicável — e isso quebrou o caso mais comum de todos:
       clicar no chip com um painel aberto abria o mapa ATRÁS dele, e a tela não
       mudava. Medido em `/labs`: painel 60, overlay 25.
       O chrome continua por cima, mas por outro caminho — ver `body[data-trip]`. */
    z-index: 75;
    display: flex;
    flex-direction: column;
    background: rgba(3, 6, 15, 0.96);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease;
}
.trip-overlay[data-open="true"] { opacity: 1; pointer-events: auto; }

/* Com o mapa aberto, o header e o menu sobem acima dele.
   Não dá para resolver só com z-index fixo: o overlay precisa ficar acima do painel
   (60) e o chrome acima do overlay, e `.hud` vale 30 para conviver com os OUTROS
   overlays (o do desktop, que é tela cheia de propósito e deve cobrir tudo). A classe
   no `body` limita a inversão ao tempo em que o mapa está aberto. */
body[data-trip="open"] .hud-top,
body[data-trip="open"] .hud-menu { z-index: 80; }

.trip-card {
    position: relative;
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    width: 100%;
    min-height: 0;
    overflow: hidden;
    background: linear-gradient(180deg, rgba(8, 14, 28, 0.92), rgba(5, 9, 20, 0.82));
}

.trip-bar {
    flex: 0 0 auto;
    display: flex; align-items: center; gap: 14px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--border);
    font-family: var(--font-mono);
    font-size: 12px;
    letter-spacing: 0.06em;
}
/* Com a pílula de cidades na barra, o título encolhe ao próprio texto: com
   `flex: 1` ele esticava por toda a sobra e a pílula boiava a 200px do texto,
   parecendo solta em vez de encadeada. Quem passa a empurrar os botões de camada
   para a direita é o `margin-right: auto` da pílula. */
.trip-bar:has(.via-dock.is-docked:not([hidden])) .trip-title { flex: 0 1 auto; }

.trip-title {
    flex: 1 1 auto;
    display: inline-flex; align-items: baseline; gap: 8px;
    min-width: 0;
}
.trip-icon  { font-size: 13px; }

/* ===== Seletor de mapa — pills na barra do overlay ===== */
.trip-maps {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 4px;
    /* Rola em vez de quebrar: a barra tem uma linha, e sete pills numa janela estreita
       empurrariam a rota para fora. `-webkit-overflow-scrolling` mantém a inércia no
       iOS, onde a barra é o lugar mais provável de faltar espaço. */
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    max-width: min(52vw, 460px);
}
.trip-maps::-webkit-scrollbar { display: none; }

.trip-map-pill {
    flex: 0 0 auto;
    appearance: none;
    padding: 4px 11px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.03);
    color: var(--fg-dim);
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.04em;
    cursor: pointer;
    white-space: nowrap;
    /* `transform` e `opacity` na transição, não `background`: são as duas propriedades
       que o compositor anima sem recalcular layout, e a barra fica por cima de um mapa
       que já está desenhando tiles. */
    transition: color 0.18s ease, border-color 0.18s ease, background 0.18s ease, transform 0.12s ease;
}
.trip-map-pill:hover {
    color: var(--fg);
    border-color: var(--border-2);
    background: rgba(255, 255, 255, 0.07);
}
.trip-map-pill:active { transform: scale(0.95); }
.trip-map-pill:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
/* A ativa se acende. `box-shadow` em vez de borda mais grossa: borda mudaria a largura
   da pill e as vizinhas dariam um pulo a cada troca. */
.trip-map-pill[data-on="true"] {
    color: #06121f;
    background: var(--accent);
    border-color: var(--accent);
    font-weight: 600;
    box-shadow: 0 0 12px rgba(87, 224, 255, 0.35);
}

@media (max-width: 900px) {
    .trip-maps { max-width: 42vw; }
    .trip-map-pill { padding: 4px 9px; font-size: 10px; }
}
@media (max-width: 640px) {
    /* Na tela pequena a rota já ocupa a linha. As pills descem para a segunda,
       roláveis — some seria tirar a escolha de quem está no celular. */
    .trip-bar { flex-wrap: wrap; row-gap: 6px; }
    .trip-maps { max-width: 100%; order: 3; width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
    .trip-map-pill { transition: none; }
    .trip-map-pill:active { transform: none; }
}
.trip-route { color: var(--fg); font-weight: 600; letter-spacing: 0.04em;
              white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Cinza quase branco, cor literal em vez de `--fg-mute`. O token vale #3e4663 —
   azul escuro que some no fundo do overlay (rgba(8,14,28)): a linha "última
   viagem · ontem · confiança 72%" ficava ilegível. Aqui ela é informação, não
   ornamento; quem recua é o peso da fonte, não o contraste. */
.trip-meta  { color: #ccd6ec; font-size: 11px; white-space: nowrap; }

/* Sem `aspect-ratio`: o palco ocupa o que sobrar entre a barra e o rodapé. Era o
   4/3 que prendia o mapa ao formato de cartão — em tela cheia ele deixaria faixa
   morta em qualquer janela que não fosse 4/3. */
.trip-stage {
    position: relative;
    flex: 1 1 auto;
    min-height: 0;
    background: #0d1117;
}
/* Leaflet mede o container no momento da criação. Sem altura resolvida aqui o
   mapa nasce colapsado — e colapsado ele não emite erro nenhum, só fica preto. */
.trip-stage .leaflet-container {
    width: 100%; height: 100%;
    background: #0d1117;
    font-family: var(--font-mono);
    outline: none;
}
.tm-fallback {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    margin: 0; padding: 0 24px;
    text-align: center;
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--fg-mute);
}

/* Controles do Leaflet vestidos com o HUD — o padrão é branco de app de mapa e
   destoa do resto do cartão. */
.trip-stage .leaflet-bar {
    border: 1px solid var(--border-2);
    box-shadow: none;
}
.trip-stage .leaflet-bar a {
    background: rgba(8, 14, 28, 0.92);
    color: var(--fg);
    border-bottom-color: var(--border);
}
.trip-stage .leaflet-bar a:hover,
.trip-stage .leaflet-bar a:focus { background: rgba(16, 26, 48, 0.96); color: var(--accent); }
.trip-stage .leaflet-control-attribution {
    background: rgba(3, 6, 15, 0.74);
    color: var(--fg-mute);
    font-family: var(--font-mono);
    font-size: 9px;
    padding: 2px 6px;
}
.trip-stage .leaflet-control-attribution a { color: var(--fg-mute); }

/* Vetores por cima do tile. As classes vêm do `className` das options do
   Leaflet; CSS vence os atributos de apresentação que ele escreve no path.

   Calibrados para o tile CLARO (CARTO voyager). O ciano do HUD, que funcionava
   sobre o `dark_all`, some sobre bege — aqui a régua é o contraste com o mapa,
   não a paleta do site. O halo branco por baixo do traço é o que separa a rota
   das rodovias impressas no tile, que também são linhas claras e grossas. */
.tm-uf {
    fill: rgba(12, 32, 64, 0.04);
    stroke: rgba(12, 32, 64, 0.42);
    stroke-width: 1.2;
    stroke-linejoin: round;
}
/* A célula É a precisão publicada: 0,1° (~10 km), o arredondamento aplicado no
   edge. Desenhá-la diz o tamanho do erro sem uma linha de texto — e o tracejado
   deixa claro que é área de incerteza, não trajeto. */
.tm-cell {
    fill: rgba(16, 96, 200, 0.09);
    stroke: rgba(16, 96, 200, 0.55);
    stroke-width: 1;
    stroke-dasharray: 5 5;
}
.tm-track-glow {
    fill: none;
    stroke: rgba(255, 255, 255, 0.9);
    stroke-width: 13;
    stroke-linecap: round; stroke-linejoin: round;
}
.tm-track {
    fill: none;
    stroke: #0d5fd6;
    stroke-width: 4.4;
    stroke-linecap: round; stroke-linejoin: round;
}
/* O que ainda FALTA, do carro até o destino. Tracejado e translúcido porque é
   previsão em linha reta, não rastro: o carro não passou por ali, e traço cheio
   afirmaria que passou. Mais fino que o percorrido pela mesma razão — o que já
   aconteceu tem mais direito à tinta que o que talvez aconteça. */
.tm-ahead {
    fill: none;
    stroke: rgba(13, 95, 214, 0.42);
    stroke-width: 3;
    stroke-dasharray: 9 8;
    stroke-linecap: round;
}
.tm-pin-a { fill: #0a9c72; fill-opacity: 1; stroke: #fff; stroke-width: 2.5; }
.tm-pin-b { fill: #6a3fd6; fill-opacity: 1; stroke: #fff; stroke-width: 2.5; }

/* Rótulo colado em A e B: é o que responde "de onde para onde" sem obrigar o
   visitante a reconhecer a mancha urbana no tile. */
.tm-tip {
    background: rgba(3, 6, 15, 0.92);
    border: 1px solid rgba(255, 255, 255, 0.28);
    border-radius: 5px;
    box-shadow: 0 1px 6px rgba(0, 0, 0, 0.35);
    padding: 4px 10px;
    font-family: var(--font-mono);
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.05em;
    white-space: nowrap;
    color: var(--fg);
}
.tm-tip::before { display: none; }      /* a seta branca do Leaflet não combina */
/* Segunda linha do rótulo: o número. Menor e em itálico falso (é um `<i>` sem
   itálico de verdade — a fonte mono não tem um bom) para o olho separar o dado do
   nome sem precisar de linha divisória. */
.tm-stat {
    display: block;
    margin-top: 2px;
    font-style: normal;
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.02em;
    opacity: 0.82;
}
.tm-pin-a-tip { color: #5bf0c8; }
.tm-pin-b-tip { color: #b08bff; }

/* Cidade por onde o carro está passando. Mais forte que A e B de propósito: é o
   único rótulo que muda sozinho, e é a resposta à pergunta "onde ele está agora". */
.tm-car-tip {
    color: #57e0ff;
    border-color: rgba(87, 224, 255, 0.55);
    box-shadow: 0 0 12px rgba(87, 224, 255, 0.28);
    font-weight: 600;
}

.tm-car-icon { background: none; border: 0; }
.tm-car {
    display: block;
    /* Proporção do arquivo (84×210). O elemento é um `<img>`, não um `<svg>`
       inline: as regras de cor abaixo (`tm-car-body` e companhia) não o alcançam,
       e é de propósito — as cores são as do desenho fornecido. */
    width: 26px; height: 65px;
    overflow: visible;
    transform-origin: 50% 50%;
    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.45));
    /* O ícone é decorativo e o arrasto do mapa tem de passar por ele. */
    pointer-events: none;
    -webkit-user-drag: none;
    user-select: none;
}
/* Ciano ACINZENTADO, não o ciano da marca.
   O `--accent` puro (#6fd6ff) sobre tile claro lia como branco: o carro clareava até
   quase sumir no fundo, e o contorno branco de 1,6 ainda somava. Aqui a carroceria é
   um ciano puxado para o aço (#6E9CB2) e o contorno perdeu peso e opacidade — o carro
   continua se destacando das rodovias, que também são linhas claras e grossas, sem
   virar uma mancha branca.
   O ciano da marca segue vivo no halo do `is-live` e no glow, onde ele brilha em vez
   de competir com o tile. */
.tm-car-body {
    fill: #6E9CB2;
    stroke: rgba(255, 255, 255, 0.72);
    stroke-width: 1.2;
}
.tm-car-glass { fill: rgba(6, 20, 38, 0.9); }
.tm-car-wheel { fill: rgba(6, 14, 32, 0.92); }

/* Só a viagem EM CURSO pulsa. O halo é a única coisa da tela que diz "isto é
   agora" — pôr o mesmo pulso numa viagem de dois dias atrás faria a página
   inteira mentir sobre estar ao vivo. */
.tm-car-icon.is-live::after {
    content: '';
    position: absolute;
    left: 50%; top: 50%;
    width: 30px; height: 30px;
    margin: -15px 0 0 -15px;
    border-radius: 50%;
    background: rgba(87, 224, 255, 0.35);
    animation: tm-pulse 2s ease-out infinite;
    pointer-events: none;
}
@keyframes tm-pulse {
    0%   { transform: scale(0.6); opacity: 0.75; }
    100% { transform: scale(2.6); opacity: 0; }
}

.trip-foot {
    flex: 0 0 auto;
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 8px 14px;
    border-top: 1px solid var(--border);
    font-family: var(--font-mono);
    font-size: 10px;
    letter-spacing: 0.04em;
    /* Mesmo motivo da `.trip-meta`, um passo abaixo: a nota de privacidade é
       secundária, mas precisa ser lida — é ela que diz por que o traço é grosso. */
    color: #9aa6c2;
}
.trip-hist { color: var(--accent); }

/* O ☰ MENU é `position: fixed` no canto inferior direito com z-index 85 — fica
   POR CIMA do overlay. Sem reservar a faixa, a nota do rodapé passa por baixo
   dele e some no meio da palavra ("…não são publicad"). Mesma condição que faz
   o fab nascer, em `css/responsive.css`. */
@media (max-width: 900px), (pointer: coarse) and (max-height: 500px) {
    .trip-foot { padding-right: 150px; }
}

/* Tela estreita: o mapa é o conteúdo, então quem encolhe é o cromo em volta.
   Rótulo e carro caem junto — em 360 px de largura os 13 px do tooltip cobriam
   o traço que eles deveriam explicar. */
@media (max-width: 640px) {
    .trip-bar   { padding: 8px 10px; gap: 10px; }
    .trip-meta  { display: none; }
    .trip-foot  { font-size: 9px; }
    .tm-tip     { font-size: 11px; padding: 3px 7px; }
    .tm-car     { width: 24px; height: 40px; }
    .tm-car-icon.is-live::after { width: 24px; height: 24px; margin: -12px 0 0 -12px; }
    .trip-stage .leaflet-control-attribution { font-size: 8px; }
}
/* Movimento reduzido: sem replay (o JS nem agenda o rAF) e sem pulso. A posição
   continua legível — ela é o conteúdo; a animação é só o que a apresenta. */
@media (prefers-reduced-motion: reduce) {
    .trip-overlay, .trip-card { transition: none; }
    .tm-car-icon.is-live::after { animation: none; opacity: 0; }
}


/* ===== /trip sem viagem — o estado NORMAL do endereço, não uma falha ===== */
.trip-empty {
    position: absolute; inset: 0;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    gap: 26px;
    padding: 24px;
    text-align: center;
}
/* A estrada encolhe com a tela em vez de estourar: `min()` contra a largura da
   viewport e um teto em px para não virar um paredão no monitor grande. */
.te-road { width: min(82vw, 560px); height: auto; overflow: visible; }
.te-line {
    fill: none;
    stroke: rgba(111, 214, 255, 0.34);
    stroke-width: 3.4;
    stroke-linecap: round;
    stroke-dasharray: 11 10;
    /* O traço se acende atrás do carro — a estrada "existe" na medida em que ele
       passa. 520 cobre o comprimento da curva com folga; sobra vira atraso, falta
       deixaria o traço aparecendo pela metade. */
    stroke-dashoffset: 520;
    animation: te-pave 3.1s cubic-bezier(0.42, 0, 0.22, 1) 0.3s forwards;
}
@keyframes te-pave { to { stroke-dashoffset: 0; } }

.te-a { fill: #0a9c72; }
.te-b { fill: #6a3fd6; }
.te-a, .te-b { stroke: rgba(255, 255, 255, 0.55); stroke-width: 2; }
/* Halo pulsando no destino: é o único elemento que continua vivo depois que o
   carro para, e é ele que diz "esperando a próxima viagem" sem uma linha de texto. */
.te-halo {
    fill: none;
    stroke: #6a3fd6;
    stroke-width: 2;
    transform-origin: 300px 30px;
    animation: te-wait 2.6s ease-out 3.2s infinite;
    opacity: 0;
}
@keyframes te-wait {
    0%   { opacity: 0.55; transform: scale(1); }
    70%  { opacity: 0;    transform: scale(2.6); }
    100% { opacity: 0;    transform: scale(2.6); }
}

/* O carro é o MESMO desenho do mapa, agora DENTRO do svg — ver o comentário em
   `showEmpty()` sobre por que `offset-path` num elemento HTML não servia. */
.te-car { filter: drop-shadow(0 0 8px rgba(111, 214, 255, 0.5)); }
/* A pintura vem das regras de `.tm-car-*` acima — as duas telas usam o MESMO carro,
   e é justamente isso que faz o desenho do estado vazio anunciar o do mapa. */

.te-title {
    margin: 0;
    font-family: var(--font-mono);
    font-size: clamp(15px, 2.4vw, 20px);
    letter-spacing: 0.06em;
    color: var(--fg);
}

/* Quem pediu menos movimento recebe o desenho PRONTO, não uma versão pobre: a
   estrada inteira, o carro no fim do percurso e o halo parado. */
@media (prefers-reduced-motion: reduce) {
    .te-line { animation: none; stroke-dashoffset: 0; }
    .te-halo { animation: none; opacity: 0.4; }
}


/* ===== Chip do HUD em viagem: a barra de progresso ===== */
.wx-route { white-space: nowrap; }

/* Segunda linha do chip: barra à esquerda ocupando o que sobra, número à direita.
   A largura vem do NOME (a linha de cima), então a barra encolhe conforme o texto do
   "faltam N km" cresce — e nunca empurra o relógio do HUD. */
.wx-line {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
}
.wx-left {
    flex: 0 0 auto;
    font-size: 10.5px;
    font-weight: 500;
    letter-spacing: 0.02em;
    color: #9fb6d4;
    white-space: nowrap;
}

/* Largura do NOME, não um valor fixo: o trilho fica embaixo do texto e alinhado com
   ele, então o preenchimento se lê como o trecho já andado daquela rota. Com 72 px ao
   lado, era um traço solto que não dizia a que se referia. */
.wx-rail {
    position: relative;
    display: block;
    flex: 1 1 auto;
    min-width: 40px;   /* abaixo disto o carro cobre a barra inteira e o progresso some */
    /* 3 → 5 px. Em 3 o trilho lia como sublinhado do texto, não como barra, e o carro
       de 12 px em cima dele parecia flutuar solto. Em 5 os dois se leem como um
       conjunto — e ainda cabe na altura do HUD sem empurrar nada. */
    height: 5px;
    border-radius: 3px;
    background: rgba(207, 224, 245, 0.24);
}
.wx-fill {
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: var(--p, 0%);
    border-radius: 3px;
    /* As cores do TRAÇO do mapa, não a paleta genérica do HUD. O verde-água → ciano
       que havia aqui não existia em lugar nenhum do percurso; agora a barra sai do
       mesmo azul do trecho percorrido (`.tm-track`, #0d5fd6) e clareia até o ciano da
       carroceria. Quem viu o mapa reconhece a barra, e vice-versa. */
    background: linear-gradient(90deg, #0d5fd6, #6EC8E8);
    /* Transição, não animação: quando o ponto novo chega, o preenchimento DESLIZA até
       a marca nova em vez de saltar. É o mesmo movimento do carro logo abaixo, e é o
       que faz o chip parecer ao vivo sem nada piscando. */
    transition: width 0.7s cubic-bezier(0.33, 0, 0.2, 1);
}
/* Brilho correndo sobre o trecho já percorrido. Discreto e lento: o chip fica no topo
   de todas as páginas, e um efeito chamativo ali cansa em trinta segundos. */
.wx-fill::after {
    content: '';
    position: absolute; inset: 0;
    border-radius: 3px;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.55), transparent);
    background-size: 40% 100%;
    background-repeat: no-repeat;
    animation: wx-shine 2.8s ease-in-out infinite;
}
@keyframes wx-shine {
    0%   { background-position: -40% 0; }
    60%  { background-position: 140% 0; }
    100% { background-position: 140% 0; }
}

.wx-car {
    position: absolute;
    left: var(--p, 0%);
    top: 50%;
    /* Cresce junto com o trilho: aumentar só a barra deixaria o carro pequeno demais
       para se reconhecer como veículo, que é o ponto dele estar ali. */
    font-size: 14px;
    line-height: 1;
    font-style: normal;
    /* O `-50%` horizontal centra o carro NA marca do progresso: sem ele o emoji começa
       na marca e o veículo inteiro fica adiantado em relação ao que a barra afirma. */
    transform: translate(-50%, -50%);
    transition: left 0.7s cubic-bezier(0.33, 0, 0.2, 1);
    filter: drop-shadow(0 0 4px rgba(87, 224, 255, 0.6));
    pointer-events: none;
}
/* ── Barra INDETERMINADA: em movimento, destino desconhecido ──
   Sem `to` não há total, e sem total não existe percentual — fingir um seria inventar.
   Mas sumir com a barra também mente, porque ele ESTÁ andando. O segmento correndo de
   ponta a ponta é o que "carregando sem total conhecido" significa em qualquer
   interface: informa o movimento sem afirmar a fração. */
.wx-rail.is-indeterminate .wx-fill {
    width: 34%;
    transition: none;
    animation: wx-run 1.9s cubic-bezier(0.5, 0, 0.5, 1) infinite;
}
/* O brilho de dentro sai de cena: dois movimentos no mesmo elemento viram ruído, e
   aqui quem carrega o significado é o segmento. */
.wx-rail.is-indeterminate .wx-fill::after { animation: none; opacity: 0; }
@keyframes wx-run {
    0%   { transform: translateX(-110%); }
    100% { transform: translateX(320%); }
}
@media (prefers-reduced-motion: reduce) {
    /* Sem correr: fica um segmento parado à esquerda, que ainda diz "sem total
       conhecido" sem nada se mexendo. */
    .wx-rail.is-indeterminate .wx-fill { animation: none; transform: none; }
}

/* Quem pediu menos movimento fica com a barra e o carro na posição certa — o que sai
   é o deslizar e o brilho, não a informação. */
@media (prefers-reduced-motion: reduce) {
    .wx-fill, .wx-car { transition: none; }
    .wx-fill::after { animation: none; opacity: 0; }
}

@media (max-width: 640px) {
    /* No celular o chip disputa a linha com relógio e bandeiras, e o nome já quebra:
       a barra some e fica o texto, que ainda diz que ele está viajando. */
    .wx-rail { display: none; }
}

/* ── Trilha da viagem — a lista que sai do notch ───────────────────────────
   Filha do `.np-dock`, logo abaixo do notch. A margem negativa a enfia ATRÁS
   dele (z-index menor), então a borda de cima nunca aparece e os dois leem como
   um objeto só que cresceu.

   A lista NÃO tem horário, e isso é desenho: `/api/trip` já apaga todo timestamp
   em `redact()`, e carimbar as faixas devolveria por esta porta a duração da
   viagem e as paradas, por subtração. Sobra a ordem — que é o que interessa. */
.trip-tracks[hidden] { display: none; }

.trip-tracks {
    position: relative;
    z-index: 1;                 /* atrás do notch, dentro do dock */

    /* -18px some com a costura sob a pílula; o padding devolve o espaço por
       dentro, para o cabeçalho não nascer colado no notch. */
    margin-top: -18px;
    padding-top: 18px;

    width: var(--dock-w);
    max-height: min(62vh, 420px);
    display: flex;
    flex-direction: column;

    border: 1px solid rgba(111, 214, 255, 0.42);
    border-top: 0;
    border-radius: 0 0 20px 20px;
    background: rgba(9, 16, 44, 0.96);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    box-shadow: 0 18px 44px rgba(3, 8, 30, 0.7);
    font-family: var(--font-mono);
    overflow: hidden;

    /* O atraso deixa a pílula chegar ao tamanho final primeiro; a lista se revela
       dentro de um recipiente que já parou de crescer. */
    animation: ttOpen 0.30s cubic-bezier(0.22, 1, 0.36, 1) 0.06s both;
    transform-origin: top center;
}

/* Abre revelando de cima para baixo, como se saísse de dentro do notch.
   `clip-path` e não `height`: altura anima mal com conteúdo de tamanho variável
   e força reflow a cada quadro; o recorte é composto na GPU e não mexe no
   layout.
   O leve `translateY` negativo faz a lista parecer EMPURRADA para fora do notch
   em vez de simplesmente desenhada — sem ele o movimento é chapado. */
@keyframes ttOpen {
    from { clip-path: inset(0 0 100% 0); opacity: 0.4; transform: translateY(-6px); }
    to   { clip-path: inset(0 0 0 0);    opacity: 1;   transform: translateY(0); }
}

/* Fechar tinha `hidden` direto: a lista SUMIA num quadro enquanto a pílula ainda
   encolhia com transição — as duas metades do mesmo objeto saíam em tempos
   diferentes, e era isso que ficava estranho. Agora ela recolhe para dentro do
   notch, e só então o elemento é escondido (o JS espera o `animationend`). */
.np-dock.is-closing .trip-tracks {
    animation: ttClose 0.2s cubic-bezier(0.4, 0, 1, 1) both;
}
@keyframes ttClose {
    from { clip-path: inset(0 0 0 0);    opacity: 1;   transform: translateY(0); }
    to   { clip-path: inset(0 0 100% 0); opacity: 0;   transform: translateY(-6px); }
}

@media (prefers-reduced-motion: reduce) {
    .np-dock.is-closing .trip-tracks { animation: none; }
}

.trip-tracks .tt-head {
    flex: 0 0 auto;
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 9px 14px;
    border-bottom: 1px solid var(--border);
    color: var(--accent);
    font-size: 10px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}
.trip-tracks .tt-close {
    appearance: none;
    border: 0; background: none;
    color: var(--accent);
    font-size: 16px; line-height: 1;
    cursor: pointer;
    opacity: 0.7;
    padding: 0 2px;
}
.trip-tracks .tt-close:hover { opacity: 1; }

.trip-tracks .tt-list {
    flex: 1 1 auto;
    overflow-y: auto;
    margin: 0;
    padding: 6px 0;
    list-style: none;
    /* A lista é desenhada da MAIS RECENTE para a mais antiga, mas o número tem de
       ser a posição cronológica: a de cima é a 15ª que tocou, não a 1ª. Por isso
       o contador começa no total (posto pelo JS em `--n`) e DECRESCE. */
    counter-reset: faixa calc(var(--n, 0) + 1);
}
.trip-tracks .tt-list li {
    counter-increment: faixa -1;
    display: flex; gap: 9px;
    padding: 6px 14px;
    font-size: 11px;
    line-height: 1.45;
    color: #d7e0f2;
}
/* ── A lista de CIDADES conta ao contrário da de músicas ───────────────────
   Ela é cronológica: a de cima é a primeira travessia, não a última. Herdando o
   contador decrescente da trilha (que existe porque lá o topo é a faixa mais
   recente), a numeração saía **0, −1, −2, −3** — medido em 09/08/2026, com o
   popup aberto. Aqui o contador nasce em 0 e cresce, dando 1, 2, 3. */
#trip-cities .tt-list { counter-reset: faixa 0; }
#trip-cities .tt-list li { counter-increment: faixa 1; }

.trip-tracks .tt-list li + li { border-top: 1px solid rgba(255, 255, 255, 0.04); }
.trip-tracks .tt-list li::before {
    content: counter(faixa);
    flex: none;
    min-width: 18px;
    color: var(--accent);
    opacity: 0.5;
    text-align: right;
}
/* A linha inteira é clicável e leva à busca no YouTube. `flex: 1` dá ao link a
   largura toda da linha, para o alvo não ser só a extensão do texto. */
.trip-tracks .tt-link {
    flex: 1 1 auto;
    min-width: 0;
    color: inherit;
    text-decoration: none;
    border-radius: 4px;
    transition: color 0.15s ease;
}
.trip-tracks .tt-link:hover .tt-t { color: var(--accent); text-decoration: underline; }
.trip-tracks .tt-link:hover .tt-a { color: #aab6d0; }
.trip-tracks .tt-link:focus-visible {
    outline: 1px solid var(--accent);
    outline-offset: 2px;
}
.trip-tracks .tt-list li:hover { background: rgba(111, 214, 255, 0.05); }

.trip-tracks .tt-t { display: block; }
.trip-tracks .tt-a { display: block; color: #8f9cba; }
/* A faixa que está tocando AGORA, quando a viagem está em curso. */
.trip-tracks .is-now .tt-t { color: var(--accent); }
.trip-tracks .is-now::before { opacity: 1; }


@media (prefers-reduced-motion: reduce) {
    .trip-tracks { animation: none; }
}
