/* Rastram — estilos do painel (tela do mapa, diálogos e peças compartilhadas)
   Fonte publicada: src/Rastram.WebHtml/css/rastram.css
   Ordem no index.html: tokens.css → app.css → rastram.css → componentes.css → Font Awesome
   (lib/fontawesome/css/fontawesome.min.css + solid.min.css, locais).

   Os valores (cor, tipografia, espaço, raio, sombra, alvo, camadas) vêm só de tokens.css — cópia do
   design system Rastram mais os atalhos --rs-type-*, que o tema do Keycloak também consome. Aqui os
   componentes usam tokens SEMÂNTICOS; quando um valor precisa ficar fixo, ele vira variável de
   componente declarada no próprio componente (--tl-*), nunca um literal solto.

   Fonte, base do body, anel de foco e reduced-motion moram em app.css: este arquivo não os repete.
   Toda superfície sobre o mapa é opaca — tiles atrás de texto derrubam o contraste.
*/

/* ---------- 1. Tokens ---------- */
/* Os tokens entram por <link> próprio no index.html, ANTES desta folha. Eram um
   @import daqui; um @import só é descoberto depois de esta folha baixar, e serializa
   duas idas à rede no caminho crítico — caro justamente na conexão móvel lenta. */

/*
  Segue o sistema no intervalo entre o primeiro byte do HTML e o script embutido do <body>, que é o
  ÚNICO instante em que o corpo ainda não tem `data-tema`. Depois disso quem manda é o tema
  escolhido, e o `color-scheme` dele vem de tokens.css, junto das cores — os dois precisam trocar
  no mesmo momento, senão a barra de rolagem fica no esquema do sistema dentro de um painel que o
  usuário pôs no outro.
*/
@media (prefers-color-scheme: dark) {
  body:not([data-tema]) { color-scheme: dark; }
}

/* ---------- 2. Base ---------- */
* { box-sizing: border-box; }

/*
  Identificador (IMEI, e-mail, coordenada, placa selecionável do toast): Inter 600 com números
  tabulares e ss02 — o sistema não tem monoespaçada; o que separa 0/O e 1/I é o conjunto estilístico.
*/
.tl-mono {
  font-family: var(--font-ui);
  font-weight: 600;
  letter-spacing: .02em;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "ss02" 1;
}

/*
  Barra de rolagem nas superfícies que rolam de fato (não em `*`: o mapa e os contêineres do Leaflet
  não rolam e pagariam o recálculo). `thin` tira a faixa de 17px do Windows dos diálogos de 560px; a
  cor sai do cinza do sistema e entra na rampa de neutros.
*/
.tl-dialogo__corpo,
.tl-pagina,
.tl-tabela-wrap,
.tl-erro-tecnico__corpo,
.corpo pre,
.corpo table,
.sumario,
.sumario ol {
  scrollbar-width: thin;
  scrollbar-color: var(--border-default) transparent;
}

/* ---------- 3. Animações ---------- */
/* @keyframes tlSpin mora em app.css (o shell de carga gira antes desta folha chegar). Nada pulsa
   sobre o mapa: o "você está aqui" é estático. */
@keyframes tlSkel  { 0%,100% { opacity: .55 } 50% { opacity: 1 } }
@keyframes tlUp    { from { transform: translateY(var(--space-8)); opacity: 0 } to { transform: none; opacity: 1 } }
.tl-spin  { animation: tlSpin 900ms var(--ease-linear) infinite; }
.tl-skel  { animation: tlSkel 1400ms var(--ease-standard) infinite; }
.tl-up    { animation: tlUp var(--duration-base) var(--ease-standard); }

/* ---------- 4. Leaflet ---------- */
/*
  leaflet.css é carregado SOB DEMANDA por js/core/carregador.js e entra no <head> DEPOIS desta folha:
  em empate de especificidade quem vence é ele. Por isso as regras abaixo levam o prefixo .tl-palco
  (especificidade maior) ou !important.
*/
.leaflet-container {
  background: var(--tl-mapa-fundo, var(--surface-muted)) !important;
  font-family: inherit !important;
}
.leaflet-tooltip {
  background: var(--map-overlay-bg) !important; color: var(--text-secondary) !important;
  border: var(--border-width-1) solid var(--map-overlay-border) !important; box-shadow: var(--shadow-overlay) !important;
  font: var(--rs-type-supporting) !important; border-radius: var(--radius-md) !important;
  padding: var(--space-8) var(--space-12) !important;
}
.leaflet-tooltip strong { font: var(--rs-type-label); color: var(--text-primary); }
/* A seta do tooltip nasce branca no Leaflet; no tema escuro ela destoava da caixa. */
.leaflet-tooltip-top::before { border-top-color: var(--map-overlay-bg) !important; }
.leaflet-tooltip-bottom::before { border-bottom-color: var(--map-overlay-bg) !important; }
.leaflet-tooltip-left::before { border-left-color: var(--map-overlay-bg) !important; }
.leaflet-tooltip-right::before { border-right-color: var(--map-overlay-bg) !important; }

/* Atribuição: exigência da licença dos tiles — sempre visível, opaca, colada ao canto. */
.leaflet-control-attribution {
  background: var(--map-overlay-bg) !important; color: var(--text-secondary) !important;
  font: var(--rs-type-caption) !important; letter-spacing: .01em;
  padding: 2px var(--space-8) !important; margin: 0 !important;
  border-top-left-radius: var(--radius-sm);
}
.leaflet-control-attribution a {
  color: var(--text-secondary) !important;
  text-decoration: underline !important; text-underline-offset: 3px;
}
/* modo escuro: escurece SÓ os tiles, preservando o contraste dos marcadores; no claro, nenhum filtro */
body[data-tema="escuro"] .leaflet-tile-pane { filter: invert(1) hue-rotate(184deg) brightness(.94) contrast(.92) saturate(.62); }

/*
  Controle de zoom — o único controle do mapa que o painel não desenha.

  Vesti-lo sai mais barato (e menos frágil) do que trocá-lo por botões próprios, que teriam de
  reimplementar o zoom animado, o limite de níveis e o desabilitado nas pontas da escala. Vira UMA
  caixa com divisor, com a mesma casca dos controles da coluna (44px, opaca, --radius-md).

  Especificidade: ".leaflet-touch .leaflet-bar a:first-child" (0,3,1) empataria com o seletor de
  âncora curto e venceria por vir depois; ".leaflet-control-zoom.leaflet-bar" leva a caixa a 0,3,0 e
  as âncoras a 0,4,1, acima de toda regra do Leaflet.
*/
.tl-palco .leaflet-bar { border: 0; box-shadow: none; }
.tl-palco .leaflet-control-zoom.leaflet-bar {
  display: flex; flex-direction: column; gap: 0; overflow: hidden;
  background: var(--map-overlay-bg); background-clip: border-box;
  border: var(--border-width-1) solid var(--map-overlay-border);
  border-radius: var(--radius-md); box-shadow: var(--shadow-overlay);
}
/* 0,3,0: ".leaflet-right .leaflet-control" e ".leaflet-bottom .leaflet-control" (0,2,0) fixam 10px. */
.tl-palco .leaflet-right .leaflet-control-zoom {
  margin: 0 var(--space-24) var(--space-16) 0;
}
.tl-palco .leaflet-control-zoom.leaflet-bar a.leaflet-control-zoom-in,
.tl-palco .leaflet-control-zoom.leaflet-bar a.leaflet-control-zoom-out {
  width: var(--size-touch); height: var(--size-touch);
  border: 0; border-radius: 0; background: transparent;
  color: var(--text-primary); font: 400 var(--size-icon-lg)/var(--size-touch) var(--font-ui); text-indent: 0;
  transition: background-color var(--duration-fast) var(--ease-standard);
}
.tl-palco .leaflet-control-zoom.leaflet-bar a.leaflet-control-zoom-out {
  border-top: var(--border-width-1) solid var(--border-subtle);
}
.tl-palco .leaflet-control-zoom.leaflet-bar a.leaflet-control-zoom-in:hover,
.tl-palco .leaflet-control-zoom.leaflet-bar a.leaflet-control-zoom-out:hover { background: var(--state-hover); color: var(--text-primary); }
.tl-palco .leaflet-control-zoom.leaflet-bar a.leaflet-control-zoom-in:active,
.tl-palco .leaflet-control-zoom.leaflet-bar a.leaflet-control-zoom-out:active { background: var(--state-pressed); }
/* Desabilitado é cor, não transparência. */
.tl-palco .leaflet-control-zoom.leaflet-bar a.leaflet-disabled,
.tl-palco .leaflet-control-zoom.leaflet-bar a.leaflet-disabled:hover {
  background: transparent; color: var(--text-disabled); opacity: 1; cursor: not-allowed;
}

/* ---------- 5. Sobreposições do mapa ---------- */
.tl-mapa { position: absolute; inset: 0; z-index: var(--z-map); }
/*
  Variáveis de componente do palco (não são tokens):
  --tl-altura-menu        faixa da base ocupada pelo menu inferior (barra de 72px no celular; no
                          desktop, menu flutuante de 56px a 16px da base) — somada por toasts,
                          controles do Leaflet, coluna de controles e .tl-offline (componentes.css);
  --tl-altura-atribuicao  linha da atribuição (caption 16px + 2×2px de recheio);
  --tl-altura-zoom        caixa agrupada do zoom (2×44px + bordas);
  --tl-mapa-fundo         fundo enquanto os tiles não chegam.

  A altura vem em DUAS declarações, e a ordem é o mecanismo: `dvh` só existe a partir do Chrome 108.
  Um navegador anterior descarta a segunda linha e fica com a primeira. Sem o `100vh`, o palco cai
  para `height: auto` — e como o único filho é absoluto, a altura resolve para ZERO: tela branca
  silenciosa (Moto Z3 Play com Chrome 101, 04/09/2026).
*/
.tl-palco {
  --tl-altura-menu: 72px;
  --tl-altura-atribuicao: 20px;
  --tl-altura-zoom: calc(var(--size-touch) * 2 + var(--border-width-1) * 2);
  --tl-mapa-fundo: var(--surface-muted);
  position: relative; width: 100%; overflow: hidden; background: var(--tl-mapa-fundo);
  height: 100vh;
  height: 100dvh;
}

/*
  Superfície de sobreposição do mapa (.rs-overlay). O nome da classe ficou porque a marcação inteira
  a usa (cartão, menu, controles, contador do link, acesso encerrado, popover da auditoria); o
  desenho é opaco: fundo, borda, raio e sombra do sistema.
*/
.tl-vidro {
  background: var(--map-overlay-bg);
  border: var(--border-width-1) solid var(--map-overlay-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-overlay);
}

/*
  O rail de ações do veículo não existe mais: Bloquear e Recuperar ficam no menu inferior, Histórico
  e Log como ícones em .tl-controles. A quilometragem continua sendo um lápis no cartão.
*/

/*
  Cartão do veículo — desktop: topo centralizado, livre da coluna de controles dos DOIS lados
  (recuo 24 + controle 44 + folga 24), para continuar centrado sem encostar nela.
  gap 0: o banner de bloqueio/pendente cola no painel (seção 7).
*/
.tl-cartao {
  position: absolute; z-index: var(--z-summary); top: var(--space-24); left: 50%; transform: translateX(-50%);
  width: min(var(--size-summary), calc(100% - 2 * (var(--space-24) + var(--size-touch) + var(--space-24))));
  display: flex; flex-direction: column; gap: 0;
}
/* Nome + identificação + situação em coluna; min-width 0 deixa o nome encolher com reticências. */
.tl-cartao__textos { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; }
/* "Mais/Menos": só o chevron, numa caixa de 44px com contorno de contraste; o texto fica para o leitor de tela. */
.tl-btn.tl-cartao__alternar {
  flex: none; width: var(--size-touch); padding: 0; justify-content: center;
  border-color: var(--border-contrast);
}
.tl-btn.tl-cartao__alternar i { font-size: var(--size-icon-md); }
/* Notas: a cor sai da marcação (era style inline) e vem do modificador. */
.tl-cartao__nota.tl-cartao__nota--alarme { font: var(--rs-type-supporting); color: var(--functional-danger); }
.tl-cartao__nota.tl-cartao__nota--gps { font: var(--rs-type-supporting); color: var(--text-secondary); }
/*
  Lápis (26/32px) e ponto ao vivo mantêm o desenho, mas o toque ganha 44px por uma área invisível
  em volta — sem deslocar o layout do cabeçalho.
*/
.tl-cartao__editar,
.tl-live__botao { position: relative; }
.tl-cartao__editar::after,
.tl-live__botao::after { content: ""; position: absolute; inset: -9px; }

/*
  Velocidade e odômetro — sempre visíveis, fora do "Mais" (SpeedOdometer).

  Duas colunas iguais quando cabem; `min-content` deixa a coluna do número longo crescer em vez de
  o valor invadir a vizinha. Cada métrica é rótulo em cima e valor embaixo, e o valor encosta na base
  da célula: os dois números ficam na mesma linha mesmo com corpos diferentes (40 e 28px).
*/
.tl-metricas {
  display: grid; grid-template-columns: repeat(2, minmax(min-content, 1fr));
  gap: var(--space-12) 0; margin: 0;
  padding-top: var(--space-12); border-top: var(--border-width-1) solid var(--border-subtle);
}
.tl-metrica { display: grid; grid-template-rows: auto 1fr; gap: 2px; min-width: 0; }
.tl-metrica + .tl-metrica {
  padding-inline-start: var(--space-24);
  border-inline-start: var(--border-width-1) solid var(--border-subtle);
}
.tl-metrica__rotulo {
  margin: 0; display: flex; align-items: center; gap: var(--space-8);
  font: var(--rs-type-supporting); color: var(--text-secondary);
}
.tl-metrica__rotulo i { font-size: var(--size-icon-sm); color: var(--text-primary); }
/* O lápis não pode engordar a linha do rótulo, senão "Odômetro" desce em relação a "Velocidade". */
.tl-metrica__rotulo .tl-cartao__editar { margin-block: -6px; }
/* `font` zera font-variant-numeric: os tabulares vêm sempre DEPOIS do atalho. */
.tl-metrica__valor {
  margin: 0; align-self: end; display: flex; align-items: baseline; gap: var(--space-4);
  white-space: nowrap; color: var(--text-primary);
  font: var(--rs-type-data-md); font-variant-numeric: tabular-nums;
}
.tl-metrica--xl .tl-metrica__valor { font: var(--rs-type-data-xl); letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
.tl-metrica--lg .tl-metrica__valor { font: var(--rs-type-data-lg); font-variant-numeric: tabular-nums; }
.tl-metrica__unidade { font: var(--rs-type-supporting); color: var(--text-secondary); letter-spacing: 0; }
.tl-metrica--xl .tl-metrica__unidade { font: var(--rs-type-label); }
.tl-metrica--lg .tl-metrica__unidade { font: var(--rs-type-supporting); }

/* Detalhes do "Mais": grade de 4 (2 no celular), régua superior, sem a técnica do fio de 1px. */
.tl-detalhes {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-12);
  margin: 0; padding-top: var(--space-12); border-top: var(--border-width-1) solid var(--border-subtle);
  background: transparent;
}

/*
  Controles do mapa: coluna à direita, centrada no desktop (no celular, ancorada pela base — seção 9).
  O indicador de tempo real não mora aqui: fica à frente do nome, no cartão.

  Caixa de 44px quadrada com raio de 8px (o mock); fundo, borda e sombra vêm de .tl-vidro, e esta
  regra vem depois dela para vencer o raio. Hover, pressionado e desabilitado ficam na seção 10.
*/
.tl-controles {
  position: absolute; z-index: var(--z-map-controls); right: var(--space-24); top: 50%; transform: translateY(-50%);
  display: flex; flex-direction: column; gap: var(--space-8);
}
.tl-controle {
  width: var(--size-touch); height: var(--size-touch); padding: 0; border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center;
  color: var(--text-primary); cursor: pointer;
}
.tl-controle i { font-size: var(--size-icon-lg); }
a.tl-controle { text-decoration: none; }

/*
  Toasts acima de TUDO — o maior z-index que o navegador aceita. Com 900 a pilha ficava atrás do
  fundo dos diálogos (.tl-scrim, 1000), e o toast que responde a um gesto feito DENTRO de um diálogo
  (copiar a placa na confirmação, o resultado de um comando no console) nascia escondido.

  Superfície inversa e MONOCROMÁTICA: o tipo se lê pelo glifo (avisos.js), não pela cor. As
  variantes --ok/--warn/--crit da seção 7 são neutralizadas aqui, e a pilha deixa o clique passar
  para o mapa e para o diálogo por baixo.
*/
.tl-toasts {
  position: absolute; z-index: 2147483647; inset-inline: 0;
  bottom: calc(var(--tl-altura-menu) + var(--space-16));
  display: flex; flex-direction: column; align-items: center; gap: var(--space-8);
  padding-inline: var(--space-16); pointer-events: none;
}
.tl-toasts--avulsa { position: fixed; bottom: calc(env(safe-area-inset-bottom, 0px) + var(--space-24)); }
.tl-toasts > .tl-aviso {
  width: min(100%, 480px); min-height: 52px;
  align-items: center; gap: var(--space-12);
  padding: var(--space-12) var(--space-16);
  background: var(--surface-inverse); color: var(--text-inverse);
  border: 0; border-radius: var(--radius-md); box-shadow: var(--shadow-overlay);
  font: var(--rs-type-supporting);
}
.tl-toasts > .tl-aviso > i { color: inherit; font-size: var(--size-icon-lg); }
.tl-toasts > .tl-aviso strong { font: var(--rs-type-label); color: inherit; }
/*
  A entrada do toast sobe SEM esmaecer. O .tl-up comum parte de opacity: 0, e um toast é lido no
  instante em que chega — com o quadro atrasado (aba recém-trazida para frente, celular ocupado
  desenhando o mapa) ele ficava translúcido justamente quando o olho chegava nele.
*/
@keyframes tlSobeOpaco { from { transform: translateY(var(--space-8)) } to { transform: none } }
.tl-toasts > .tl-aviso.tl-up { animation-name: tlSobeOpaco; }
/*
  Trecho do toast que o operador precisa conseguir copiar à mão — a placa quando a área de
  transferência recusa a cópia (js/componentes/placa.js). Só este trecho recebe o clique, e
  user-select:all faz um clique (ou toque longo) selecionar o valor inteiro, como em .tl-codigo.
*/
.tl-toasts .tl-aviso__valor { pointer-events: auto; cursor: text; user-select: all; -webkit-user-select: all; color: inherit; }

/*
  Placa do veículo — sempre em destaque, e sempre copiável (js/componentes/placa.js).

  Creme com tinta preta e faixa superior NOS DOIS TEMAS, de propósito: é o objeto que o operador
  compara com o que vê na rua, e precisa saltar igual no claro e no escuro. Por isso as cores são
  variáveis do componente presas às primitivas da marca, e não tokens semânticos que invertem.

  24px de altura no mínimo: a placa é uma ação (copiar), e 24px é o piso de alvo do WCAG (2.5.8).
  O recheio de cima desconta a faixa de 3px, que é sombra interna e não ocupa espaço.
*/
.tl-placa {
  --tl-placa-fundo: var(--brand-cream);
  --tl-placa-tinta: var(--brand-black);
  --tl-placa-hover: var(--neutral-50);
  --tl-placa-icone: var(--neutral-600);
  position: relative;
  display: inline-flex; align-items: center; gap: var(--space-4); flex: none; max-width: 100%; min-height: 24px;
  padding: var(--space-4) var(--space-8) 2px;
  border: var(--border-width-1) solid var(--tl-placa-tinta); border-radius: var(--radius-sm);
  background: var(--tl-placa-fundo); color: var(--tl-placa-tinta);
  box-shadow: inset 0 var(--border-width-3) 0 var(--tl-placa-tinta);
  font: var(--rs-type-identifier); line-height: 16px; letter-spacing: .02em;
  font-feature-settings: "tnum" 1, "ss02" 1;
  white-space: nowrap; cursor: copy; vertical-align: middle;
}
.tl-placa:hover { background: var(--tl-placa-hover); }
.tl-placa__icone { font-size: var(--size-icon-sm); color: var(--tl-placa-icone); }
/* No lugar do nome (veículo só com placa), a placa acompanha o corpo do título do cartão. */
.tl-cartao__titulo > .tl-placa { font: var(--rs-type-card-title); letter-spacing: .02em; }
/*
  No toque, o alvo da placa cresce até 44px sem que o desenho cresça junto: uma placa de 44px dobraria
  cada linha da lista da frota. A área invisível estende só a altura, sobre vizinhos que não são alvo.

  No cartão, a placa abre a linha logo abaixo do nome, e a extensão de cima cairia sobre a bolinha
  do tempo real e o lápis. A linha do nome sobe um degrau na pilha e fica com o toque na faixa dela.
*/
@media (pointer: coarse) {
  .tl-placa::after {
    content: ''; position: absolute; left: 0; right: 0; top: 50%;
    height: var(--size-touch); transform: translateY(-50%);
  }
  .tl-cartao__nome { position: relative; z-index: 1; }
}

/*
  Menu inferior — desktop: sobreposição centrada na base (fundo, borda, raio e sombra de .tl-vidro),
  56px de altura a 16px da base, dentro da faixa --tl-altura-menu que os vizinhos descontam.
*/
.tl-menu-inferior {
  position: absolute; z-index: var(--z-toolbar); left: 50%; bottom: var(--space-16); transform: translateX(-50%);
  height: calc(var(--tl-altura-menu) - var(--space-16));
  display: flex; align-items: stretch; gap: var(--space-4); padding: var(--space-4);
}
.tl-menu-inferior__item {
  position: relative; min-width: 88px; min-height: var(--size-touch); padding: 0 var(--space-12);
  border: 0; border-radius: var(--radius-md);
  background: transparent; color: var(--text-secondary);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-4);
  font: var(--rs-type-label); cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard);
}
.tl-menu-inferior__item:hover { background: var(--state-hover); }
.tl-menu-inferior__item i { font-size: var(--size-icon-lg); }
.tl-menu-inferior__item > span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/*
  Seção ativa (diálogo do item aberto, ou página atual): texto em primário e barra de 3px no topo do
  item (o mock). No escuro --state-indicator é laranja por token.
*/
.tl-menu-inferior__item[aria-expanded="true"],
.tl-menu-inferior__item[aria-current="page"] { color: var(--text-primary); }
.tl-menu-inferior__item[aria-expanded="true"]::before,
.tl-menu-inferior__item[aria-current="page"]::before {
  content: ""; position: absolute; top: 0; inset-inline: calc(var(--space-16) + var(--space-4));
  height: var(--border-width-3); background: var(--state-indicator);
}
/*
  aria-pressed no item Bloquear = veículo bloqueado: preenchimento inverso do StatusBadge, com o
  cadeado que o JS já escreve. Bloqueio remoto é reversível, então nada de vermelho aqui.
  O `:hover` repete o seletor porque `.tl-menu-inferior__item:hover` viria por cima.
*/
.tl-menu-inferior__item[aria-pressed="true"],
.tl-menu-inferior__item[aria-pressed="true"]:hover {
  background: var(--status-blocked-bg); color: var(--status-blocked-fg);
}
/*
  Bloquear com o veículo livre: a ação de emergência em destaque (--state-active). Bloqueado continua
  no inverso acima; sem seleção ou sem permissão, o cinza de desabilitado abaixo.
*/
.tl-menu-inferior__item[data-nav-bloqueio]:not([aria-pressed="true"]):not([aria-disabled="true"]):not(:disabled),
.tl-menu-inferior__item[data-nav-bloqueio]:not([aria-pressed="true"]):not([aria-disabled="true"]):not(:disabled):hover {
  background: var(--state-active); color: var(--state-on-active);
}
.tl-menu-inferior__item[data-nav-bloqueio]:not([aria-pressed="true"]):not([aria-disabled="true"]):not(:disabled):hover { filter: brightness(.94); }
.tl-menu-inferior__item[data-nav-bloqueio]:not([aria-pressed="true"])::before { background: var(--state-on-active); }
/* Sobre o preenchimento inverso a barra de ativo some; ela passa à cor do texto. */
.tl-menu-inferior__item[aria-pressed="true"]::before { background: var(--status-blocked-fg); }
/* Bloqueio na fila, aguardando velocidade segura: contorno tracejado laranja (pendente). */
.tl-menu-inferior__item--pendente { border: var(--border-width-2) dashed var(--status-pending-border); }
/* Desabilitado é cor, não transparência. */
.tl-menu-inferior__item[aria-disabled="true"] { color: var(--text-disabled); cursor: default; }
.tl-menu-inferior__item[aria-disabled="true"]:hover { background: transparent; }
/* Comando que não existe para esta sessão (o link que bloqueia e não libera): clique desligado. */
.tl-menu-inferior__item:disabled { color: var(--text-disabled); cursor: not-allowed; }
.tl-menu-inferior__item:disabled:hover { background: transparent; }

/* ---------- 6. Modais ---------- */
/* Véu plano, sem desfoque: o desfoque custava quadros no celular e não informa nada. */
.tl-scrim {
  position: absolute; inset: 0; z-index: var(--z-scrim); background: var(--bg-scrim);
  display: flex; align-items: center; justify-content: center; padding: var(--space-24);
}
.tl-dialogo {
  position: relative; z-index: var(--z-dialog);
  width: var(--size-dialog); max-width: 100%; max-height: calc(100% - var(--space-48)); min-height: 0;
  display: flex; flex-direction: column;
  background: var(--surface-default); color: var(--text-primary);
  border: var(--border-width-1) solid var(--border-default);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-dialog); overflow: hidden;
}
/* Cabeçalho na mesma superfície do corpo, sem linha: o título separa sozinho. */
.tl-dialogo__cabecalho {
  flex: none; display: flex; align-items: flex-start; gap: var(--space-12);
  padding: var(--space-24) var(--space-16) var(--space-8) var(--space-24);
  border-bottom: 0; background: var(--surface-default);
}
/*
  O bloco de texto ocupa a sobra, o que empurra o X para a borda direita do diálogo — sempre no
  mesmo canto, qualquer que seja o comprimento do título. `min-width: 0` deixa um título comprido
  quebrar em vez de empurrar o X para fora da caixa.
*/
.tl-dialogo__cabecalho > .tl-dialogo__textos { flex: 1 1 auto; min-width: 0; }
/* IMPORTANTE: o corpo é o ÚNICO container rolável.
   flex:1 1 auto (nunca 1 1 0 — com height:auto no diálogo, base 0 colapsa a caixa). */
.tl-dialogo__corpo { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; display: flex; flex-direction: column; }
.tl-dialogo__filtros-acoes { flex: none; padding: var(--space-12) var(--space-16) 0; }
.tl-dialogo__filtros { flex: none; padding: var(--space-12) var(--space-16); border-bottom: var(--border-width-1) solid var(--border-subtle); }
.tl-dialogo__lista { flex: none; padding: var(--space-12); display: flex; flex-direction: column; gap: var(--space-8); }
/*
  Ações à direita, informação à esquerda. Em flex, o `gap` separa os botões sem depender de espaço
  em branco na marcação, e `flex-end` põe a ação principal onde ela é procurada. Quem não é ação
  fica à esquerda por `margin-right: auto` na própria peça (hoje só .tl-resumo-frota).
*/
.tl-dialogo__rodape {
  flex: none; position: sticky; bottom: 0; z-index: 2;
  display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: var(--space-12);
  padding: var(--space-16) var(--space-24);
  border-top: var(--border-width-1) solid var(--border-subtle); background: var(--surface-default);
}

/* ---------- 7. Chips, campos e estados ---------- */
/* Chip de filtro: pílula compacta; ligado = laranja com texto preto e contorno de contraste. */
.tl-chip {
  min-height: var(--size-touch); display: inline-flex; align-items: center; gap: var(--space-8);
  padding: 0 var(--space-16); border-radius: var(--radius-full);
  border: var(--border-width-1) solid var(--border-strong);
  background: var(--surface-default); color: var(--text-primary);
  font: var(--rs-type-label); white-space: nowrap; cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard);
}
.tl-chip:hover { background: var(--state-hover); border-color: var(--border-contrast); }
.tl-chip[aria-pressed="true"] { background: var(--state-active); color: var(--state-on-active); border-color: var(--border-contrast); }
.tl-chip[aria-pressed="true"]:hover { background: var(--action-primary-bg-hover); }
.tl-chip:disabled { background: var(--action-disabled-bg); color: var(--text-disabled); border-color: var(--border-subtle); cursor: not-allowed; }

/*
  Campo: pílula de altura travada (as variantes, como .tl-campo--area, soltam a altura).
  Corpo 16px no input, o que evita o zoom automático do iOS ao focar.
*/
.tl-campo {
  display: flex; align-items: center; gap: var(--space-8); height: var(--size-touch); min-width: 0;
  padding: 0 var(--space-12); border-radius: var(--radius-md);
  border: var(--border-width-1) solid var(--border-strong);
  background: var(--surface-default); color: var(--text-primary);
  transition: border-color var(--duration-fast) var(--ease-standard);
}
.tl-campo:hover { border-color: var(--border-contrast); }
.tl-campo > i { flex: none; font-size: var(--size-icon-md); color: var(--text-secondary); }
.tl-campo input { flex: 1; min-width: 0; padding: 0; border: 0; background: transparent; color: var(--text-primary); font: var(--rs-type-body); outline: none; }
.tl-campo input::placeholder { color: var(--text-tertiary); opacity: 1; }
/*
  O anel universal de app.css vai para a PÍLULA, não para o input de dentro (como o input-group do
  sistema): os mesmos valores, no contêiner. `:focus-within`, e não `:has()`, por causa do Chrome 101.
*/
.tl-campo :is(input, textarea):focus-visible { outline: none; box-shadow: none; }
.tl-campo:focus-within {
  outline: var(--border-width-2) solid var(--focus-inner); outline-offset: 2px;
  box-shadow: var(--focus-halo);
}
/* Campo recusado: borda de 2px (o texto e o ícone do erro ficam abaixo, fora da pílula). Regras
   separadas porque um `:has()` numa lista derrubaria a lista inteira no navegador antigo. */
.tl-campo--invalido { border: var(--border-width-2) solid var(--functional-danger); padding-inline: calc(var(--space-12) - 1px); }
.tl-campo:has(input[aria-invalid="true"]) { border: var(--border-width-2) solid var(--functional-danger); padding-inline: calc(var(--space-12) - 1px); }

/*
  Botão: secundário por padrão (contorno de contraste); --primario é o laranja com texto preto;
  --critico só para o irreversível (excluir, revogar) — bloqueio remoto é reversível e vai em
  --primario. `text-decoration: none` porque o botão nem sempre é <button>: "Voltar ao mapa" e a
  navegação entre documentos são <a class="tl-btn">.
*/
.tl-btn {
  min-height: var(--size-touch); display: inline-flex; align-items: center; justify-content: center; gap: var(--space-8);
  padding: 0 var(--space-16); border-radius: var(--radius-md);
  border: var(--border-width-1) solid var(--action-secondary-border);
  background: var(--action-secondary-bg); color: var(--action-secondary-fg);
  font: var(--rs-type-button); text-decoration: none; cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard);
}
.tl-btn i { font-size: var(--size-icon-md); }
.tl-btn:hover { background: var(--state-hover); }
.tl-btn:active { background: var(--state-pressed); }
.tl-btn--primario { border-color: transparent; background: var(--action-primary-bg); color: var(--action-primary-fg); }
.tl-btn--primario:hover { background: var(--action-primary-bg-hover); }
.tl-btn--primario:active { background: var(--action-primary-bg-pressed); }
.tl-btn--critico { border-color: transparent; background: var(--action-destructive-bg); color: var(--action-destructive-fg); }
.tl-btn--critico:hover,
.tl-btn--critico:active { background: var(--action-destructive-bg-hover); }
/*
  Desabilitado é cor, não transparência. Ocupado (aria-busy) mantém a cor da variante: o aro girando
  diz "trabalhando", e o botão não pode parecer outro no meio do envio. A ordem importa — cada regra
  de ocupado vence o desabilitado e o hover declarados antes dela.
*/
.tl-btn:disabled { background: var(--action-disabled-bg); color: var(--action-disabled-fg); border-color: transparent; cursor: progress; }
.tl-btn[aria-busy="true"] { background: var(--action-secondary-bg); color: var(--action-secondary-fg); border-color: var(--action-secondary-border); cursor: progress; }
.tl-btn--primario[aria-busy="true"] { background: var(--action-primary-bg); color: var(--action-primary-fg); border-color: transparent; }
.tl-btn--critico[aria-busy="true"] { background: var(--action-destructive-bg); color: var(--action-destructive-fg); border-color: transparent; }

/*
  Aviso embutido (diálogos e páginas) = notice do sistema: superfície com borda e ícone; o tipo vem
  da borda e do ícone, sem véus tintados. Dentro de .tl-toasts a seção 5 troca tudo pela superfície
  inversa.
*/
.tl-aviso {
  display: flex; align-items: flex-start; gap: var(--space-12); padding: var(--space-12) var(--space-16);
  border: var(--border-width-1) solid var(--border-default); border-radius: var(--radius-md);
  background: var(--surface-default); color: var(--text-primary); font: var(--rs-type-supporting);
}
.tl-aviso > i { flex: none; font-size: var(--size-icon-lg); }
.tl-aviso strong { font: var(--rs-type-label); }
.tl-aviso__texto { flex: 1 1 auto; min-width: 0; }
.tl-aviso--ok { border-color: var(--functional-success); }
.tl-aviso--ok > i { color: var(--functional-success); }
/* Atenção: laranja da marca com tinta preta em TUDO (ícone, título, links) — cinza não passa ali. */
.tl-aviso--warn { background: var(--surface-accent); border-color: var(--surface-accent); color: var(--text-on-accent); }
.tl-aviso--warn > i,
.tl-aviso--warn strong,
.tl-aviso--warn a { color: var(--text-on-accent); }
.tl-aviso--crit {
  border: var(--border-width-2) solid var(--functional-danger);
  padding: calc(var(--space-12) - 1px) calc(var(--space-16) - 1px);
}
.tl-aviso--crit > i { color: var(--functional-danger); }

/*
  Banner do resumo (bloqueado / pendente): cartao-veiculo.js o insere logo ANTES do painel, dentro
  de .tl-cartao. Os dois se colam por irmandade — cantos de cima no banner, painel sem cantos nem
  borda superiores —, então o conjunto lê como um cartão só. Opaco e com a sombra das sobreposições.
*/
.tl-aviso--fixo {
  align-items: center; gap: var(--space-12); padding: var(--space-12) var(--space-16);
  border: var(--border-width-1) solid var(--map-overlay-border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-overlay); font: var(--rs-type-supporting);
}
.tl-aviso--fixo i { font-size: var(--size-icon-md); color: inherit; }
.tl-aviso--fixo strong { font: var(--rs-type-label); color: inherit; }
/* Bloqueado é um estado do equipamento, não um perigo: preenchimento inverso e cadeado. */
.tl-aviso--bloqueado { background: var(--status-blocked-bg); color: var(--status-blocked-fg); border-color: var(--status-blocked-bg); }
/* Pendente: superfície comum com contorno tracejado laranja e ampulheta. */
.tl-aviso--pendente {
  background: var(--status-pending-bg); color: var(--status-pending-fg);
  border: var(--border-width-2) dashed var(--status-pending-border);
  padding: calc(var(--space-12) - 1px) calc(var(--space-16) - 1px);
}
/* Falha e expirado: superfície comum com contorno vermelho sólido, como o selo --falhou. O relé continua como estava. */
.tl-aviso--falha {
  background: var(--surface-default); color: var(--text-primary);
  border: var(--border-width-2) solid var(--status-failed);
  padding: calc(var(--space-12) - 1px) calc(var(--space-16) - 1px);
}
.tl-aviso--falha > i { color: var(--status-failed); }
.tl-cartao > .tl-aviso--fixo { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.tl-aviso--fixo + .tl-cartao__painel { border-top-left-radius: 0; border-top-right-radius: 0; border-top: 0; }

/* ---------- 8. Marcadores (divIcon) ---------- */
/*
  position: absolute, e NUNCA relative.

  O Leaflet posiciona o marcador com `transform: translate3d(...)` sobre uma base
  `.leaflet-marker-icon { position: absolute; left: 0; top: 0 }` (leaflet.css, bloco "required
  styles"). Declarar `relative` aqui vencia a regra do Leaflet e devolvia o marcador ao fluxo
  normal: o translate passava a somar à posição estática, e cada marcador ficava deslocado para BAIXO
  pela altura dos anteriores da frota — o veículo parecia subir ou descer sobre a via a cada zoom,
  enquanto o rastro (SVG) ficava no lugar certo.

  `absolute` mantém o marcador como bloco de contenção para .tl-mk__corpo, .tl-mk__estado e
  .tl-mk__rotulo, que são absolutos e se ancoram nele.
*/
.tl-mk { position: absolute; }
/* Disco de 40px para todos os marcadores; a seleção é o anel laranja, não um disco maior. */
.tl-mk__corpo {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  display: block; width: var(--size-marker); height: var(--size-marker);
  border-radius: var(--radius-full); background: var(--map-marker-bg);
  border: var(--border-width-2) solid var(--map-marker-border); box-shadow: var(--shadow-overlay);
}
/* A silhueta (160×256) cabe em 18×29; o giro do curso vem inline, com o translate de centralizar. */
.tl-mk__imagem {
  position: absolute; left: 50%; top: 50%; width: 18px; height: 29px;
  object-fit: contain; pointer-events: none; user-select: none;
}
.tl-mk--selecionado .tl-mk__corpo { box-shadow: 0 0 0 var(--border-width-3) var(--map-marker-selected), var(--shadow-overlay); }
/* Em reboque: contorno tracejado no disco — a forma diz, não só a cor. */
.tl-mk--reboque .tl-mk__corpo { border-style: dashed; border-color: var(--status-towing-border); }

/* ---------- 9. Responsivo (celular) ---------- */
@media (max-width: 719.98px) {
  /*
    O teto do cartão desconta, de baixo para cima: menu, atribuição, folga, zoom (e, à esquerda, os
    controles de área, da mesma altura), folga, a fileira de controles e a folga dela. Com o "Mais"
    aberto, os detalhes rolam dentro do painel em vez de o cartão descer sobre o menu (iPhone SE).
  */
  .tl-cartao {
    top: calc(env(safe-area-inset-top, 0px) + var(--space-16));
    left: var(--space-16); right: var(--space-16); width: auto; transform: none;
    max-height: max(160px, calc(100% - env(safe-area-inset-top, 0px) - var(--space-16)
            - env(safe-area-inset-bottom, 0px) - var(--tl-altura-menu) - var(--tl-altura-atribuicao)
            - var(--space-16) - var(--tl-altura-zoom) - var(--space-8) - var(--size-touch) - var(--space-16)));
  }
  /*
    Com o "Mais" aberto o cartão cresce POR CIMA de tudo — fileira de controles, zoom e menu —, até
    16px da base; só os detalhes rolam se ainda faltar altura. A fileira não desce junto (mapa.js).
  */
  .tl-cartao--aberto {
    max-height: calc(100% - env(safe-area-inset-top, 0px) - var(--space-16) - env(safe-area-inset-bottom, 0px) - var(--space-16));
  }
  .tl-cartao > .tl-aviso--fixo { flex: none; }
  /* Compacto: recheio e vãos menores, e a velocidade no mesmo corpo do odômetro. */
  .tl-cartao .tl-cartao__painel { padding: var(--space-12); gap: var(--space-8); }
  .tl-cartao .tl-cartao__resumo { padding-top: var(--space-8); }
  .tl-cartao .tl-metrica--xl .tl-metrica__valor { font: var(--rs-type-data-lg); letter-spacing: 0; font-variant-numeric: tabular-nums; }
  .tl-cartao .tl-metrica--xl .tl-metrica__unidade { font: var(--rs-type-supporting); }
  /* Só os detalhes rolam: o cabeçalho (com o "Menos") e as métricas ficam sempre à vista. */
  .tl-cartao__painel { min-height: 0; }
  .tl-cartao__painel > [data-detalhes] { min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
  .tl-metrica + .tl-metrica { padding-inline-start: var(--space-16); }
  .tl-detalhes { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /*
    Controles numa FILEIRA logo abaixo do cartão, alinhada à direita. Em coluna, ancorada pela base,
    só três dos seis cabiam entre o cartão e o zoom numa tela de 667px: os outros ficavam por baixo
    do cartão. A base do cartão vem medida em --tl-base-cartao (mapa.js); sem veículo selecionado
    não há cartão, e a fileira sobe para o topo.
  */
  .tl-controles {
    right: var(--space-16); bottom: auto; transform: none;
    top: calc(var(--tl-base-cartao, calc(env(safe-area-inset-top, 0px) + var(--space-8))) + var(--space-8));
    max-width: calc(100% - 2 * var(--space-16));
    flex-direction: row; flex-wrap: wrap; justify-content: flex-end;
  }
  /* A pilha avulsa (telas sem palco) fica com a própria base, da seção 5. */
  .tl-toasts:not(.tl-toasts--avulsa) {
    bottom: calc(env(safe-area-inset-bottom, 0px) + var(--tl-altura-menu) + var(--tl-altura-atribuicao) + var(--space-12));
  }

  /*
    O menu encosta na borda de baixo no celular, e os dois controles que o Leaflet ancora ali ficariam
    POR BAIXO dele — o zoom cortado e a atribuição sumida, e ela é obrigação da licença dos tiles.
    A margem sobe os dois para cima do menu; a atribuição fica colada a ele, no canto.
  */
  .leaflet-bottom.leaflet-right,
  .leaflet-bottom.leaflet-left { bottom: calc(env(safe-area-inset-bottom, 0px) + var(--tl-altura-menu)); }
  .tl-palco .leaflet-right .leaflet-control-zoom { margin: 0 var(--space-16) var(--space-16) 0; }

  /* Barra plana, opaca, de largura total e colada à base; os itens dividem a largura por igual. */
  .tl-menu-inferior {
    left: 0; right: 0; bottom: 0; transform: none;
    height: auto; min-height: calc(var(--tl-altura-menu) + env(safe-area-inset-bottom, 0px));
    gap: 0; padding: 0 0 env(safe-area-inset-bottom, 0px);
    background: var(--surface-default);
    border: 0; border-top: var(--border-width-1) solid var(--border-subtle);
    border-radius: 0; box-shadow: none;
  }
  .tl-menu-inferior__item {
    flex: 1 1 0; min-width: 0; min-height: var(--tl-altura-menu);
    padding: var(--space-4); border-radius: 0;
  }
  /* A barra de ativo cobre a borda superior da barra. */
  .tl-menu-inferior__item[aria-expanded="true"]::before,
  .tl-menu-inferior__item[aria-current="page"]::before { top: -1px; }

  /* Modais viram bottom sheet: colados à base, cantos de cima arredondados, pegador decorativo. */
  .tl-scrim { align-items: flex-end; padding: 0; }
  .tl-dialogo {
    width: 100%; max-height: 88%;
    border-bottom: 0; border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  }
  .tl-dialogo::before {
    content: ""; display: block; flex: none; width: 32px; height: var(--space-4);
    margin: var(--space-8) auto 0; border-radius: 2px; background: var(--border-strong);
  }
  .tl-dialogo__cabecalho { align-items: center; padding: var(--space-8) var(--space-8) var(--space-8) var(--space-16); }
  .tl-dialogo__rodape {
    gap: var(--space-8);
    padding: var(--space-12) var(--space-16) calc(var(--space-12) + env(safe-area-inset-bottom, 0px));
  }
  .tl-dialogo__rodape .tl-btn { flex: 1 1 0; }
}

/* Celular estreito: botões do rodapé empilhados, largura total. */
@media (max-width: 479.98px) {
  .tl-dialogo__rodape { flex-direction: column-reverse; align-items: stretch; }
  .tl-dialogo__rodape .tl-btn { flex: none; width: 100%; }
}

/* ---------- 10. Extensões do painel (fora do pacote de design) ---------- */
/* Texto só para leitor de tela — não altera nada visual. clip-path cobre quem já descartou `clip`. */
.tl-sr-somente {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/*
  Controles do mapa (IconButton sobre o mapa). A caixa de 44px e a posição moram na seção 5; aqui
  ficam a superfície opaca e os estados. Ligado = laranja com ícone preto e contorno, como no mock:
  laranja é permitido para "estado ativo", e a borda garante a leitura sem depender da cor.
*/
.tl-controle {
  border: var(--border-width-1) solid var(--map-overlay-border);
  background: var(--map-overlay-bg); color: var(--text-primary);
  box-shadow: var(--shadow-overlay); font-size: var(--size-icon-lg);
  transition: background-color var(--duration-fast) var(--ease-standard);
}
.tl-controle:hover:not(:disabled) { background: var(--state-hover); }
.tl-controle:active:not(:disabled) { background: var(--state-pressed); }
/* Único caso hoje: a localização enquanto o mapa ainda não existe — clicar não teria onde marcar. */
.tl-controle:disabled {
  background: var(--action-disabled-bg); color: var(--action-disabled-fg);
  box-shadow: none; opacity: 1; cursor: progress;
}
.tl-controle[aria-pressed="true"] {
  background: var(--state-active); color: var(--state-on-active); border-color: var(--border-contrast);
}
.tl-controle[aria-pressed="true"]:hover:not(:disabled) { background: var(--brand-orange-hover); }

/*
  Sinal de tempo real (LiveIndicator) — o ponto à frente do nome do veículo.

  A cor vive no ANCESTRAL e o ponto a herda por currentColor: é o que deixa a mesma marcação servir
  de amostra na legenda. Ligado = ponto cheio com pulso lento; reconectando e inativo = anel vazado
  (a forma muda, não só a cor); sem conexão = ponto cheio em perigo.

  O botão mantém o desenho de 26px e ganha a área de toque de 44px por ::after, sem mexer na linha.
*/
.tl-live { display: inline-flex; flex: none; align-items: center; }
.tl-live__botao {
  position: relative; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0;
  border: 0; border-radius: var(--radius-full); background: transparent; color: inherit; cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard);
}
.tl-live__botao::after { content: ""; position: absolute; inset: -9px; }
.tl-live__botao:hover { background: var(--state-hover); }
.tl-live__ponto {
  position: relative; display: block; flex: none;
  width: var(--size-dot); height: var(--size-dot); border-radius: var(--radius-full);
  background: currentColor;
}
.tl-live--on { color: var(--functional-success); }
.tl-live--off { color: var(--functional-danger); }
.tl-live--warn { color: var(--text-primary); }
.tl-live--idle { color: var(--text-tertiary); }
.tl-live--warn .tl-live__ponto,
.tl-live--idle .tl-live__ponto { background: transparent; box-shadow: inset 0 0 0 2px currentColor; }
.tl-live--warn .tl-live__ponto { animation: tlLiveRespira 1400ms var(--ease-standard) infinite; }
/* O pulso é uma cópia do ponto que cresce e some: o ponto em si nunca pisca nem perde contraste. */
.tl-live--pisca .tl-live__ponto::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; background: currentColor;
  animation: tlLivePulso 1800ms var(--ease-exit) infinite;
}
@keyframes tlLivePulso {
  0% { transform: scale(1); opacity: .55; }
  80%, 100% { transform: scale(2.6); opacity: 0; }
}
@keyframes tlLiveRespira {
  0%, 100% { opacity: .55; }
  50% { opacity: 1; }
}
/* A régua global zera a duração; a cópia do pulso some de vez para não sobrar um ponto duplicado. */
@media (prefers-reduced-motion: reduce) {
  .tl-live--pisca .tl-live__ponto::after { display: none; }
}

/*
  Legenda dos estados do sinal (diálogo aberto pelo ponto).

  O ponto de cada linha é o MESMO nó da tela, com o mesmo modificador de cor: legenda que não é
  idêntica ao que explica vira uma segunda fonte de verdade.
*/
.tl-legenda__intro, .tl-legenda__nota { margin: 0; font: var(--rs-type-supporting); color: var(--text-secondary); }
.tl-legenda { display: flex; flex-direction: column; gap: var(--space-12); margin: 0; padding: 0; list-style: none; }
.tl-legenda__item { display: flex; align-items: flex-start; gap: var(--space-8); }
.tl-legenda__ponto {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px;
}
.tl-legenda__texto { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.tl-legenda__texto strong { font: var(--rs-type-label); color: var(--text-primary); }
.tl-legenda__texto span { font: var(--rs-type-supporting); color: var(--text-secondary); }
/* "agora" marca o estado corrente: selo compacto preenchido (selecionado), retangular, sem caixa alta. */
.tl-legenda__agora {
  flex: none; align-self: center; margin-left: auto;
  display: inline-flex; align-items: center; min-height: 22px; padding: 0 6px;
  border-radius: var(--radius-sm);
  background: var(--state-selected-fill); color: var(--state-selected-on);
  font: 600 12px/16px var(--font-ui);
}

/*
  Complementos do marcador (tl-mk): a silhueta, o selo de situação e o rótulo com o nome. O disco,
  o anel de seleção e o tracejado do offline são da seção 8.
*/
/* A imagem é centrada pelo translate inline (que também gira), por isso precisa de posição absoluta. */
.tl-mk__imagem {
  position: absolute; left: 50%; top: 50%; display: block;
  width: 18px; height: 29px; object-fit: contain;
  transition: transform var(--duration-marker) var(--ease-standard);
  pointer-events: none;
}

/* Seta do rastro na cor do contorno da rota, sem sombra: o contraste vem do casing, não de efeito. */
.tl-rastro-seta {
  display: grid; place-items: center;
  background: transparent; border: 0;
  color: var(--map-route-casing);
}
.tl-rastro-seta i { display: block; font-size: 10px; line-height: 1; }

/*
  Selo de situação (StatusBadge) — a MESMA peça no cartão, na lista, no marcador e nos resultados
  de comando. Retângulo de propósito (nunca pílula): cada situação tem uma FORMA própria — laranja
  cheio, contorno sólido, tracejado, inverso, perigo — e ícone e palavra, então nada depende só da
  cor. Cada variante pinta fundo, borda e texto opacos; o ícone herda.
*/
.tl-selo {
  display: inline-flex; align-items: center; gap: var(--space-4);
  min-height: 28px; padding: 0 var(--space-8);
  border: var(--border-width-1) solid transparent; border-radius: var(--radius-sm);
  background: var(--surface-default); color: var(--text-primary);
  font: var(--rs-type-label); white-space: nowrap; vertical-align: middle;
}
.tl-selo i { font-size: var(--size-icon-sm); color: inherit; }

.tl-selo--em-movimento { background: var(--status-moving-bg); color: var(--status-moving-fg); border-color: transparent; }
.tl-selo--parado {
  background: var(--status-stopped-bg); color: var(--status-stopped-fg); border-color: var(--status-stopped-border);
}
.tl-selo--desconectado {
  background: var(--status-offline-bg); color: var(--status-offline-fg);
  border: var(--border-width-1) dashed var(--status-offline-border);
}
.tl-selo--bloqueado { background: var(--status-blocked-bg); color: var(--status-blocked-fg); border-color: transparent; }
.tl-selo--em-alarme { background: var(--status-alarm-bg); color: var(--status-alarm-fg); border-color: transparent; }
/* Sem sinal de GPS: dedução da plataforma (garagem), não alarme do equipamento — âmbar, nunca vermelho. */
.tl-selo--sem-gps { background: var(--status-nogps-bg); color: var(--status-nogps-fg); border-color: transparent; }
/* Reboque: deslocamento com a ignição desligada. Tracejado forte — chama atenção sem ser alarme. */
.tl-selo--em-reboque {
  background: var(--status-towing-bg); color: var(--status-towing-fg);
  border: var(--border-width-2) dashed var(--status-towing-border); padding-inline: 7px;
}

/* Resultados de comando (auditoria, console). Borda de 2px desconta 1px do recheio para manter a largura. */
.tl-selo--pendente {
  background: var(--status-pending-bg); color: var(--status-pending-fg);
  border: var(--border-width-2) dashed var(--status-pending-border); padding-inline: 7px;
}
.tl-selo--confirmado { background: var(--surface-default); color: var(--text-primary); border-color: var(--border-default); }
.tl-selo--confirmado i { color: var(--status-confirmed); }
.tl-selo--falhou {
  background: var(--surface-default); color: var(--text-primary);
  border: var(--border-width-2) solid var(--status-failed); padding-inline: 7px;
}
.tl-selo--falhou i { color: var(--status-failed); }
.tl-selo--neutro { background: var(--surface-muted); color: var(--text-primary); border-color: transparent; }

/*
  Variante compacta, para listas densas. A situação da linha da frota também é compacta pelo
  contexto: ao lado do "Sem GPS" compacto, um selo de 28px desalinharia a linha.
*/
.tl-selo--compacto,
.tl-item-frota__base > .tl-selo { min-height: 22px; padding: 0 6px; font: 600 12px/16px var(--font-ui); }
.tl-selo--compacto.tl-selo--pendente,
.tl-selo--compacto.tl-selo--falhou,
.tl-item-frota__base > .tl-selo--pendente,
.tl-item-frota__base > .tl-selo--falhou { padding-inline: 5px; }

/*
  Selo do marcador: disco de 20px no canto superior direito do disco do veículo, com as MESMAS
  cores das variantes acima. Vem depois delas de propósito: com a mesma especificidade, a borda de
  2px na cor do disco vence o contorno de cada variante — tracejado de 1px não se lê em 20px.
*/
.tl-mk__estado {
  position: absolute; top: -6px; right: -8px; left: auto;
  width: 20px; height: 20px; min-height: 0; padding: 0;
  justify-content: center;
  border: var(--border-width-2) solid var(--map-marker-bg); border-radius: var(--radius-full);
  font-size: 10px;
}
.tl-mk__estado i { font-size: 10px; line-height: 1; }
.tl-mk__estado.tl-selo--parado { box-shadow: inset 0 0 0 1px var(--status-stopped-border); }
.tl-mk__estado.tl-selo--pendente { box-shadow: inset 0 0 0 2px var(--status-pending-border); }
.tl-mk__estado.tl-selo--em-reboque { padding: 0; box-shadow: inset 0 0 0 2px var(--status-towing-border); }

/*
  Rótulo com o nome do veículo — só no selecionado (e em hover/foco onde há ponteiro fino). Nome
  longo termina em reticências: o rótulo não pode cobrir meio bairro do mapa.
*/
.tl-mk__rotulo,
.tl-eu__rotulo {
  position: absolute; left: 50%; top: calc(100% + 10px); bottom: auto; transform: translateX(-50%);
  max-width: 180px; padding: 2px var(--space-8);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  border: var(--border-width-1) solid var(--border-default); border-radius: var(--radius-sm);
  background: var(--map-overlay-bg); color: var(--text-primary);
  font: var(--rs-type-label); pointer-events: none;
}
.tl-mk__rotulo { display: none; }
.tl-mk--selecionado .tl-mk__rotulo { display: block; }
@media (hover: hover) and (pointer: fine) {
  .tl-mk:hover .tl-mk__rotulo,
  .tl-mk:focus-visible .tl-mk__rotulo,
  .tl-mk:focus-within .tl-mk__rotulo { display: block; }
}

/*
  "Você está aqui" — a posição de quem OLHA o painel. Um ponto, nunca a silhueta de um veículo, e
  sem pulso: a incerteza é desenhada pelo círculo de precisão (SVG, raio real do navegador). O halo
  estático só aparece quando o navegador não informou precisão (.tl-eu--sem-precisao).
*/
.tl-eu { position: absolute; }
.tl-eu__pulso {
  display: none;
  position: absolute; left: 50%; top: 50%; margin: -26px 0 0 -26px;
  width: 52px; height: 52px; border-radius: var(--radius-full);
  background: var(--map-accuracy); animation: none; pointer-events: none;
}
.tl-eu--sem-precisao .tl-eu__pulso { display: block; }
/* O anel usa --map-event-ring (creme no claro, preto no escuro): separa o ponto de qualquer ladrilho. */
.tl-eu__ponto {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 14px; height: 14px; border-radius: var(--radius-full);
  background: var(--map-my-location); border: 0;
  box-shadow: 0 0 0 3px var(--map-event-ring); pointer-events: none;
}
/* A caixa desta marca (18px) é menor que o disco do veículo (40px): o rótulo desce menos. */
.tl-eu__rotulo { top: calc(100% + 8px); }

/*
  Cabeçalho de diálogo. O sobretítulo é o único rótulo em caixa alta que sobra (eyebrow de poucas
  palavras), com o marcador laranja da marca; o título é Manrope.
*/
.tl-dialogo__sobretitulo {
  display: flex; align-items: center; gap: var(--space-8); margin-bottom: var(--space-4);
  font: var(--rs-type-overline); letter-spacing: .08em; text-transform: uppercase; color: var(--text-accent);
}
.tl-dialogo__sobretitulo::before {
  content: ""; flex: none; width: var(--size-dot); height: var(--size-dot);
  border-radius: var(--radius-full); background: var(--brand-orange);
}
/* Título visível do diálogo — é ele que dá o nome acessível, via aria-labelledby. */
.tl-dialogo__titulo { margin: 0; font: var(--rs-type-section-title); letter-spacing: -0.005em; color: var(--text-primary); }
.tl-dialogo__conteudo {
  flex: none; display: flex; flex-direction: column; gap: var(--space-16);
  padding: var(--space-16) var(--space-24);
}
/*
  Fechar: botão de ícone sutil, 44px. O tamanho do glifo vai declarado porque <button> não herda a
  fonte do documento.
*/
.tl-dialogo__fechar {
  flex: none; width: var(--size-touch); height: var(--size-touch); min-width: var(--size-touch); padding: 0;
  border: var(--border-width-1) solid transparent; border-radius: var(--radius-full);
  background: transparent; color: var(--text-primary);
  display: inline-grid; place-items: center; cursor: pointer;
  font-size: var(--size-icon-lg);
  transition: background-color var(--duration-fast) var(--ease-standard);
}
.tl-dialogo__fechar:hover:not(:disabled) { background: var(--state-hover); }
.tl-dialogo__fechar:active:not(:disabled) { background: var(--state-pressed); }
.tl-dialogo__fechar:disabled {
  background: var(--action-disabled-bg); color: var(--action-disabled-fg); opacity: 1; cursor: not-allowed;
}

/* Blocos de estado (ContentStates). A respiração é do contêiner .tl-skel: uma animação só. */
.tl-skeleton-linha { display: block; height: 12px; border-radius: var(--radius-sm); background: var(--surface-muted); }
.tl-skeleton-linha.tl-skeleton--larga { width: 60%; height: 16px; }
.tl-skeleton-linha.tl-skeleton--estreita { width: 40%; margin-top: 6px; }

.tl-estado {
  display: grid; justify-items: center; gap: var(--space-12);
  padding: var(--space-32) var(--space-24); text-align: center; color: var(--text-secondary);
}
/* Filho direto: o ícone do botão "Tentar de novo" não pode virar ladrilho. */
.tl-estado > i {
  display: grid; place-items: center; width: 56px; height: 56px;
  border-radius: var(--radius-lg); background: var(--surface-muted); color: var(--text-primary);
  font-size: 24px;
}
.tl-estado strong { font: var(--rs-type-card-title); color: var(--text-primary); }
.tl-estado p { margin: 0; max-width: 44ch; font: var(--rs-type-supporting); color: var(--text-secondary); }
.tl-estado > .tl-btn { margin-top: var(--space-4); }
/* Erro: anel de 2px em perigo — a falha se lê pela forma, não só pelo vermelho do glifo. */
.tl-estado--erro > i {
  background: var(--surface-default); color: var(--functional-danger);
  box-shadow: inset 0 0 0 2px var(--functional-danger);
}

/*
  Calendário próprio do período de rastreio (CalendarioPeriodo — nunca <input type="date">).
  Dia escolhido = preenchimento preto/creme; hoje = contorno; dentro do período = fundo discreto.
*/
.tl-calendario { display: flex; flex-direction: column; gap: var(--space-12); width: min(100%, 348px); }
.tl-dialogo__conteudo .tl-calendario { width: 100%; }
.tl-calendario__cabecalho { display: flex; align-items: center; justify-content: space-between; gap: var(--space-8); }
/*
  Sem `text-transform: capitalize`: o rótulo já vem pronto ("Agosto de 2026"), e o capitalize é por
  PALAVRA — escreveria "Agosto De 2026".
*/
.tl-calendario__cabecalho strong { flex: 1; text-align: center; font: var(--rs-type-card-title); color: var(--text-primary); }
.tl-calendario__navegar {
  flex: none; width: var(--size-touch); height: var(--size-touch); padding: 0;
  border: var(--border-width-1) solid var(--action-secondary-border); border-radius: var(--radius-full);
  background: var(--action-secondary-bg); color: var(--text-primary);
  display: inline-grid; place-items: center; font-size: var(--size-icon-md); cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard);
}
.tl-calendario__navegar:hover:not(:disabled) { background: var(--state-hover); }
.tl-calendario__navegar:active:not(:disabled) { background: var(--state-pressed); }
.tl-calendario__navegar:disabled {
  background: var(--action-disabled-bg); color: var(--action-disabled-fg); border-color: transparent;
  opacity: 1; cursor: not-allowed;
}
/* Alvo mínimo de 44px por dia, mesmo numa grade de 7 colunas. */
.tl-calendario__semana, .tl-calendario__dias {
  display: grid; grid-template-columns: repeat(7, minmax(var(--size-touch), 1fr)); gap: var(--space-4);
}
.tl-calendario__semana span {
  text-align: center; padding: var(--space-4) 0; font: var(--rs-type-label); color: var(--text-secondary);
}
.tl-calendario__dia {
  min-height: var(--size-touch); min-width: 0; padding: 0;
  border: var(--border-width-1) solid transparent; border-radius: var(--radius-md);
  background: transparent; color: var(--text-primary);
  font: var(--rs-type-data-sm); font-variant-numeric: tabular-nums; cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard);
}
.tl-calendario__dia:hover:not(:disabled) { background: var(--state-hover); }
.tl-calendario__dia:disabled { color: var(--text-disabled); opacity: 1; cursor: not-allowed; }
.tl-calendario__dia--hoje { border-color: var(--border-contrast); font-weight: 600; }
.tl-calendario__dia--periodo { background: var(--surface-muted); border-radius: var(--radius-sm); }
.tl-calendario__dia--selecionado,
.tl-calendario__dia[aria-pressed="true"] {
  background: var(--state-selected-fill); color: var(--state-selected-on);
  border-color: var(--state-selected-fill); font-weight: 600;
}
.tl-calendario__dia--selecionado:hover:not(:disabled),
.tl-calendario__dia[aria-pressed="true"]:hover:not(:disabled) { background: var(--state-selected-fill); }
.tl-calendario__vazio { min-height: var(--size-touch); }
/* Instrução é texto de apoio, não ação: sem cor de destaque. */
.tl-calendario__instrucao {
  display: flex; align-items: flex-start; gap: var(--space-8); margin: 0;
  font: var(--rs-type-supporting); color: var(--text-secondary);
}
.tl-calendario__instrucao i { flex: none; margin-top: 2px; font-size: var(--size-icon-md); color: var(--text-primary); }

/* Filtro do histórico: o dia em vigor (rótulo de apoio + valor) e os atalhos numa linha. */
.tl-periodo__vigente { display: flex; flex-direction: column; gap: 2px; }
.tl-periodo__vigente > span { font: var(--rs-type-supporting); color: var(--text-secondary); }
.tl-periodo__vigente > strong { font: var(--rs-type-body-strong); color: var(--text-primary); }
.tl-periodo__atalhos { display: flex; flex-wrap: wrap; gap: var(--space-8); }
.tl-periodo__datas { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-8); }
.tl-periodo__datas .tl-campo { min-width: 0; }
.tl-periodo__datas i { color: var(--text-secondary); font-size: var(--size-icon-md); }

/*
  Bloco de filtros do diálogo de busca. `.tl-dialogo__filtros` (seção 6) dá a caixa; aqui fica o
  arranjo interno — frota e status lado a lado, busca e faixas. Rótulos em sentence case.
*/
.tl-busca__rotulo { font: var(--rs-type-label); color: var(--text-primary); }
/* Dois seletores na mesma linha; com uma frota só, o de status ocupa a linha inteira. */
.tl-busca__selecoes {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); gap: var(--space-12);
  margin-bottom: var(--space-12);
}
.tl-busca__selecao { display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; }
/* O mesmo desenho dos seletores da auditoria (seção 10): pílula de 44px, borda forte, corpo 16px. */
.tl-busca__selecao select {
  width: 100%; min-width: 0; height: var(--size-touch); padding: 0 var(--space-12);
  border: var(--border-width-1) solid var(--border-strong); border-radius: var(--radius-md);
  background: var(--surface-default); color: var(--text-primary); font: var(--rs-type-body);
  text-overflow: ellipsis; cursor: pointer;
  transition: border-color var(--duration-fast) var(--ease-standard);
}
.tl-busca__selecao select:hover { border-color: var(--border-contrast); }
/* Visto do chip ligado: o estado não depende só do laranja. O chip removível (com X) não o recebe. */
.tl-chip__visto { display: none; font-size: var(--size-icon-sm); }
.tl-chip[aria-pressed="true"] > .tl-chip__visto,
.tl-chip[aria-checked="true"] > .tl-chip__visto { display: inline-block; }
/* Onde a busca está procurando agora — texto, não controle. */
.tl-busca__alcance { margin: var(--space-4) 0 0; font: var(--rs-type-supporting); color: var(--text-secondary); }

/*
  A lupa fica FORA do campo: ela é o gesto que dispara a consulta, e um alvo próprio ao lado do
  campo é o que o dedo alcança. `stretch` iguala a altura dos dois.
*/
.tl-busca__linha { display: flex; align-items: stretch; gap: var(--space-8); }
.tl-busca__linha .tl-campo { flex: 1; min-width: 0; }
.tl-busca__lupa { flex: none; width: 48px; min-height: var(--size-touch); padding: 0; justify-content: center; }

/* "Mais filtros": área secundária em --bg-subtle, duas faixas lado a lado (uma abaixo de 480px). */
.tl-busca__avancar { margin-top: var(--space-12); }
.tl-busca__faixas {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-16);
  margin-top: var(--space-12); padding: var(--space-16);
  border-radius: var(--radius-md); background: var(--bg-subtle);
}
.tl-busca__faixa { min-width: 0; margin: 0; padding: 0; border: 0; }
.tl-busca__faixa legend { padding: 0 0 var(--space-8); font: var(--rs-type-label); color: var(--text-primary); }
.tl-busca__faixa legend i { margin-right: var(--space-4); font-size: var(--size-icon-sm); }
.tl-busca__faixa-campos { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-8); }
.tl-busca__medida { display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; }
.tl-busca__medida > span { font: var(--rs-type-supporting); color: var(--text-secondary); }
/* `.tl-campo` é um <span> aqui (dentro do <label>), então precisa do display que o seletor de tag não dá. */
.tl-busca__medida .tl-campo { display: flex; min-width: 0; }
.tl-busca__medida input {
  flex: 1; min-width: 0; border: 0; background: transparent; color: var(--text-primary);
  font: var(--rs-type-body); font-variant-numeric: tabular-nums; outline: none;
}
.tl-busca__medida input::placeholder { color: var(--text-tertiary); opacity: 1; }

/*
  Sentinela da rolagem infinita. Tem altura própria de propósito: gatilho de altura zero nunca
  intersecta em alguns navegadores, e o vão é o mesmo em que o lote seguinte aparece.
*/
.tl-busca__sentinela {
  display: flex; align-items: center; justify-content: center; gap: var(--space-8);
  min-height: 52px; font: var(--rs-type-supporting); color: var(--text-secondary);
}
.tl-busca__sentinela i { color: var(--text-primary); }

/*
  Linha da lista de frota (VehicleListRow). Selecionada = borda de 2px em contraste (o recheio
  desconta 1px para a linha não crescer) e o botão preenchido com o visto — sem tingir a linha.
*/
.tl-item-frota {
  width: 100%; display: flex; align-items: center; gap: var(--space-12); min-height: 72px;
  padding: var(--space-12); border-radius: var(--radius-md);
  border: var(--border-width-1) solid var(--border-default); background: var(--surface-default);
  color: var(--text-primary); text-align: left;
  /* Mesma razão do .tl-dialogo__fechar: sem isto o botão parte do padrão do navegador. */
  font: var(--rs-type-body);
}
/*
  `aria-current`, e não `aria-selected`: a linha não é opção de listbox. Quem seleciona é o botão
  do fim da linha; a linha só declara que é a atual.
*/
.tl-item-frota[aria-current="true"] {
  border: var(--border-width-2) solid var(--border-contrast); padding: calc(var(--space-12) - 1px);
}
/* O botão não encolhe nem quebra: uma coluna de botões com larguras diferentes desalinha a lista. */
.tl-item-frota__selecionar { flex: none; white-space: nowrap; }
.tl-item-frota[aria-current="true"] .tl-item-frota__selecionar,
.tl-item-frota[aria-current="true"] .tl-item-frota__selecionar:hover {
  background: var(--state-selected-fill); color: var(--state-selected-on); border-color: var(--state-selected-fill);
}
/* Crachá da frota — só aparece quando há mais de uma ao alcance da sessão. */
.tl-item-frota__frota { display: inline-flex; align-items: center; gap: var(--space-4); color: var(--text-secondary); }

.tl-item-frota__corpo { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--space-4); }
.tl-item-frota__topo { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-12); }
/* O nome quebra em até duas linhas em vez de cortar o modelo com reticências. */
.tl-item-frota__nome {
  min-width: 0; font: var(--rs-type-card-title); color: var(--text-primary);
  overflow: hidden; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
}
/*
  Veículo cadastrado só com a placa: ela ocupa o lugar do nome. Não há texto para cortar, e o
  overflow:hidden cortava o anel de foco da placa, desenhado fora da caixa.
*/
.tl-item-frota__nome--placa { overflow: visible; display: block; }
.tl-item-frota__velocidade {
  flex: none; white-space: nowrap; color: var(--text-primary);
  font: var(--rs-type-data-md); font-variant-numeric: tabular-nums;
}
.tl-item-frota__base {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-4) var(--space-12);
  font: var(--rs-type-supporting); color: var(--text-secondary);
}
/*
  A ficha do veículo cai um degrau na rampa de neutros: placa, tempo e ficha são três fatos, e a
  ficha usa ponto internamente ("Fiat Fiorino · 2021 · Branca"). O degrau agrupa sem pontuação que
  sobraria órfã quando a linha quebra no celular.
*/
.tl-item-frota__base > [data-detalhe] { color: var(--text-tertiary); }
/* "Sem GPS" é um .tl-selo compacto (tracejado); aqui só não pode encolher. */
.tl-item-frota__sem-posicao { flex: none; }

@media (max-width: 479.98px) {
  /*
    No celular o botão encolhe em vez de descer para uma linha própria: descê-lo deixava três
    veículos por tela numa lista que pode ter milhares. O alvo continua com 44px.
  */
  .tl-item-frota__selecionar { padding: 0 var(--space-12); font: var(--rs-type-label); }
  .tl-busca__faixas { grid-template-columns: minmax(0, 1fr); }

}

/*
  Resumo da frota, no rodapé do diálogo de busca. `margin-right: auto` porque o rodapé alinha à
  direita: é contagem, não ação, e fica no canto oposto ao dos botões.
*/
.tl-resumo-frota {
  display: flex; align-items: center; gap: var(--space-12); flex-wrap: wrap; margin-right: auto;
  font: var(--rs-type-supporting); color: var(--text-secondary);
}
.tl-resumo-frota strong { font: var(--rs-type-label); font-variant-numeric: tabular-nums; color: var(--text-primary); }

/*
  Velocidade e odômetro (SpeedOdometer) — sempre visíveis, logo abaixo do cabeçalho do cartão.

  Colunas 2:3, e não iguais: o odômetro de caminhão ("123.456,7 km") não cabe em meia largura de
  um celular de 360px, e colunas por conteúdo fariam o odômetro andar de lado cada vez que a
  velocidade ganha um dígito. Rótulos alinham no topo e valores na base de cada célula.
*/
.tl-metricas {
  display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  column-gap: var(--space-24); row-gap: var(--space-12); align-items: stretch;
  margin: 0; padding-top: var(--space-12);
  border-top: var(--border-width-1) solid var(--border-subtle);
}
.tl-metrica { display: grid; grid-template-rows: auto 1fr; gap: 2px; min-width: 0; }
.tl-metrica + .tl-metrica {
  padding-inline-start: var(--space-24); border-inline-start: var(--border-width-1) solid var(--border-subtle);
}
.tl-metrica__rotulo {
  margin: 0; display: flex; align-items: center; gap: var(--space-4); min-width: 0;
  font: var(--rs-type-supporting); color: var(--text-secondary);
}
.tl-metrica__rotulo i { font-size: var(--size-icon-sm); color: var(--text-primary); }
/* O lápis (26px) não pode engordar a linha de 20px do rótulo: a margem negativa absorve a diferença. */
.tl-metrica__rotulo .tl-cartao__editar { margin-block: -3px; }
/* `font` zera font-variant-numeric: tabular-nums vem sempre depois da abreviação. */
.tl-metrica__valor {
  margin: 0; align-self: end; min-width: 0;
  display: flex; flex-wrap: wrap; align-items: baseline; column-gap: var(--space-4);
  font: var(--rs-type-data-md); font-variant-numeric: tabular-nums; color: var(--text-primary);
}
.tl-metrica__valor > [data-valor] { white-space: nowrap; }
.tl-metrica--xl .tl-metrica__valor { font: var(--rs-type-data-xl); letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
.tl-metrica--lg .tl-metrica__valor { font: var(--rs-type-data-lg); font-variant-numeric: tabular-nums; }
/* Unidade menor ao lado do número; também serve à velocidade da linha da frota. */
.tl-metrica__unidade { font: var(--rs-type-supporting); letter-spacing: 0; color: var(--text-secondary); }
.tl-metrica--xl .tl-metrica__unidade { font: var(--rs-type-label); }
.tl-metrica--lg .tl-metrica__unidade { font: var(--rs-type-supporting); }

/* Detalhes (dentro de "Mais"): grade de 4 colunas (2 no celular), sem o fio de 1px desenhado por fundo. */
.tl-detalhes {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-12);
  margin: 0; padding-top: var(--space-12);
  border-top: var(--border-width-1) solid var(--border-subtle); background: transparent;
}
.tl-detalhes > div { min-width: 0; padding: 0; background: transparent; }
.tl-detalhes dt {
  margin: 0 0 2px; display: flex; align-items: center; gap: var(--space-4);
  font: var(--rs-type-supporting); color: var(--text-secondary);
}
.tl-detalhes dt i { font-size: var(--size-icon-sm); color: var(--text-primary); }
.tl-detalhes dd { margin: 0; font: var(--rs-type-label); color: var(--text-primary); overflow-wrap: anywhere; }

@media (max-width: 719.98px) {
  .tl-metricas { column-gap: var(--space-16); }
  .tl-metrica + .tl-metrica { padding-inline-start: var(--space-16); }
  .tl-detalhes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Valor deduzido pelo servidor, e não reportado pelo equipamento: mais leve que a medição ao lado (nunca abaixo de 12px). */
.tl-inferido { margin-left: var(--space-4); font: var(--rs-type-caption); color: var(--text-tertiary); }

/* Painel interno do cartão do veículo (VehicleSummary). A casca opaca vem de .tl-vidro (seção 5). */
.tl-cartao__painel { display: flex; flex-direction: column; gap: var(--space-12); padding: var(--space-16); }
/* Detalhes, notas e coordenada abrem juntos em "Mais": o bloco precisa do próprio espaçamento. */
.tl-cartao__painel > [data-detalhes] { display: flex; flex-direction: column; gap: var(--space-12); }
/* Nome, placa + situação e ficha empilhados; o "Mais" desceu para a linha das métricas. */
.tl-cartao__cabecalho { display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; }
.tl-cartao__identidade { flex: 1; display: flex; align-items: center; gap: var(--space-8); min-width: 0; }
.tl-cartao__textos { flex: 1; min-width: 0; display: flex; flex-direction: column; }
/* O lápis fica colado ao rótulo que edita, e não na borda da coluna. */
.tl-cartao__rotulo-editavel { display: flex; align-items: center; justify-content: flex-start; gap: var(--space-4); }
.tl-cartao__rotulo-editavel > span { min-width: 0; }

/* "Mais"/"Menos": quadrado de 44px com o chevron, no canto das métricas. */
.tl-cartao__alternar {
  flex: none; min-height: var(--size-touch);
  border-color: var(--border-contrast);
}
/*
  Métricas e "Mais" na mesma linha: o botão encosta na base, ao lado dos números, e a régua que
  separava as métricas do cabeçalho passa a ser desta linha.
*/
.tl-cartao__resumo {
  display: flex; align-items: flex-end; gap: var(--space-12);
  padding-top: var(--space-12); border-top: var(--border-width-1) solid var(--border-subtle);
}
.tl-cartao__resumo > .tl-metricas { flex: 1 1 auto; min-width: 0; padding-top: 0; border-top: 0; }
.tl-cartao__alternar i { font-size: var(--size-icon-md); }

/*
  Lápis de edição — serve ao odômetro e ao cadastro do veículo: dois lápis no mesmo cartão são o
  mesmo botão. Desenho de 26px; o ::after leva a área de toque a 44px sem mexer na linha.
*/
.tl-cartao__editar {
  position: relative; flex: none;
  display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; padding: 0;
  border: 0; border-radius: var(--radius-full); background: transparent; color: var(--text-primary);
  font-size: var(--size-icon-sm); cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard);
}
.tl-cartao__editar::after { content: ""; position: absolute; inset: -9px; }
.tl-cartao__editar:hover { background: var(--state-hover); }

/*
  Linha do nome. O título encolhe até as reticências (min-width: 0, que o flex exige) e o lápis fica
  colado nele, e não na borda do cartão: é o nome que ele edita.
*/
.tl-cartao__nome { display: flex; align-items: center; gap: var(--space-8); min-width: 0; }
.tl-cartao__nome > .tl-cartao__titulo { min-width: 0; }
.tl-cartao__titulo {
  margin: 0; font: var(--rs-type-card-title); color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* A mesma razão de .tl-item-frota__nome--placa: com a placa no título, o anel de foco dela aparece. */
.tl-cartao__titulo--placa { overflow: visible; }
.tl-cartao__identificacao, .tl-cartao__meta {
  margin: var(--space-4) 0 0; font: var(--rs-type-supporting); color: var(--text-secondary);
}
/* A ficha ("Chevrolet Onix · 2022 · Prata") ocupa uma linha só, com reticências; o texto inteiro vai no title. */
.tl-cartao__identificacao { margin: 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Placa, selo de situação e "há 2 h" na mesma linha; em tela estreita o tempo desce inteiro. */
.tl-cartao__meta { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-4) var(--space-8); margin: var(--space-4) 0 0; }
.tl-cartao__nota { margin: 0; font: var(--rs-type-supporting); color: var(--text-secondary); }
.tl-cartao__nota > i { margin-inline-end: var(--space-4); font-size: var(--size-icon-sm); color: var(--text-primary); }
.tl-cartao__nota strong { font: var(--rs-type-label); color: var(--text-primary); }
/* Alarme: ícone e nome do alarme em perigo; o resto da frase fica no tom de apoio. */
.tl-cartao__nota--alarme > i,
.tl-cartao__nota--alarme > strong { color: var(--functional-danger); }
.tl-cartao__nota--gps > i { color: var(--text-secondary); }
/* Coordenada como identificador (sem monoespaçada): traços tabulares vêm depois da abreviação `font`. */
.tl-cartao__coordenada {
  margin: 0; color: var(--text-secondary);
  display: flex; align-items: center; gap: var(--space-8); flex-wrap: wrap;
  font: var(--rs-type-identifier); letter-spacing: .02em; font-feature-settings: "tnum" 1, "ss02" 1;
}
.tl-cartao__coordenada > i { font-size: var(--size-icon-sm); color: var(--text-primary); }
.tl-cartao__coordenada-texto { user-select: all; margin-inline-end: var(--space-4); }
a.tl-cartao__editar { text-decoration: none; }

/* Variante larga do diálogo — só o painel de auditoria precisa de espaço para uma tabela. */
.tl-dialogo--largo { width: min(var(--size-content), calc(100% - 48px)); }
@media (max-width: 719.98px) { .tl-dialogo--largo { width: 100%; } }

/* Painel de auditoria. */
.tl-auditoria { display: flex; flex-direction: column; gap: var(--space-16); padding: var(--space-16); }
.tl-auditoria__filtros { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-12); position: relative; }
.tl-auditoria__campo { display: flex; flex-direction: column; gap: var(--space-8); }
/*
  Filho direto, e não descendente: o popover do calendário é renderizado DENTRO do campo, e um
  seletor descendente alcançaria os dias da semana do calendário.

  `.tl-rotulo` entra na MESMA declaração: é o rótulo genérico que outros diálogos já escrevem na
  marcação. Todos em sentence case (Inter 600 14px), sem caixa alta.
*/
.tl-auditoria__campo > span,
.tl-rotulo { display: block; font: var(--rs-type-label); color: var(--text-primary); }
.tl-rotulo { margin-bottom: var(--space-8); }
/* O select do tamanho de página entra nesta lista em vez de repetir a declaração inteira. */
.tl-auditoria__campo select, .tl-auditoria__campo input, .tl-paginacao__tamanho select {
  height: var(--size-touch); min-width: 140px; padding: 0 var(--space-12);
  border: var(--border-width-1) solid var(--border-strong); border-radius: var(--radius-md);
  background: var(--surface-default); color: var(--text-primary); font: var(--rs-type-body);
  transition: border-color var(--duration-fast) var(--ease-standard);
}
.tl-auditoria__campo select:hover, .tl-auditoria__campo input:hover, .tl-paginacao__tamanho select:hover {
  border-color: var(--border-contrast);
}
.tl-auditoria__campo input::placeholder { color: var(--text-tertiary); opacity: 1; }
.tl-paginacao__tamanho { display: inline-flex; align-items: center; gap: var(--space-8); }
.tl-paginacao__tamanho > span { font: var(--rs-type-supporting); color: var(--text-secondary); }
.tl-paginacao__tamanho select { min-width: 96px; }
/* Popover do calendário: superfície opaca sobre a própria tabela, com a largura do calendário + recheio. */
.tl-auditoria__popover {
  position: absolute; z-index: 5; top: calc(100% + var(--space-8)); left: 0;
  min-width: 380px; padding: var(--space-16);
  background: var(--surface-default); border: var(--border-width-1) solid var(--border-default);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-overlay);
}
.tl-auditoria__total { margin-left: auto; text-align: right; display: flex; flex-direction: column; gap: 2px; }
.tl-auditoria__total strong {
  display: block; color: var(--text-primary);
  font: var(--rs-type-data-lg); font-variant-numeric: tabular-nums;
}
.tl-auditoria__total span { font: var(--rs-type-supporting); color: var(--text-secondary); }

/* Tabela responsiva (DataTable) — desktop: tabela; celular: um cartão por linha. */
.tl-tabela-wrap {
  overflow-x: auto; border: var(--border-width-1) solid var(--border-default);
  border-radius: var(--radius-lg); background: var(--surface-default);
}
.tl-tabela { width: 100%; border-collapse: collapse; font: var(--rs-type-supporting); color: var(--text-primary); }
.tl-tabela th, .tl-tabela td {
  padding: var(--space-12) var(--space-16); text-align: left; vertical-align: middle; white-space: nowrap;
  border-bottom: var(--border-width-1) solid var(--border-subtle);
}
.tl-tabela th { position: sticky; top: 0; background: var(--bg-subtle); font: var(--rs-type-label); color: var(--text-primary); }
.tl-tabela tbody tr:last-child td { border-bottom: 0; }
/* Só onde o ponteiro passa de verdade: no toque o realce gruda na última linha tocada. */
@media (hover: hover) { .tl-tabela tbody tr:hover td { background: var(--state-hover); } }
/* O rótulo por célula existe sempre no DOM; no desktop quem o mostra é o <thead>. */
.tl-tabela__rotulo { display: none; }

@media (max-width: 719.98px) {
  /*
    Cada linha vira um cartão de duas colunas e o rótulo passa a morar dentro da célula: oito
    colunas de largura fixa só se leriam arrastando de lado.

    O <thead> some com display:none, e não com a classe de leitor de tela: cada célula já anuncia o
    seu rótulo, e a semântica de tabela volta pelos papéis ARIA que TabelaResponsiva escreve.
  */
  .tl-tabela-wrap { overflow-x: visible; border: 0; border-radius: 0; background: transparent; }
  .tl-tabela { display: block; }
  .tl-tabela thead { display: none; }
  .tl-tabela tbody { display: flex; flex-direction: column; gap: var(--space-12); }

  .tl-tabela tbody tr {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-12);
    padding: var(--space-16); background: var(--surface-default);
    border: var(--border-width-1) solid var(--border-default); border-radius: var(--radius-md);
  }
  .tl-tabela tbody tr:hover td { background: transparent; }

  .tl-tabela td {
    display: flex; flex-direction: column; gap: 2px; padding: 0; border-bottom: 0; min-width: 0;
    white-space: normal; overflow-wrap: anywhere;
  }

  .tl-tabela__rotulo { display: block; margin: 0; font: var(--rs-type-supporting); color: var(--text-secondary); }
  /* Sem a abreviação `font`: a família e os traços do <td>.tl-mono (identificador) precisam chegar ao valor. */
  .tl-tabela__valor { display: block; font-size: 14px; font-weight: 400; line-height: 20px; color: var(--text-primary); }

  /* Coluna de destaque: título do cartão, à frente das demais mesmo se declarada fora de ordem. */
  .tl-tabela td.tl-tabela__celula--destaque { grid-column: 1 / -1; order: -1; }
  .tl-tabela td.tl-tabela__celula--destaque .tl-tabela__rotulo { display: none; }
  .tl-tabela td.tl-tabela__celula--destaque .tl-tabela__valor { font-size: 17px; font-weight: 600; line-height: 24px; }
  .tl-tabela td.tl-tabela__celula--larga { grid-column: 1 / -1; }
}

/* Paginação: informação à esquerda, controles à direita; Anterior/Próxima são .tl-btn secundários. */
.tl-paginacao {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--space-12) var(--space-24); font: var(--rs-type-supporting); color: var(--text-secondary);
}
.tl-paginacao [data-navegacao] { display: inline-flex; align-items: center; gap: var(--space-8); }
.tl-paginacao [data-posicao] { font: var(--rs-type-label); font-variant-numeric: tabular-nums; color: var(--text-primary); }

/*
  Página cheia fora do palco do mapa (rota /eventos-acoes) — precisa da própria rolagem porque
  app.css trava a rolagem do body para o painel do mapa.
*/
.tl-pagina { position: fixed; inset: 0; overflow-y: auto; background: var(--bg-canvas); color: var(--text-primary); }
/* Coluna flex mantida: .tl-pagina__conteudo--login (seção 11+) depende dela. */
.tl-pagina__conteudo {
  max-width: var(--size-content); margin: 0 auto; padding: var(--space-24);
  display: flex; flex-direction: column; gap: var(--space-16);
}
.tl-pagina__cabecalho { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-12); flex-wrap: wrap; }
.tl-pagina__cabecalho h1 { margin: var(--space-4) 0; font: var(--rs-type-page-title); letter-spacing: -0.01em; color: var(--text-primary); }
.tl-pagina__cabecalho p { margin: 0; max-width: 60ch; font: var(--rs-type-body); color: var(--text-secondary); }

/*
  Entorno da tabela no celular: os filtros dividem a largura em vez de manter 140px fixos, e o
  total sai do canto direito, onde ficava sozinho numa linha.
*/
@media (max-width: 719.98px) {
  .tl-pagina__conteudo { padding: var(--space-16) var(--space-12) var(--space-24); }
  .tl-auditoria { padding: var(--space-12); gap: var(--space-12); }
  .tl-auditoria__campo { flex: 1 1 150px; min-width: 0; }
  .tl-auditoria__campo select, .tl-auditoria__campo input, .tl-auditoria__campo > .tl-btn { width: 100%; min-width: 0; }
  /*
    O período ganha a linha inteira: em meia largura o resumo "dd/mm/aaaa a dd/mm/aaaa" quebrava em
    três linhas, e o popover, ancorado no campo, ficava com metade da largura do calendário (7 × 44px).
    O popover avança 8px sobre o recheio da auditoria e afina o próprio: no diálogo, os 320px do
    calendário cabem até num 360px.
  */
  .tl-auditoria__campo--periodo { flex-basis: 100%; }
  .tl-auditoria__popover {
    left: calc(-1 * var(--space-8)); right: calc(-1 * var(--space-8)); min-width: 0;
    padding: var(--space-8);
  }
  .tl-auditoria__total { margin-left: 0; text-align: left; align-self: flex-end; }
  .tl-paginacao { gap: var(--space-12); }
}

@media (max-width: 479.98px) {
  .tl-dialogo__conteudo { padding-inline: var(--space-16); }
}

/* Celular estreito: 7 dias de 44px + 6 vãos de 2px = 320px, e o recheio do diálogo encolhe junto. */
@media (max-width: 379.98px) {
  .tl-calendario__semana, .tl-calendario__dias { gap: 2px; }
  .tl-dialogo__conteudo { padding-inline: var(--space-12); }
}

/* ---------- 11. Escolha, preferência e valor copiável (diálogos de compartilhar, perfil e serviço) ---------- */
/*
  Três peças que o pacote de design não tinha porque não havia tela que as pedisse: um grupo de
  escolha única (.tl-opcoes/.tl-opcao, o SegmentedControl do sistema Rastram), uma lista de
  preferências (.tl-config) e o bloco de um valor que se copia com o olho e com o cursor (.tl-codigo).

  Nenhuma delas redefine foco: a régua universal de app.css (2px --focus-inner + --focus-halo) vale
  para todo elemento focável, e reescrevê-la aqui só criaria uma segunda régua para divergir. A única
  exceção documentada é a caixa do .tl-check, porque o <input> dela fica escondido.
*/

/*
  Grupo de escolha única. Coluna por padrão porque a variante alta (--cartao) só se lê empilhada; a
  linha é o SegmentedControl ("30 min · 2 h · 24 h", "Claro · Escuro"): a borda fica no CONTÊINER,
  e os segmentos vivem soltos dentro dele, separados por 2px.
*/
.tl-opcoes { display: flex; flex-direction: column; gap: var(--space-8); }
.tl-opcoes--linha {
  flex-direction: row; flex-wrap: nowrap;
  padding: 1px; gap: 2px;
  border: var(--border-width-1) solid var(--border-strong); border-radius: var(--radius-md);
  background: var(--surface-default);
}

/*
  Largura igual entre os segmentos (flex 1 1 0), e não largura de conteúdo: com base automática os
  botões mudariam de tamanho conforme o rótulo, e a linha inteira tremeria a cada clique.
*/
.tl-opcao {
  flex: 1 1 0; min-width: 72px; min-height: var(--size-touch);
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-8);
  padding: 0 var(--space-16); border: 0; border-radius: calc(var(--radius-md) - 2px);
  background: transparent; color: var(--text-primary);
  font: var(--rs-type-button); text-align: center; cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard);
}
.tl-opcao:hover { background: var(--state-hover); }
/*
  Escolhido: preenchimento preto com texto creme (invertido no tema escuro). A diferença é de
  claridade (20:1), não de matiz — quem não distingue cor continua vendo qual segmento está ligado.
*/
.tl-opcao[aria-checked="true"] { background: var(--state-selected-fill); color: var(--state-selected-on); }

/*
  Variante alta (Recuperar / Somente verificar): ícone à esquerda, título e descrição em coluna, cada
  cartão com a própria borda porque aqui não há contêiner segmentado. Os três filhos são diretos e
  irmãos (<i>, <strong>, <span>), sem invólucro — daí a grade nomeada, que é o que permite ao ícone
  ocupar as duas linhas de texto sem um <span> agrupador na marcação.
*/
.tl-opcao--cartao {
  flex: none; min-width: 0;
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas: "icone titulo" "icone descricao";
  align-items: center; justify-items: start; text-align: left;
  gap: var(--space-4) var(--space-12); padding: var(--space-12) var(--space-16);
  border: var(--border-width-1) solid var(--border-strong); border-radius: var(--radius-md);
  background: var(--surface-default);
  transition: background-color var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard);
}
.tl-opcao--cartao:hover { border-color: var(--border-contrast); }
.tl-opcao--cartao > i { grid-area: icone; align-self: center; font-size: var(--size-icon-lg); color: var(--text-primary); }
.tl-opcao--cartao > strong { grid-area: titulo; font: var(--rs-type-label); }
.tl-opcao--cartao > span { grid-area: descricao; font: var(--rs-type-supporting); color: var(--text-secondary); }
/* No cartão escolhido tudo herda o creme do preenchimento — a descrição é a linha que evita o socorro errado. */
.tl-opcao--cartao[aria-checked="true"] { border-color: var(--state-selected-fill); }
.tl-opcao--cartao[aria-checked="true"] > i,
.tl-opcao--cartao[aria-checked="true"] > span { color: inherit; }

/*
  Caixa de marcação — js/componentes/modal-compartilhar.js e modal-recuperacao.js

  O <input> continua nativo, e não um botão com ARIA: ele já é anunciado, já entra na navegação por
  teclado e já responde à barra de espaço. O que se vê é a caixa de 20px (.tl-check__caixa) com o
  fa-check; o input fica escondido mas focável, e a linha inteira (44px) é clicável.
*/
.tl-check {
  position: relative;
  display: inline-flex; align-items: center; gap: var(--space-12);
  min-height: var(--size-touch); padding: 0; border: 0; border-radius: 0;
  background: transparent; color: var(--text-primary);
  font: var(--rs-type-body); cursor: pointer;
}
.tl-check input[type="checkbox"] {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; opacity: 0;
}
.tl-check__caixa {
  display: grid; place-items: center; flex: none; width: 20px; height: 20px;
  border: var(--border-width-2) solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface-default); color: transparent; font-size: 12px;
  transition: background-color var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard);
}
.tl-check:hover .tl-check__caixa { border-color: var(--border-contrast); }
.tl-check input:checked + .tl-check__caixa {
  background: var(--state-selected-fill); border-color: var(--state-selected-fill); color: var(--state-selected-on);
}
/* Exceção à régua universal: o anel vai na caixa visível, porque o input está escondido. Mesmos valores. */
.tl-check input:focus-visible + .tl-check__caixa {
  outline: var(--border-width-2) solid var(--focus-inner); outline-offset: 2px; box-shadow: var(--focus-halo);
}
.tl-check input:disabled + .tl-check__caixa { background: var(--action-disabled-bg); border-color: var(--border-subtle); }
.tl-check input:disabled ~ .tl-check__texto { color: var(--text-disabled); }
.tl-check__texto { min-width: 0; }
.tl-check__texto small { display: block; font: var(--rs-type-supporting); color: var(--text-secondary); }
/* Indisponível (veículo já bloqueado): quem carrega o recado é o texto e o `disabled`; a cor é reforço. */
.tl-check--indisponivel { cursor: not-allowed; }
.tl-check--indisponivel .tl-check__texto { color: var(--text-disabled); }

/* Lista de preferências: uma caixa só, com faixa de cabeçalho e linhas divididas por régua. */
.tl-config {
  display: flex; flex-direction: column;
  border: var(--border-width-1) solid var(--border-default); border-radius: var(--radius-lg);
  background: var(--surface-default); overflow: hidden;
}
/* É um <h3>: sem a margem zerada, o navegador abriria um vão dentro da própria faixa. Sobretítulo de uma palavra → overline. */
.tl-config__grupo {
  margin: 0; padding: var(--space-8) var(--space-16);
  background: var(--bg-subtle); border-bottom: var(--border-width-1) solid var(--border-subtle);
  font: var(--rs-type-overline); letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-secondary);
}
/*
  Grade de três colunas — ícone, texto, controle —, e não flex: com flex, a coluna do meio precisaria
  de min-width:0 e ainda assim o controle da direita mudaria de posição de linha para linha,
  conforme o tamanho do texto. Na grade, as três colunas se alinham entre TODAS as linhas da lista.
*/
.tl-config__linha {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center; gap: var(--space-12);
  min-height: var(--size-touch); padding: var(--space-12) var(--space-16);
  border-bottom: var(--border-width-1) solid var(--border-subtle);
}
.tl-config__linha:last-child { border-bottom: 0; }
/* Largura mínima no ícone para que os glifos, que têm larguras diferentes, comecem no mesmo x. Cor do texto, como todo ícone. */
.tl-config__linha > i { justify-self: center; min-width: var(--space-16); text-align: center; font-size: var(--size-icon-md); color: var(--text-primary); }
.tl-config__linha > span { display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; }
.tl-config__linha > span > strong { font: var(--rs-type-label); color: var(--text-primary); }
.tl-config__linha > span > span { font: var(--rs-type-supporting); color: var(--text-secondary); }
/*
  O interruptor (.tl-switch) e a linha indisponível saíram junto com as duas preferências que não
  tinham destino — alerta sonoro e reconexão automática. Toda configuração que restou é escolha de
  verdade, feita por .tl-opcoes.
*/

/*
  Valor para ser lido em voz alta e copiado: link de compartilhamento, coordenada do atendimento.
  user-select:all faz um clique selecionar o valor inteiro — é a saída manual quando a área de
  transferência do navegador recusa a cópia automática.

  A fonte é a do identificador (Inter 600 + tnum + ss02, que separa 0/O e 1/I), a MESMA de .tl-mono,
  que acompanha esta classe em todos os usos: declarar igual aqui evita que as duas divirjam.
*/
.tl-codigo {
  display: block; margin: 0; padding: var(--space-8) var(--space-12);
  border: var(--border-width-1) solid var(--border-default); border-radius: var(--radius-md);
  background: var(--bg-subtle); color: var(--text-primary);
  font: var(--rs-type-identifier); letter-spacing: .02em; font-feature-settings: "tnum" 1, "ss02" 1;
  overflow-wrap: anywhere; user-select: all; -webkit-user-select: all;
}

/*
  Iniciais de quem está na sessão. Telha --surface-muted com o raio médio, e não um disco: o sistema
  reserva o círculo a pontos, chips compactos, interruptores e botões de ícone.
*/
.tl-avatar {
  flex: none; width: 48px; height: 48px; border-radius: var(--radius-md);
  display: inline-flex; align-items: center; justify-content: center;
  border: var(--border-width-1) solid var(--border-default);
  background: var(--surface-muted); color: var(--text-primary);
  font: var(--rs-type-data-md); text-transform: uppercase; letter-spacing: .02em;
}
.tl-avatar i { font-size: var(--size-icon-lg); color: var(--text-secondary); }

/*
  Campo de texto de várias linhas. .tl-campo trava a altura e só estiliza `input`, então a variante
  precisa soltar a altura, alinhar o conteúdo pelo topo e vestir o <textarea>.
*/
.tl-campo--area { height: auto; min-height: 96px; align-items: stretch; padding: var(--space-12); }
.tl-campo--area textarea {
  flex: 1; width: 100%; min-width: 0; border: 0; background: transparent; color: var(--text-primary);
  font: var(--rs-type-body); outline: none; resize: vertical;
}
/* O texto de exemplo precisa de cor declarada: o cinza padrão do navegador não acompanha o tema. */
.tl-campo--area textarea::placeholder { color: var(--text-tertiary); opacity: 1; }

/*
  O botão verde do envio saiu: o sistema não tem botão de sucesso — --functional-success só colore
  ícone de confirmação. "Gerar link seguro" é a decisão do diálogo e vai em .tl-btn--primario.
*/

/*
  Rodapé com os dois botões afastados (destrutivo à esquerda, saída à direita).

  O modificador fica num <div> DENTRO do rodapé, e não no <footer>: quem renderiza
  <footer class="tl-dialogo__rodape"> é dialogo.js, que não aceita classe extra. Como o rodapé não
  é um contêiner flex, o invólucro é um bloco e já ocupa a largura toda; o width:100% é a garantia de
  que continue ocupando se o rodapé um dia virar flex.
*/
.tl-dialogo__rodape--entre {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-12); flex-wrap: wrap; width: 100%;
}

@media (max-width: 719.98px) {
  /*
    Na largura de celular as três colunas da linha de configuração não cabem: o grupo de opções
    espremia o texto que explica a preferência. O controle desce para uma segunda linha, alinhado
    com o texto (coluna 2), e passa a ocupar a largura disponível.
  */
  .tl-config__linha { grid-template-columns: auto minmax(0, 1fr); gap: var(--space-8) var(--space-12); }
  .tl-config__linha > i { align-self: start; margin-top: 2px; }
  .tl-config__linha > .tl-opcoes { grid-column: 2; justify-self: stretch; width: 100%; }
}

/* Rodapé empilhado no celular estreito, com a saída embaixo, onde o polegar chega. */
@media (max-width: 479.98px) {
  .tl-dialogo__rodape--entre { flex-direction: column-reverse; }
  .tl-dialogo__rodape--entre .tl-btn { width: 100%; }
}

/*
  Ação dentro da pílula do campo — o olho que revela a senha nova da conta (js/componentes/ficha-campos.js)
  e o "x" que limpa a busca da frota (js/componentes/modal-frota.js). Botão de ícone reduzido (36px),
  redondo como todo botão de ícone: não pode herdar o min-height de .tl-btn, que esticaria a caixa.
*/
.tl-campo__acao {
  flex: none; display: inline-grid; place-items: center; width: 36px; height: 36px; padding: 0;
  border: var(--border-width-1) solid transparent; border-radius: var(--radius-full);
  background: transparent; color: var(--text-secondary); font-size: var(--size-icon-md); cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard);
}
.tl-campo__acao:hover { background: var(--state-hover); color: var(--text-primary); }
.tl-campo__acao[aria-pressed="true"] { background: var(--state-selected-fill); color: var(--state-selected-on); border-color: var(--state-selected-fill); }

/*
  Variante discreta: ação secundária que vive dentro do conteúdo, e não no rodapé — botão sutil com
  cara de link (sublinhado, cor de link, 44px de alvo). Usada só pelo diálogo da frota.
*/
.tl-btn--discreto {
  min-height: var(--size-touch); padding: 0 var(--space-12); border: 0; background: transparent;
  color: var(--text-link); font: var(--rs-type-button);
  text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px;
}
.tl-btn--discreto:hover { filter: none; background: var(--action-subtle-bg-hover); color: var(--text-link); text-decoration-thickness: 2px; }

/*
  O `cursor: progress` de .tl-btn:disabled fala de trabalho em curso; um primário travado por
  formulário incompleto não está trabalhando, está esperando o operador.
*/
.tl-btn:disabled:not([aria-busy="true"]) { cursor: not-allowed; }

/*
  Diálogo de erro técnico (js/componentes/modal-erro-tecnico.js). Aviso de falha do sistema
  (borda 2px --functional-danger sobre a superfície, sem véu tintado), porque é sempre um bug — nunca
  uma validação esperada, que já tem tratamento próprio inline.
*/
.tl-erro-tecnico__aviso {
  display: flex; align-items: flex-start; gap: var(--space-12); margin: 0 0 var(--space-12);
  padding: calc(var(--space-12) - 1px) calc(var(--space-16) - 1px);
  border: var(--border-width-2) solid var(--functional-danger); border-radius: var(--radius-md);
  background: var(--surface-default); color: var(--text-primary); font: var(--rs-type-supporting);
}
.tl-erro-tecnico__aviso i { flex: none; margin-top: 2px; font-size: var(--size-icon-lg); color: var(--functional-danger); }
/* Nome de chave de configuração: identificador em Inter, sem monoespaçada (o sistema tem duas famílias só). */
.tl-erro-tecnico__aviso code { font: inherit; font-weight: 600; letter-spacing: .02em; font-feature-settings: "tnum" 1, "ss02" 1; }
/*
  A pilha vai em Inter com números tabulares e ss02 (0/O, 1/I): perde o alinhamento por coluna da
  monoespaçada, mas é diálogo de diagnóstico, e pre-wrap mantém as quebras originais.
*/
.tl-erro-tecnico__corpo {
  display: block; max-height: 50vh; margin: 0; padding: var(--space-12);
  border: var(--border-width-1) solid var(--border-default); border-radius: var(--radius-md);
  background: var(--bg-subtle); color: var(--text-primary);
  font: var(--rs-type-data-sm); letter-spacing: .02em; font-feature-settings: "tnum" 1, "ss02" 1;
  white-space: pre-wrap; overflow-wrap: anywhere; overflow-y: auto; user-select: text;
}

/* Validade do acesso na mesma tela de rastreamento. Fundo, borda e sombra vêm da .tl-vidro (opaca) da marcação. */
.tl-acesso-compartilhado {
  position: absolute;
  z-index: var(--z-map-controls);
  bottom: calc(var(--space-16) + env(safe-area-inset-bottom, 0px));
  /*
    Centrado por margem, não por left 50% + translate: com left 50% a largura disponível para o
    texto encolhia à metade da tela, e "Acesso compartilhado: 23:55:31" quebrava em três linhas.
  */
  left: 0; right: 0; margin-inline: auto; width: fit-content;
  max-width: calc(100% - 2 * var(--space-16));
  padding: var(--space-12) var(--space-16);
  border-radius: var(--radius-lg);
  text-align: center;
  font: var(--rs-type-label);
  font-variant-numeric: tabular-nums;
}
/*
  Link que autoriza o bloqueio: o menu volta, e o contador sobe para cima dele. No celular, sobe
  também a atribuição e encosta à esquerda, longe do zoom.
*/
.tl-palco:has(> .tl-menu-inferior:not([hidden])) .tl-acesso-compartilhado {
  bottom: calc(env(safe-area-inset-bottom, 0px) + var(--tl-altura-menu) + var(--space-16));
}
@media (max-width: 719.98px) {
  .tl-palco:has(> .tl-menu-inferior:not([hidden])) .tl-acesso-compartilhado {
    bottom: calc(env(safe-area-inset-bottom, 0px) + var(--tl-altura-menu) + var(--tl-altura-atribuicao) + var(--space-16));
    left: var(--space-16); right: auto; margin-inline: 0;
    max-width: calc(100% - 3 * var(--space-16) - var(--size-touch));
  }
}

/* Véu plano (--bg-scrim), sem desfoque: o mapa por baixo só precisa deixar de competir com o cartão. */
.tl-acesso-encerrado {
  position: absolute;
  z-index: var(--z-scrim);
  inset: 0;
  display: grid;
  place-items: center;
  padding: max(var(--space-16), env(safe-area-inset-top, 0px)) var(--space-16)
    max(var(--space-16), env(safe-area-inset-bottom, 0px));
  background: var(--bg-scrim);
}

/* É um diálogo de alerta, não uma sobreposição do mapa: fundo e sombra de diálogo por cima da .tl-vidro da marcação. */
.tl-acesso-encerrado__cartao {
  width: min(var(--size-dialog-sm), 100%);
  padding: clamp(var(--space-24), 6vw, var(--space-32));
  border: var(--border-width-1) solid var(--border-default);
  border-radius: var(--radius-lg);
  background: var(--surface-default);
  box-shadow: var(--shadow-dialog);
  text-align: center;
}

/* Telha do estado de erro: anel interno de 2px em --functional-danger, sem disco tintado. */
.tl-acesso-encerrado__icone {
  display: inline-grid;
  place-items: center;
  width: 56px;
  height: 56px;
  margin-bottom: var(--space-12);
  border-radius: var(--radius-lg);
  background: var(--surface-default);
  color: var(--functional-danger);
  box-shadow: inset 0 0 0 var(--border-width-2) var(--functional-danger);
  font-size: 24px;
}

.tl-acesso-encerrado__rotulo {
  margin: 0 0 var(--space-8);
  color: var(--text-secondary);
  font: var(--rs-type-overline);
  letter-spacing: .08em;
  text-transform: uppercase;
}

/* Passo de título de página do sistema (Manrope), que já cai para 26/32 abaixo de 720px. */
.tl-acesso-encerrado h1 {
  margin: 0 0 var(--space-12);
  color: var(--text-primary);
  font: var(--rs-type-page-title);
  letter-spacing: -0.01em;
}

.tl-acesso-encerrado__cartao > p:not(.tl-acesso-encerrado__rotulo) {
  margin: 0;
  color: var(--text-secondary);
  font: var(--rs-type-body);
}

.tl-acesso-encerrado__orientacao {
  padding-top: var(--space-8);
}

.tl-acesso-encerrado .tl-btn {
  width: 100%;
  margin-top: var(--space-16);
}

/* ---------------------------------------------------------------------------------------------
  Ficha de cadastro do veículo — js/componentes/modal-veiculo.js

  Duas colunas a partir de 480px e uma só abaixo. Cada campo empilha rótulo, pílula e erro por
  FORA da .tl-campo, pelo mesmo motivo do bloco de senha: a .tl-campo é uma linha travada em altura,
  desenhada para o par [ícone][campo], e três elementos dentro dela apareceriam espremidos.
--------------------------------------------------------------------------------------------- */
.tl-ficha { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-16) var(--space-24); }
.tl-ficha__campo { display: flex; flex-direction: column; gap: var(--space-8); min-width: 0; }
.tl-ficha__campo--largo { grid-column: 1 / -1; }
.tl-ficha__campo label { font: var(--rs-type-label); color: var(--text-primary); }
/* Erro = texto + ícone (fa-circle-exclamation) + borda de 2px no campo; nunca cor sozinha. */
.tl-ficha__erro { display: flex; gap: var(--space-8); align-items: flex-start; margin: 0; font: var(--rs-type-label); color: var(--functional-danger); }
.tl-ficha__erro i { flex: none; margin-top: 2px; font-size: var(--size-icon-md); }
.tl-ficha__nota { margin: 0 0 var(--space-12); font: var(--rs-type-supporting); color: var(--text-secondary); }

/*
  Campo recusado: a borda de 2px marca qual pílula o erro logo abaixo descreve. Dois gatilhos porque
  a marcação está migrando para aria-invalid no <input>; o erro visível continua valendo enquanto isso.
*/
.tl-ficha__campo:has(.tl-ficha__erro:not([hidden])) .tl-campo,
.tl-ficha .tl-campo:has(input[aria-invalid="true"]) { border: var(--border-width-2) solid var(--functional-danger); }

@media (max-width: 479.98px) {
  .tl-ficha { grid-template-columns: minmax(0, 1fr); }
}

/* =============================================================================
   Console do rastreador (componentes/console-comandos.js)

   Um registro de conversa: a linha que saiu (fa-arrow-right) e a que voltou (fa-arrow-left), em
   Inter com números tabulares e ss02 — o sistema não tem monoespaçada, e o que distingue 0/O e 1/I
   nas respostas de protocolo é o conjunto estilístico, não a família. Os atalhos são chips de
   44px (alvo de toque), e o acordeão mantém uma seção aberta por vez para o diálogo não crescer.
   ============================================================================= */
.tl-console { gap: var(--space-12); }
.tl-console__intro { margin: 0; font: var(--rs-type-supporting); color: var(--text-secondary); }
.tl-console__sugestoes { display: flex; flex-wrap: wrap; gap: var(--space-8); }
.tl-console__chip {
  display: inline-flex; align-items: center; gap: var(--space-8);
  min-height: var(--size-touch); padding: 0 var(--space-16); cursor: pointer;
  border: var(--border-width-1) solid var(--border-strong); border-radius: var(--radius-full);
  background: var(--surface-default); color: var(--text-primary);
  font: var(--rs-type-identifier); letter-spacing: .02em; font-feature-settings: "tnum" 1, "ss02" 1;
  transition: background-color var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard);
}
.tl-console__chip:hover { background: var(--state-hover); border-color: var(--border-contrast); }
.tl-console__rotulo { font: var(--rs-type-label); color: var(--text-primary); }
/* 16px para o iOS não aproximar a tela ao focar; ss02 separa 0/O e 1/I nos comandos digitados. */
.tl-console__campo input { font: var(--rs-type-body); letter-spacing: .02em; font-feature-settings: "tnum" 1, "ss02" 1; }
/* Campo recusado: a mesma borda de 2px da ficha, por classe ou por aria-invalid no <input>. */
.tl-console__campo.tl-campo--invalido,
.tl-console__campo:has(input[aria-invalid="true"]) { border: var(--border-width-2) solid var(--functional-danger); }
.tl-console__envelope {
  display: flex; align-items: center; gap: var(--space-12); min-height: var(--size-touch);
  font: var(--rs-type-supporting); color: var(--text-primary);
}
/* Caixa nativa de 20px na cor de seleção; o color-scheme de tokens.css a acompanha no tema escuro. */
.tl-console__envelope input { flex: none; margin: 0; width: 20px; height: 20px; accent-color: var(--state-selected-fill); }
/*
  O registro fixa peso 400 e números tabulares por cima da .tl-mono da marcação (identificador, 600):
  é leitura corrida de várias linhas, não um código a destacar.
*/
.tl-console__log {
  margin: 0; padding: var(--space-12); list-style: none; display: flex; flex-direction: column; gap: var(--space-8);
  max-height: 40vh; overflow: auto; border-radius: var(--radius-md);
  border: var(--border-width-1) solid var(--border-default); background: var(--bg-subtle);
  font: var(--rs-type-data-sm); letter-spacing: .02em; font-feature-settings: "tnum" 1, "ss02" 1;
}
.tl-console__log:empty { display: none; }
.tl-console__linha { display: grid; grid-template-columns: auto auto 1fr; gap: var(--space-8); align-items: baseline; }
.tl-console__hora { color: var(--text-tertiary); }
.tl-console__seta { color: var(--text-secondary); }
.tl-console__seta i { font-size: var(--size-icon-sm); }
.tl-console__texto { overflow-wrap: anywhere; white-space: pre-wrap; }
/* Resposta do equipamento em destaque sobre o envio; a cor entra só quando o comando falhou. */
.tl-console__linha--rx .tl-console__seta { color: var(--text-primary); }
.tl-console__linha--pendente .tl-console__texto { color: var(--text-tertiary); font-style: normal; }
.tl-console__linha--falha .tl-console__seta, .tl-console__linha--falha .tl-console__texto { color: var(--status-failed); }

/* Modelo identificado ao abrir (VERSION#): um aviso informativo no topo, com as notas do firmware embaixo. */
.tl-console__modelo {
  display: flex; flex-direction: column; gap: var(--space-4); padding: var(--space-8) var(--space-12);
  border-radius: var(--radius-md); border: var(--border-width-1) solid var(--border-default); background: var(--bg-subtle);
}
.tl-console__modelo-linha { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-8); font: var(--rs-type-label); color: var(--text-primary); }
.tl-console__modelo-linha > i { color: var(--text-primary); font-size: var(--size-icon-md); }
.tl-console__modelo-titulo { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.tl-console__modelo-notas { margin: 0; font: var(--rs-type-supporting); color: var(--text-secondary); }
.tl-console__modelo--pendente .tl-console__modelo-titulo { color: var(--text-tertiary); font-style: normal; }
/* Falha na identificação: aviso de falha (borda 2px), e o padding absorve o pixel a mais para nada se mover. */
.tl-console__modelo--falha {
  border: var(--border-width-2) solid var(--functional-danger);
  padding: calc(var(--space-8) - 1px) calc(var(--space-12) - 1px);
  background: var(--surface-default);
}
.tl-console__modelo--falha .tl-console__modelo-linha > i { color: var(--functional-danger); }

/* Acordeão (componentes/acordeao.js): seções recolhíveis em <details>; no console, uma aberta por vez.
   A seta aponta para cima com a seção aberta (recolher) e vira para baixo quando fechada (abrir).
   O <summary> é focável e recebe a régua universal de foco. */
.tl-acordeao { display: flex; flex-direction: column; gap: var(--space-8); }
.tl-acordeao__secao { border: var(--border-width-1) solid var(--border-default); border-radius: var(--radius-md); padding: var(--space-8) var(--space-12); }
.tl-acordeao__titulo {
  display: flex; align-items: center; gap: var(--space-8); min-height: var(--size-touch); cursor: pointer; list-style: none;
  font: var(--rs-type-label); color: var(--text-primary);
}
.tl-acordeao__titulo::-webkit-details-marker { display: none; }
.tl-acordeao__titulo > i { color: var(--text-primary); font-size: var(--size-icon-md); }
.tl-acordeao__titulo > .tl-acordeao__seta { margin-left: auto; color: var(--text-secondary); transition: transform var(--duration-base) var(--ease-standard); }
.tl-acordeao__secao:not([open]) .tl-acordeao__seta { transform: rotate(180deg); }
.tl-acordeao__corpo { display: flex; flex-direction: column; gap: var(--space-8); padding-top: var(--space-8); }

/* Grupo de passos (economia de dados, formato estendido): cada passo com explicação, campo, envio e o
   selo de conferência; os dois botões do grupo ficam no rodapé dele. */
.tl-console__grupo { display: flex; flex-direction: column; }
.tl-console__grupo-intro { margin: 0; font: var(--rs-type-supporting); color: var(--text-secondary); }
/* Instrução de cuidado em peso 600 e na cor do texto — nunca laranja como texto (não alcança contraste). */
.tl-console__grupo-aviso { margin: var(--space-8) 0 0; font: var(--rs-type-label); color: var(--text-primary); }
.tl-console__passos { margin: var(--space-12) 0 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--space-12); }
.tl-console__passo { display: flex; flex-direction: column; gap: var(--space-4); padding-top: var(--space-8); border-top: var(--border-width-1) solid var(--border-subtle); }
.tl-console__passo-cabecalho { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-8); }
.tl-console__passo-titulo { font: var(--rs-type-label); color: var(--text-primary); }
/*
  Resultado da conferência como selo de situação (StatusBadge): retângulo de 28px com ícone + palavra,
  forma por estado — neutro em --surface-muted, confirmado só com o ícone verde, pendente tracejado,
  falhou com contorno de 2px. A cor nunca vem sozinha, e o teste lê o textContent exato do <span>.
*/
.tl-console__passo-situacao {
  display: inline-flex; align-items: center; gap: var(--space-4); min-height: 28px; padding: 0 var(--space-8);
  border: var(--border-width-1) solid transparent; border-radius: var(--radius-sm);
  background: var(--surface-muted); color: var(--text-primary); overflow-wrap: anywhere;
  font: var(--rs-type-label);
}
.tl-console__passo-situacao i { font-size: var(--size-icon-sm); }
.tl-console__passo-situacao--neutro { background: var(--surface-muted); color: var(--text-primary); }
.tl-console__passo-situacao--ok { background: var(--surface-default); color: var(--text-primary); border-color: var(--border-default); }
.tl-console__passo-situacao--ok i { color: var(--status-confirmed); }
.tl-console__passo-situacao--warn {
  background: var(--status-pending-bg); color: var(--status-pending-fg);
  border: var(--border-width-2) dashed var(--status-pending-border); padding-inline: 7px;
}
.tl-console__passo-situacao--crit {
  background: var(--surface-default); color: var(--text-primary);
  border: var(--border-width-2) solid var(--status-failed); padding-inline: 7px;
}
.tl-console__passo-situacao--crit i { color: var(--status-failed); }
.tl-console__passo-explicacao { margin: 0; font: var(--rs-type-supporting); color: var(--text-secondary); }
.tl-console__passo-acoes { display: flex; gap: var(--space-8); align-items: stretch; }
.tl-console__passo-acoes .tl-campo { flex: 1 1 auto; min-width: 0; }
.tl-console__passo-acoes .tl-btn { flex: none; }
.tl-console__grupo-acoes { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--space-12); margin-top: var(--space-12); }

/* Seção "Todos os comandos": o campo livre e o registro primeiro, a referência por categoria abaixo.
   Cada item é o chip do comando (preenche o campo), a explicação, a resposta esperada e as etiquetas. */
.tl-console__comandos { display: flex; flex-direction: column; gap: var(--space-8); }
.tl-console__erro { display: flex; gap: var(--space-8); align-items: flex-start; margin: 0; font: var(--rs-type-label); color: var(--functional-danger); }
.tl-console__erro i { flex: none; margin-top: 2px; font-size: var(--size-icon-md); }
.tl-console__referencia-intro { margin: var(--space-8) 0 0; font: var(--rs-type-supporting); color: var(--text-secondary); }
.tl-console__referencia { display: flex; flex-direction: column; gap: var(--space-12); }
/* Nome de categoria (1–3 palavras): o único lugar do console em caixa alta, como sobretítulo. */
.tl-console__categoria-titulo {
  margin: 0; font: var(--rs-type-overline); letter-spacing: .08em; text-transform: uppercase; color: var(--text-secondary);
}
.tl-console__itens { margin: var(--space-4) 0 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--space-8); }
.tl-console__item { display: flex; flex-direction: column; gap: var(--space-4); padding-top: var(--space-8); border-top: var(--border-width-1) solid var(--border-subtle); }
/* Comando que não existe neste modelo: cores de desabilitado e riscado, sem opacidade (que lava o contraste). */
.tl-console__item--ausente .tl-console__chip {
  opacity: 1; text-decoration: line-through;
  color: var(--text-disabled); background: var(--action-disabled-bg); border-color: var(--border-subtle);
}
.tl-console__item-linha { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-8); }
/* Na referência o chip pode quebrar linha: comandos longos (SZCS#SLPDISCONNECT=1) não cabem em 360px. */
.tl-console__item-linha .tl-console__chip { padding: var(--space-8) var(--space-16); line-height: 20px; text-align: left; white-space: normal; overflow-wrap: anywhere; }
.tl-console__item-explicacao, .tl-console__item-resposta { margin: 0; font: var(--rs-type-supporting); color: var(--text-secondary); }
.tl-console__item-resposta code { font: var(--rs-type-identifier); letter-spacing: .02em; font-feature-settings: "tnum" 1, "ss02" 1; color: var(--text-primary); overflow-wrap: anywhere; }
/* Motivo do cuidado: peso 600 na cor do texto, pelo mesmo motivo de .tl-console__grupo-aviso. */
.tl-console__item-cuidado { margin: 0; font: var(--rs-type-label); color: var(--text-primary); }
/*
  Etiquetas do item como selo compacto (22px, 12px/600): origem da informação, cuidado e ausência.
  "Cuidado" usa o preenchimento de alarme (comando perigoso); "não existe neste modelo" é o neutro.
*/
.tl-console__etiqueta {
  display: inline-flex; align-items: center; gap: var(--space-4); min-height: 22px; padding: 0 6px;
  border: var(--border-width-1) solid transparent; border-radius: var(--radius-sm);
  font: 600 12px/16px var(--font-ui); white-space: nowrap;
}
.tl-console__etiqueta i { font-size: var(--size-icon-sm); }
.tl-console__etiqueta--documentacao { background: var(--surface-default); color: var(--text-secondary); border-color: var(--border-default); }
.tl-console__etiqueta--conferido { background: var(--surface-default); color: var(--text-primary); border-color: var(--border-default); }
.tl-console__etiqueta--conferido i { color: var(--status-confirmed); }
.tl-console__etiqueta--cuidado { background: var(--status-alarm-bg); color: var(--status-alarm-fg); }
.tl-console__etiqueta--ausente { background: var(--surface-muted); color: var(--text-primary); }

@media (max-width: 719.98px) {
  .tl-console__passo-acoes { flex-wrap: wrap; }
  .tl-console__passo-acoes .tl-btn { flex: 1 1 100%; }
  .tl-console__grupo-acoes .tl-btn { flex: 1 1 100%; }
}

/* ---------- 12. Áreas de risco (js/componentes/areas-risco.js, js/mapa/areas-risco.js) ---------- */
/*
  Formas no mapa. Cor, espessura e transparência vêm DAQUI e vencem os atributos que o Leaflet
  escreve no SVG: trocar o tema troca as áreas sem redesenhar nada. As formas não são interativas
  (o toque é resolvido por teste geométrico no clique do mapa), então nenhuma recebe cursor.
*/
path.tl-area { stroke-width: 2px; stroke-opacity: 1; fill-opacity: .22; transition: fill-opacity var(--duration-fast) var(--ease-standard); }
path.tl-area--baixo { fill: var(--risk-low-fill); stroke: var(--risk-low-stroke); }
path.tl-area--moderado { fill: var(--risk-moderate-fill); stroke: var(--risk-moderate-stroke); }
path.tl-area--alto { fill: var(--risk-high-fill); stroke: var(--risk-high-stroke); }
path.tl-area--critico { fill: var(--risk-critical-fill); stroke: var(--risk-critical-stroke); }
/* Selecionada: contorno mais grosso e preenchimento mais denso; as outras recuam, sem sumir. */
path.tl-area--selecionada { stroke-width: 4px; fill-opacity: .34; }
.tl-mapa--com-area-selecionada path.tl-area:not(.tl-area--selecionada) { fill-opacity: .1; stroke-opacity: .45; }
/* Em edição, o contorno tracejado diz "isto está sendo mexido" sem depender da cor. */
path.tl-area--editando { stroke-dasharray: 10 6; }

/* Rascunho da área nova, na linguagem de rota (laranja sobre preto), tracejado. */
path.tl-area--rascunho { fill: var(--map-route); fill-opacity: .18; stroke: var(--map-route-casing); stroke-dasharray: 6 6; }
path.tl-area-rascunho__linha,
path.tl-area-rascunho__guia { fill: none; stroke: var(--map-route-casing); stroke-width: 2px; stroke-dasharray: 6 6; }
path.tl-area-rascunho__guia { stroke-opacity: .55; }
path.tl-area-rascunho__ponto { fill: var(--map-event-ring); fill-opacity: 1; stroke: var(--map-route-casing); stroke-width: 2px; }
path.tl-area-rascunho__ponto--fechar { fill: var(--map-route); stroke-width: 3px; }
.tl-mapa--desenhando.leaflet-grab,
.tl-mapa--desenhando .leaflet-grab { cursor: crosshair; }

/*
  Alças da edição: alvo de 44px (o ícone do marcador) com o disco visível menor, no centro. Os
  pontos médios são menores e translúcidos — acrescentar vértice é secundário a ajustar.
*/
.tl-alca { display: flex; align-items: center; justify-content: center; background: transparent; border: 0; }
.tl-alca.leaflet-marker-draggable { cursor: grab; }
.tl-alca__disco {
  width: 20px; height: 20px; border-radius: var(--radius-full);
  display: flex; align-items: center; justify-content: center;
  border: var(--border-width-2) solid var(--map-marker-border); background: var(--map-marker-bg); color: var(--text-primary);
  box-shadow: var(--shadow-overlay); transition: transform var(--duration-fast) var(--ease-standard);
}
.tl-alca--mover .tl-alca__disco,
.tl-alca--raio .tl-alca__disco { width: 32px; height: 32px; }
.tl-alca__disco i { font-size: var(--size-icon-sm); }
.tl-alca--meio .tl-alca__disco { width: 14px; height: 14px; border-width: var(--border-width-1); opacity: .85; }
.tl-alca--ativa .tl-alca__disco { background: var(--state-active); border-color: var(--border-contrast); transform: scale(1.25); }
@media (hover: hover) { .tl-alca:hover .tl-alca__disco { transform: scale(1.15); } }
/* Durante o arrasto, só a alça que está no dedo fica: as outras estão em posições que vão mudar. */
.tl-mapa--arrastando-alca .tl-alca:not(.tl-alca--arrastada) { opacity: 0; pointer-events: none; }

/* Controles: canto inferior esquerdo, livre do cartão (topo), da coluna (direita) e do menu (centro). */
.tl-areas {
  position: absolute; z-index: var(--z-map-controls); left: var(--space-24); bottom: var(--space-24);
  display: flex; flex-direction: column; gap: var(--space-8);
}
/* O "+" leva o nome do recurso: pílula de 44px de altura, ícone e texto. */
.tl-controle.tl-areas__nova { width: auto; gap: var(--space-8); padding: 0 var(--space-16); font: var(--rs-type-button); }
.tl-areas__nova i { font-size: var(--size-icon-md); }
/* Com o painel aberto, os botões dele fazem o trabalho — e ocupariam o mesmo canto. */
.tl-areas--com-painel { display: none; }

/* Painel compacto da área (e do desenho), acima da faixa do menu. */
.tl-area-painel {
  position: absolute; z-index: var(--z-panel); left: var(--space-24);
  bottom: calc(var(--tl-altura-menu) + var(--space-16));
  width: min(360px, calc(100% - var(--space-48)));
  max-height: calc(100% - var(--tl-altura-menu) - 160px); overflow-y: auto; overscroll-behavior: contain;
  padding: var(--space-12); display: flex; flex-direction: column; gap: var(--space-12);
}
.tl-area-painel__cabecalho { display: flex; align-items: center; gap: var(--space-12); }
.tl-area-painel__textos { flex: 1 1 auto; min-width: 0; }
.tl-area-painel__nome {
  margin: 0; font: var(--rs-type-card-title); color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tl-area-painel__meta { margin: 0; font: var(--rs-type-supporting); color: var(--text-secondary); }
.tl-area-painel__acoes { flex: none; display: flex; gap: var(--space-4); }
.tl-area-painel__acao {
  width: var(--size-touch); height: var(--size-touch); padding: 0; border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center;
  border: var(--border-width-1) solid transparent; background: transparent; color: var(--text-primary); cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard);
}
.tl-area-painel__acao i { font-size: var(--size-icon-md); }
.tl-area-painel__acao:hover { background: var(--state-hover); }
.tl-area-painel__acao--ligada,
.tl-area-painel__acao--ligada:hover { background: var(--state-active); color: var(--state-on-active); border-color: var(--border-contrast); }
.tl-area-painel__descricao { margin: 0; font: var(--rs-type-supporting); color: var(--text-primary); white-space: pre-wrap; overflow-wrap: anywhere; }
.tl-area-painel__edicao { display: flex; flex-direction: column; gap: var(--space-12); }
.tl-area-painel__linha { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-8); }
.tl-area-painel__linha > label { font: var(--rs-type-label); color: var(--text-primary); }
.tl-area-painel__raio { flex: 1 1 auto; }
.tl-area-painel__unidade { flex: none; font: var(--rs-type-supporting); color: var(--text-secondary); }
.tl-area-painel__dica { flex: 1 1 100%; margin: 0; font: var(--rs-type-caption); color: var(--text-secondary); }
.tl-area-painel__descricao-campo { min-height: 64px; }
.tl-area-painel__rodape { display: flex; gap: var(--space-8); }
.tl-area-painel__rodape .tl-btn { flex: 1 1 0; }

/* Amostra da classificação: o preenchimento e o contorno da própria área, em miniatura. */
.tl-area-amostra {
  flex: none; width: 16px; height: 16px; border-radius: var(--radius-full); border: var(--border-width-2) solid;
}
.tl-area-amostra--baixo { background: var(--risk-low-fill); border-color: var(--risk-low-stroke); }
.tl-area-amostra--moderado { background: var(--risk-moderate-fill); border-color: var(--risk-moderate-stroke); }
.tl-area-amostra--alto { background: var(--risk-high-fill); border-color: var(--risk-high-stroke); }
.tl-area-amostra--critico { background: var(--risk-critical-fill); border-color: var(--risk-critical-stroke); }
.tl-area-amostra--nova {
  width: 32px; height: 32px; display: flex; align-items: center; justify-content: center;
  background: var(--state-active); color: var(--state-on-active); border-color: var(--border-contrast);
}
.tl-area-amostra--nova i { font-size: var(--size-icon-sm); }

/* Classificação: quatro botões lado a lado. Ligado = contorno de 2px e o visto, não só a cor. */
.tl-area-classes { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-4); }
.tl-area-classe {
  position: relative; min-height: 52px; padding: var(--space-4);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-4);
  border: var(--border-width-1) solid var(--border-strong); border-radius: var(--radius-md);
  background: var(--surface-default); color: var(--text-primary); font: var(--rs-type-label); cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard);
}
.tl-area-classe:hover { background: var(--state-hover); }
.tl-area-classe[aria-pressed="true"] { border: var(--border-width-2) solid var(--border-contrast); padding: calc(var(--space-4) - 1px); background: var(--state-hover); }
.tl-area-classe__visto { position: absolute; top: 4px; right: 4px; font-size: 10px; display: none; }
.tl-area-classe[aria-pressed="true"] .tl-area-classe__visto { display: block; }

.tl-area-formatos { display: flex; gap: var(--space-8); }
.tl-area-formatos .tl-chip { flex: 1 1 0; justify-content: center; }

/* Estado do salvamento: ícone e texto — "Salvo" em sucesso, "Não salvo" em perigo e com ações. */
.tl-area-painel__status {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-4) var(--space-8);
  padding-top: var(--space-8); border-top: var(--border-width-1) solid var(--border-subtle);
  font: var(--rs-type-supporting); color: var(--text-secondary);
}
.tl-area-status { display: inline-flex; align-items: center; gap: var(--space-8); min-width: 0; }
.tl-area-painel__status[data-estado="salvo"] .tl-area-status i { color: var(--status-confirmed); }
.tl-area-painel__status[data-estado="erro"] .tl-area-status { color: var(--status-failed); font-weight: 600; }
.tl-area-painel__status-acoes { display: flex; flex-wrap: wrap; }

@media (max-width: 719.98px) {
  .tl-areas {
    left: var(--space-16);
    bottom: calc(env(safe-area-inset-bottom, 0px) + var(--tl-altura-menu) + var(--tl-altura-atribuicao) + var(--space-16));
  }
  /*
    Faixa de largura total logo acima da atribuição (obrigação da licença dos tiles, não pode ficar
    por baixo): o mapa continua visível entre ela e a fileira de controles, que é o teto. O zoom
    ficaria por baixo do painel e sai enquanto ele está aberto — no celular, a pinça faz o mesmo.
  */
  .tl-area-painel {
    left: var(--space-16); right: var(--space-16); width: auto;
    bottom: calc(env(safe-area-inset-bottom, 0px) + var(--tl-altura-menu) + var(--tl-altura-atribuicao) + var(--space-8));
    max-height: min(52%, calc(100% - var(--tl-base-cartao, 0px) - var(--space-8) - var(--size-touch) - var(--space-16)
            - env(safe-area-inset-bottom, 0px) - var(--tl-altura-menu) - var(--tl-altura-atribuicao) - var(--space-8)));
  }
  .tl-palco:has(> .tl-area-painel:not([hidden])) .leaflet-control-zoom { visibility: hidden; }
  /* Compacto: classificação numa linha só e descrição em uma linha, para sobrar mapa acima. */
  .tl-area-painel { gap: var(--space-8); }
  .tl-area-painel__edicao { gap: var(--space-8); }
  .tl-area-classe { flex-direction: row; min-height: var(--size-touch); gap: 6px; font: var(--rs-type-caption); font-weight: 600; }
  .tl-area-classe .tl-area-amostra { width: 12px; height: 12px; }
  .tl-area-classe__visto { display: none !important; }
  .tl-area-painel__descricao-campo { min-height: var(--size-touch); padding-block: var(--space-8); }
  .tl-area-painel__descricao-campo textarea { resize: none; }
  /* Um painel funcional por vez: com um diálogo aberto, o da área sai da frente. */
  .tl-palco:has(> .tl-scrim) .tl-area-painel { display: none; }
}

/* ---------- 13. Menu inferior no computador ---------- */
/*
  No computador o menu é uma barra flutuante, com ícone e texto LADO A LADO: empilhados, os dois
  disputavam 56px de altura e o rótulo ficava miúdo. A pílula desce para a mesma linha de base do
  controle de áreas (esquerda) e do zoom (direita), a 24px da borda, e a faixa que os vizinhos
  descontam (--tl-altura-menu) acompanha: 56 + 24.
*/
@media (min-width: 720px) {
  .tl-palco { --tl-altura-menu: 80px; }
  .tl-menu-inferior {
    bottom: var(--space-24); height: 56px;
    padding: var(--space-4); gap: var(--space-4);
    /* O raio das sobreposições (.tl-vidro) e o dos botões de dentro, como no resto do painel. */
    border-radius: var(--radius-lg);
  }
  .tl-menu-inferior__item {
    flex-direction: row; gap: var(--space-8);
    min-width: 0; padding: 0 var(--space-16) 0 var(--space-12);
    border: var(--border-width-1) solid transparent; border-radius: var(--radius-md);
    color: var(--text-primary); font: var(--rs-type-button);
  }
  .tl-menu-inferior__item i { font-size: var(--size-icon-md); width: var(--size-icon-lg); text-align: center; }

  /*
    Item aberto: preenchimento discreto e o indicador como um traço curto sob o texto, dentro da
    pílula — a barra no topo, herdada da barra de largura total do celular, ficava solta no ar.
  */
  .tl-menu-inferior__item[aria-expanded="true"],
  .tl-menu-inferior__item[aria-current="page"] { background: var(--state-hover); border-color: var(--border-default); }
  .tl-menu-inferior__item[aria-expanded="true"]::before,
  .tl-menu-inferior__item[aria-current="page"]::before {
    inset-inline: auto; top: auto; bottom: 5px; left: 50%;
    width: 20px; margin-left: -10px; height: var(--border-width-3); border-radius: 2px;
  }

  /* Bloqueado continua sendo o preenchimento inverso, sem o traço de item aberto. */
  .tl-menu-inferior__item[aria-pressed="true"]::before { display: none; }
  .tl-menu-inferior__item--pendente { border: var(--border-width-2) dashed var(--status-pending-border); }

  /*
    Sem veículo selecionado, Bloquear e Recuperar ficam indisponíveis — mas continuam LEGÍVEIS: o
    cinza de desabilitado sumia no tema escuro, e a pessoa não sabia que as ações existem.
  */
  .tl-menu-inferior__item[aria-disabled="true"] { color: var(--text-tertiary); }
  .tl-menu-inferior__item[aria-disabled="true"] i { opacity: .8; }
}
