/* Estilo do produto. Era um <style> de 600 linhas dentro do base.html — aqui o
   navegador faz cache, o diff é legível e o HTML volta a ser HTML. Tokens de
   cor e tipografia ficam no :root, no topo. */
    /* Identidade da Smartflow Transporte, a mesma do site: laranja da marca,
       azul-petróleo das letras e Open Sans. Cor daqui não se repete solta em
       template nenhum — quem quiser a cor da marca usa a variável. */
    :root{
      --bg:#f7f8f9; --surface:#ffffff; --sidebar:#313f49; --sidebar-2:#202930;
      --ink:#313f49; --muted:#515867; --line:#e7e9ec;
      /* A cor da marca vem do dlight-admin (DlightConfig do domínio, editável no admin) pelas
         variáveis que o include admin/includes/short_style_variables.html publica no base.html.
         O laranja é só o fallback; os tons derivam da cor principal, então trocar uma muda todas. */
      --primary:var(--bs-primary,#ff6c02); --primary-600:var(--bs-hover-primary,#e55f00);
      --primary-700:color-mix(in srgb,var(--primary) 82%,#000); --primary-soft:color-mix(in srgb,var(--primary) 10%,#fff);
      /* Sino de notificações do dlight-admin: as variáveis dele apontam para as nossas. */
      --dl-bell-accent:var(--primary); --dl-bell-surface:var(--surface); --dl-bell-text:var(--ink);
      --dl-bell-muted:var(--muted); --dl-bell-border:var(--line); --dl-bell-unread-bg:var(--primary-soft);
      --dl-bell-badge:var(--red); --dl-bell-radius:var(--radius-sm); --dl-bell-shadow:var(--shadow-lg);
      --green:#0f9d6b; --green-soft:#e7f6ef; --red:#e11d48; --red-soft:#fdeaef;
      --amber:#d97706; --amber-soft:#fef3e2; --slate-soft:#eef0f2;
      --radius:16px; --radius-sm:10px; --radius-pill:999px;
      --shadow:0 1px 2px rgba(49,63,73,.05),0 1px 3px rgba(49,63,73,.08);
      --shadow-lg:0 10px 30px rgba(49,63,73,.10);
    }
    /* Open Sans servida daqui, não do Google. Um domínio externo custa uma
       conexão inteira (DNS, TCP, TLS) antes do primeiro byte — numa 4G ruim,
       de 300 a 500 ms — e o CSS do Google só ficava em cache por um dia. Aqui
       o arquivo ganha o hash no nome e um ano de cache, como o resto.

       É a versão VARIÁVEL: um arquivo cobre todos os pesos de 300 a 800 (o
       sistema usa 400, 500, 600, 700 e 800), com 43 KB — contra cinco arquivos
       de um peso cada. O latin-ext só é baixado se a tela tiver algum
       caractere fora do latim básico; o português cabe inteiro no latin.
       Licença OFL, em fonts/OFL.txt. */
    @font-face{font-family:'Open Sans';font-style:normal;font-weight:300 800;font-display:swap;
      src:url("../fonts/open-sans-latin.23145c714161.woff2") format('woff2');
      unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
    @font-face{font-family:'Open Sans';font-style:normal;font-weight:300 800;font-display:swap;
      src:url("../fonts/open-sans-latin-ext.7f28d9acd0a8.woff2") format('woff2');
      unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}

    *{box-sizing:border-box}
    html,body{margin:0}
    body{font-family:'Open Sans',system-ui,sans-serif;background:var(--bg);color:var(--ink);
      font-size:14px;line-height:1.5;-webkit-font-smoothing:antialiased}
    a{color:inherit;text-decoration:none}

    /* App shell */
    .shell{display:grid;grid-template-columns:250px 1fr;min-height:100vh}
    .sidebar{background:linear-gradient(180deg,var(--sidebar),var(--sidebar-2));
      color:#cbd5e1;padding:22px 16px;position:sticky;top:0;height:100vh;display:flex;flex-direction:column;gap:6px}
    /* A marca é a marca: o logotipo do site, na versão clara, sobre o
       azul-petróleo dele mesmo. */
    .brand{display:block;padding:4px 8px 22px;text-align:center}
    .brand img{display:block;width:100%;max-width:155px;height:auto;margin:0 auto}
    .brand small{display:block;margin-top:6px;font-weight:600;color:#93a1ad;font-size:10.5px;
      letter-spacing:.06em;text-transform:uppercase}
    .nav-label{font-size:10.5px;text-transform:uppercase;letter-spacing:.08em;color:#8493a0;padding:14px 10px 6px;font-weight:700}
    .nav-item{display:flex;align-items:center;gap:11px;padding:9px 11px;border-radius:10px;color:#c3ccda;
      font-weight:500;transition:.15s}
    .nav-item:hover{background:rgba(255,255,255,.06);color:#fff}
    /* Laranja translúcido sobre o petróleo vira marrom. O ativo é um véu claro
       com a marca marcando a borda e o ícone. */
    .nav-item.active{background:rgba(255,255,255,.09);color:#fff;
      box-shadow:inset 3px 0 0 var(--primary)}
    .nav-item.active svg{color:var(--primary)}
    .nav-item svg{width:18px;height:18px;color:#8b97ab}
    /* Nav scrolls on short screens; the brand and the user card stay put. */
    .sidebar-nav{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:6px;
      scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.18) transparent}
    .sidebar-nav::-webkit-scrollbar{width:6px}
    .sidebar-nav::-webkit-scrollbar-thumb{background:rgba(255,255,255,.18);border-radius:99px}
    .sidebar .brand,.side-user{flex-shrink:0}
    .side-user{display:flex;align-items:center;gap:10px;padding:10px;border-radius:12px;background:rgba(255,255,255,.04)}
    .avatar{width:34px;height:34px;border-radius:50%;background:linear-gradient(135deg,var(--primary),#ffa15c);
      color:#fff;display:grid;place-items:center;font-weight:700;font-size:13px;flex:none}
    .side-user .who{font-size:12.5px;color:#e2e8f0;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
    .side-user .who small{display:block;color:#94a3b8;font-weight:500}

    /* Main */
    .main{display:flex;flex-direction:column;min-width:0}
    .topbar{height:64px;background:var(--surface);border-bottom:1px solid var(--line);
      display:flex;align-items:center;position:sticky;top:0;z-index:5}
    /* The bar spans the window, but its content lines up with the page below —
       same max-width and same side padding as .content. */
    .topbar-inner{display:flex;align-items:center;justify-content:space-between;gap:16px;
      width:100%;max-width:1200px;margin:0 auto;padding:0 28px}
    .topbar h1{font-size:18px;font-weight:700;margin:0;letter-spacing:-.01em}
    .topbar-brand{display:none}
    /* A logo da transportadora, quando ela sobe a dela. */
    .conta-logo{display:block;max-height:34px;max-width:190px;width:auto}
    .topbar-brand img{display:block;height:24px;width:auto}
    /* A logo da transportadora costuma ser mais "quadrada" que a nossa: cabe
       mais alta, mas limitada na largura para não empurrar o chip. */
    .topbar-brand img.marca-conta{height:auto;max-height:36px;max-width:160px;object-fit:contain}
    /* margin:0 auto — on a wide monitor the page stays centred instead of
       hugging the sidebar with dead space on the right. */
    /* container-type: a barra lateral come 250px, então o ponto de corte das
       grades tem de olhar a largura DISPONÍVEL, não a da janela — senão numa
       janela média as duas colunas ficam estreitas demais e o valor corta. */
    .content{padding:26px 28px 48px;max-width:1200px;width:100%;margin:0 auto;
      container-type:inline-size}
    .chip{display:inline-flex;align-items:center;gap:7px;background:var(--slate-soft);color:#475569;
      padding:6px 12px;border-radius:999px;font-size:12.5px;font-weight:600}

    /* Page header */
    .page-head{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:22px;flex-wrap:wrap}
    /* Action groups in the header wrap too — 5 buttons don't fit a phone. */
    .page-head .flex{flex-wrap:wrap}
    /* Secondary actions. The primary sits outside this group so the phone can
       lift it to the title line; here it just trails the group as before. */
    .page-actions{display:flex;gap:8px;flex-wrap:wrap;align-items:center;order:1}
    .page-head>.btn-primary{order:2}
    /* Pushes the actions to the far right without space-between splitting the
       secondary group away from the primary button. */
    .page-head>:first-child{margin-right:auto;min-width:0}
    .page-head .h{font-size:22px;font-weight:800;letter-spacing:-.02em;margin:0}
    .page-head .sub{color:var(--muted);margin:2px 0 0;font-size:13.5px}

    /* Cards */
    .card{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow)}
    /* Wide content (tables) scrolls inside the card instead of pushing the
       whole page sideways on a phone. */
    .card-body{padding:20px;overflow-x:auto}
    .card-title{font-size:12px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);font-weight:700;margin:0 0 14px}

    /* Stat grid */
    .stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;margin-bottom:22px}
    .stat{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:18px 20px;box-shadow:var(--shadow)}
    .stat .label{font-size:12px;color:var(--muted);font-weight:600;display:flex;align-items:center;gap:8px}
    .stat .label .ic{width:30px;height:30px;border-radius:9px;display:grid;place-items:center}
    .stat .label .ic .ic-sv{width:16px;height:16px}
    .stat .ic svg{width:16px;height:16px}
    .stat .value{font-size:26px;font-weight:800;letter-spacing:-.02em;margin-top:12px}
    /* Seis cards: o auto-fit enche quatro por linha e deixa dois soltos na
       segunda. Três por linha fecha duas linhas iguais; em tela muito larga
       cabem os seis numa só. No celular vale a regra geral (dois por linha). */
    @media(min-width:821px){.stats.seis{grid-template-columns:repeat(3,minmax(0,1fr))}}
    @media(min-width:1700px){.stats.seis{grid-template-columns:repeat(6,minmax(0,1fr))}}
    /* Com seis na linha o cartão estreita, e "R$ 268.905,03" quebrava o "R$"
       numa linha e o número em outra. O valor encolhe com o cartão (cqi = % da
       largura dele) em vez de quebrar; no cartão largo fica nos 26px de sempre. */
    .stats.seis .stat{container-type:inline-size}
    .stats.seis .stat .value{white-space:nowrap;font-size:clamp(17px,10cqi,26px)}
    /* Linhas da mesma altura: sem isto o cartão com linha de apoio embaixo do
       valor esticava a própria linha e a grade ficava com dois tamanhos. */
    .stats.seis{grid-auto-rows:1fr}
    /* Cartão que leva a algum lugar é clicável inteiro, não só um texto nele. */
    a.stat{display:block;color:inherit;text-decoration:none}
    @media(pointer:fine){
      a.stat{transition:border-color .15s ease,box-shadow .15s ease}
      a.stat:hover{border-color:var(--primary);box-shadow:var(--shadow-lg)}
    }
    a.stat:focus-visible{outline:2px solid var(--primary);outline-offset:2px}
    a.stat .seta{color:var(--primary);font-weight:600}
    /* Par do .hide-sm: o que só faz sentido no celular (ex.: o local do frete
       junto da carga, quando a coluna própria dele some). */
    .so-sm{display:none}
    /* Denser variant for secondary metric rows inside a card. */
    .stats.compact .stat{padding:12px 14px}
    .stats.compact .stat .value{font-size:17px;margin-top:5px;white-space:nowrap}
    .stats.compact .stat .label{font-size:11px}
    /* Cadastro de veículo: uma pergunta só, e a placa com cara de placa. */
    .plate-card{max-width:520px;margin:0 auto}
    .plate-card .card-body{padding:34px 30px 30px;text-align:center}
    .plate-title{margin:0 0 16px;font-size:17px;font-weight:700;letter-spacing:-.01em}
    .plate-input{width:100%;max-width:340px;margin:0 auto;display:block;
      font-size:30px;font-weight:800;letter-spacing:.16em;text-align:center;
      text-transform:uppercase;padding:16px 12px;border:2px solid var(--line);
      border-radius:14px;background:var(--bg);color:var(--ink);
      font-family:ui-monospace,"SFMono-Regular",Menlo,monospace}
    .plate-input::placeholder{color:#c3c9d4;font-weight:700;letter-spacing:.16em}
    .plate-input:focus{outline:none;border-color:var(--primary);background:var(--surface);
      box-shadow:0 0 0 4px var(--primary-soft)}
    .plate-next{list-style:none;margin:22px auto 24px;padding:0;max-width:330px;
      text-align:left;color:var(--muted);font-size:13px}
    .plate-next li{position:relative;padding:5px 0 5px 24px}
    .plate-next li::before{content:"";position:absolute;left:4px;top:11px;width:7px;
      height:7px;border-radius:50%;background:var(--primary);opacity:.55}

    /* Foto do veículo. O crédito embaixo não é enfeite: imagem do Commons é
       CC, e CC exige atribuição visível. */
    .vphoto{margin:0 0 16px}
    .vphoto img{width:100%;max-height:320px;object-fit:cover;border-radius:14px;
      display:block;background:var(--bg)}
    .vphoto figcaption{margin-top:7px;font-size:11.5px;color:var(--muted)}
    .vphoto figcaption a{color:var(--primary);font-weight:600}

    /* Ficha: rótulo em cima, valor embaixo, quantas couberem na linha. Só
       entram as linhas preenchidas — ver _registry_card. */
    .specs{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:14px 18px}
    .specs dt{font-size:11px;text-transform:uppercase;letter-spacing:.05em;
      color:var(--muted);font-weight:600;margin-bottom:2px}
    .specs dd{margin:0;font-size:14.5px;font-weight:600;overflow-wrap:anywhere}

    /* Period strip — the phone's stand-in for the bar chart. Hidden here; the
       media query turns it on. A period too short to be a series is a single
       card, and that one shows on every screen. */
    .months{display:none}
    .months.single{display:flex;max-width:320px}
    .months.single .month{flex:0 0 auto;min-width:240px}
    .month{flex:0 0 74%;scroll-snap-align:center;background:var(--bg);
      border:1px solid var(--line);border-radius:14px;padding:13px 15px}
    .month .mname{margin:0;font-size:12px;font-weight:700;color:var(--muted);
      text-transform:uppercase;letter-spacing:.06em}
    .month .mresult{margin:4px 0 10px;font-size:21px;font-weight:800;letter-spacing:-.02em}
    .month .mline{display:flex;justify-content:space-between;gap:10px;font-size:12.5px;
      padding:3px 0;color:var(--muted)}
    .month .mline strong{font-weight:700}

    .ic-green{background:var(--green-soft);color:var(--green)}
    .ic-red{background:var(--red-soft);color:var(--red)}
    .ic-primary{background:var(--primary-soft);color:var(--primary)}
    .ic-amber{background:var(--amber-soft);color:var(--amber)}
    .pos{color:var(--green)} .neg{color:var(--red)}

    .hidden{display:none!important}
    /* O [hidden] do navegador é regra de user-agent, e perde para qualquer
       display de autor — .field e .aviso são flex, então esconder por atributo
       não escondia nada. Uma linha aqui evita a armadilha em toda tela. */
    [hidden]{display:none!important}
    /* <summary> styled as a button: drop the native disclosure triangle. */
    summary.btn{list-style:none;cursor:pointer}
    summary.btn::-webkit-details-marker{display:none}
    summary.btn::marker{content:""}
    .sim-wrap{max-width:860px;margin:0 auto}
    .sim-head{text-align:center;margin:4px 0 22px}
    /* Centered single-column page (forms, wizards). */
    .wrap-form{max-width:780px;margin:0 auto}
    .wrap-form .page-head{justify-content:center;text-align:center}

    /* File dropzone (comprovantes) */
    .dz{position:relative;border:2px dashed var(--line);border-radius:12px;background:#fafbfc;transition:border-color .15s,background .15s}
    .dz.drag{border-color:var(--primary);background:#eef2ff}
    .dz.has-file{border-style:solid;border-color:var(--primary);background:#f5f7ff}
    .dz-input{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer}
    .dz-body{display:flex;flex-direction:column;align-items:center;gap:7px;padding:22px 16px;color:var(--muted);text-align:center;pointer-events:none}
    .dz.has-file .dz-body{color:var(--ink)}
    .dz-body svg{width:26px;height:26px;stroke:currentColor}
    .dz-hint b{color:var(--primary)}
    .dz-file{display:none;font-weight:600;font-size:13px;word-break:break-all}
    .dz.has-file .dz-file{display:block} .dz.has-file .dz-hint{display:none}
    .dz-thumb{max-height:120px;border-radius:8px;display:none}
    .dz.has-file .dz-thumb.on{display:block}

    /* Table */
    .table-card{overflow-x:auto}
    table.tbl{width:100%;border-collapse:collapse}
    table.tbl th{font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);
      font-weight:700;text-align:left;padding:13px 18px;background:#fbfcfe;border-bottom:1px solid var(--line)}
    table.tbl td{padding:14px 18px;border-bottom:1px solid var(--line);vertical-align:middle}
    table.tbl tbody tr:last-child td{border-bottom:0}
    table.tbl tbody tr:hover{background:#fafbff}
    .t-right{text-align:right} .t-mono{font-variant-numeric:tabular-nums}
    .empty{color:var(--muted);text-align:center;padding:30px}

    /* Badges */
    .badge{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:999px;
      font-size:12px;font-weight:600;line-height:1}
    .badge.green{background:var(--green-soft);color:var(--green)}
    .badge.red{background:var(--red-soft);color:var(--red)}
    .badge.amber{background:var(--amber-soft);color:var(--amber)}
    .badge.slate{background:var(--slate-soft);color:#475569}
    .badge.primary{background:var(--primary-soft);color:var(--primary)}
    .badge .dot{width:6px;height:6px;border-radius:50%;background:currentColor}

    /* Buttons — arredondados como os do site da marca. */
    .btn{display:inline-flex;align-items:center;gap:8px;border:1px solid transparent;border-radius:var(--radius-pill);
      padding:9px 17px;font-weight:600;font-size:13.5px;cursor:pointer;transition:.15s;font-family:inherit}
    .btn svg{width:16px;height:16px}
    .btn-primary{background:var(--primary);border-color:var(--primary);color:#fff}
    .btn-primary:hover{background:var(--primary-600);border-color:var(--primary-600)}
    /* O escuro do site é o segundo botão da marca; aqui ele é o secundário. */
    .btn-ghost{background:var(--surface);border-color:var(--line);color:var(--ink)}
    .btn-ghost:hover{background:var(--slate-soft);border-color:#d5dade}
    /* Não existe botão verde. Em botão, a cor diz hierarquia — qual é a ação
       principal —, não sentimento: "Confirmar pagamento" verde numa tela e
       "Salvar frete" laranja na outra fazem a mesma ação parecer duas coisas.
       Verde e vermelho continuam nos valores e nos selos, onde a cor informa. */
    .btn-danger{background:var(--surface);border-color:var(--red-soft);color:var(--red)}
    .btn-danger:hover{background:var(--red-soft)}
    .btn-sm{padding:7px 14px;font-size:12.5px}

    /* Resposta ao toque. O dedo não tem hover: sem um estado de pressionado, o
       botão fica idêntico antes e depois do toque e a pessoa toca de novo,
       achando que não pegou. O reflexo do navegador (tap highlight) é o único
       retorno que existia, e cada um pinta de um jeito — aqui ele é escolhido. */
    .btn,.row-link,summary.btn,.tab-btn,.seg-opt,.nav-item{-webkit-tap-highlight-color:rgba(255,108,2,.18)}
    .btn:active{transform:translateY(1px)}
    .btn-primary:active{background:var(--primary-700);border-color:var(--primary-700)}
    .btn-ghost:active{background:#e2e6ea;border-color:#c8cfd6}
    .btn-danger:active{background:#fbd5de}
    /* A linha inteira que navega também responde ao toque. */
    tr.row-link:active{background:var(--primary-soft)}

    /* Ocupado: o clique foi recebido e a resposta está a caminho. O rótulo
       fica — "Aprovar" com ampulheta continua dizendo o que está acontecendo,
       "Salvando…" em cima de "Filtrar" mentiria. O giro ocupa o lugar do ícone
       quando existe um, para o botão não mudar de largura no meio do caminho. */
    .btn[aria-busy="true"]{pointer-events:none;opacity:.72;transition:none}
    .btn[aria-busy="true"] .btn-giro{animation:btn-giro .7s linear infinite;transform-origin:center}
    @keyframes btn-giro{to{transform:rotate(360deg)}}
    @media(prefers-reduced-motion:reduce){
      .btn[aria-busy="true"] .btn-giro{animation-duration:2.4s}
      .btn:active{transform:none}
    }

    /* Enquanto a próxima página não chega, o conteúdo recua E para de aceitar
       toque: continuar clicável convida a pessoa a tocar em outra coisa no meio
       do caminho, e o que ela tocou vira uma segunda viagem que atropela a
       primeira. Rolar continua valendo — ler enquanto espera não faz mal.

       O atraso de .08s é curto de propósito: quem espera precisa ver o aviso
       quase junto com o toque. Curto demais a ponto de piscar, não: numa tela
       que responde em 50ms nada chega a aparecer.

       O que fica de fora, e fica de propósito: a barra de baixo, o topo e o
       menu lateral. São a saída de quem se arrependeu ou caiu numa tela lenta —
       bloquear tudo transformaria a espera numa porta trancada. */
    body.navegando .content,body.navegando .auth-card{opacity:.4;pointer-events:none;transition:none}
    /* O atraso e a suavidade só existem no computador. No celular o Safari
       congela transições ao começar a navegar: com atraso, o escurecimento
       nunca chegaria a acontecer. */
    @media(pointer:fine){
      body.navegando .content,body.navegando .auth-card{transition:opacity .12s ease .08s}
    }
    body.navegando{cursor:progress}

    /* Barra de carregamento do topo. É o retorno de quem não tem botão para
       acender: a linha da tabela que navega e o filtro que recarrega sozinho. */
    .carregando{position:fixed;top:0;left:0;height:4px;width:0;z-index:200;
      background:linear-gradient(90deg,var(--primary),#ff9a4d);
      box-shadow:0 0 12px rgba(255,108,2,.75);
      transition:width .25s ease,opacity .2s ease;pointer-events:none}
    @media(prefers-reduced-motion:reduce){.carregando{transition:opacity .2s ease}}

    /* Giro no meio da tela. A barra do topo sozinha é discreta demais no
       celular: ela fica longe de onde o olho está, que é onde o dedo tocou.
       Só aparece depois de .15s — numa tela rápida ninguém chega a vê-lo. */
    .carregando-giro{position:fixed;z-index:201;left:50%;top:50%;width:52px;height:52px;
      margin:-26px 0 0 -26px;border-radius:50%;background:var(--surface);
      box-shadow:var(--shadow-lg);display:grid;place-items:center;pointer-events:none}
    /* Idem: a chegada suave, com atraso, é só para o ponteiro fino. No dedo o
       giro já nasce visível — parado, se o Safari congelar a animação, mas
       visível. */
    @media(pointer:fine){
      .carregando-giro{opacity:0;animation:carregando-surgir .18s ease .15s forwards}
    }
    /* A classe define display:grid e venceria o display:none que o navegador
       dá a [hidden] — sem esta linha o giro nunca sumiria. */
    .carregando-giro[hidden]{display:none}
    .carregando-giro svg{width:24px;height:24px;color:var(--primary);
      animation:btn-giro .7s linear infinite;transform-origin:center}
    @keyframes carregando-surgir{to{opacity:1}}
    @media(prefers-reduced-motion:reduce){
      .carregando-giro svg{animation-duration:2.4s}
    }

    /* Ícone de traço. Tamanho segue a fonte do contexto; cor, a do texto. */
    .ic-sv{width:1em;height:1em;fill:none;stroke:currentColor;stroke-width:2;
      stroke-linecap:round;stroke-linejoin:round;flex:none;vertical-align:-.125em}
    /* O bloco de símbolos não desenha nada: só guarda as formas. */
    .ic-defs{position:absolute;width:0;height:0}

    /* Cobrança: selo permanente no topo e faixa por urgência (E23). */
    .selo-ass{display:inline-flex;align-items:center;gap:7px;border-radius:var(--radius-pill);
      padding:5px 12px;font-size:12px;font-weight:700;border:1px solid transparent;white-space:nowrap}
    .selo-ass svg{width:13px;height:13px}
    .selo-nenhuma{background:var(--slate-soft);color:#475569}
    .selo-suave{background:var(--primary-soft);color:var(--primary);border-color:#ffd9b8}
    .selo-alta{background:var(--amber-soft);color:var(--amber);border-color:#f6ddb4}
    .selo-critica{background:var(--red-soft);color:var(--red);border-color:#f6cdd7}

    .faixa-ass{display:flex;align-items:center;gap:14px;padding:13px 16px;margin-bottom:16px;
      border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--surface)}
    .faixa-ico{flex:none;width:34px;height:34px;border-radius:10px;display:grid;place-items:center}
    .faixa-ico svg{width:18px;height:18px}
    .faixa-txt{flex:1;font-size:13.5px;line-height:1.55;color:var(--muted)}
    .faixa-txt strong{display:block;color:var(--ink);font-size:14px;font-weight:700}
    .faixa-acoes{flex:none;display:flex;align-items:center;gap:8px}
    .faixa-x{background:none;border:0;cursor:pointer;color:var(--muted);padding:6px;line-height:0;border-radius:8px}
    .faixa-x:hover{background:var(--slate-soft);color:var(--ink)}
    .faixa-x svg{width:15px;height:15px}
    .faixa-suave{border-color:#ffd9b8;background:#fffaf5}
    .faixa-suave .faixa-ico{background:var(--primary-soft);color:var(--primary)}
    .faixa-alta{border-color:#f6ddb4;background:var(--amber-soft)}
    .faixa-alta .faixa-ico{background:#fff;color:var(--amber)}
    .faixa-critica{border-color:#f6cdd7;background:var(--red-soft)}
    .faixa-critica .faixa-ico{background:#fff;color:var(--red)}
    /* Bolinha no menu: a Assinatura pede atenção sem gritar. */
    .nav-ponto{width:7px;height:7px;border-radius:50%;background:var(--primary);margin-left:auto;flex:none}
    @media(max-width:760px){
      .faixa-ass{flex-wrap:wrap}
      .faixa-txt{flex:1 1 100%;order:2}
      .faixa-acoes{order:3;margin-left:auto}
    }

    /* Forms */
    .form-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
    .field{display:flex;flex-direction:column;gap:6px}
    .field.full{grid-column:1/-1}
    .field label{font-size:12.5px;font-weight:600;color:#334155}
    .field input,.field select,.field textarea{width:100%;padding:10px 12px;border:1px solid var(--line);
      border-radius:var(--radius-sm);font-family:inherit;font-size:14px;background:#fff;transition:.15s}
    .field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--primary);
      box-shadow:0 0 0 3px var(--primary-soft)}
    .field input[type=checkbox]{width:18px;height:18px;accent-color:var(--primary)}
    .field .err{color:var(--red);font-size:12px}
    .field .hint{color:var(--muted);font-size:12px}
    .field label .opt{color:var(--muted);font-weight:500}
    .field label.check{display:flex;align-items:center;gap:8px;font-weight:500;cursor:pointer}
    .field label.check input{width:auto;margin:0}

    /* Segmented control — duas escolhas que mudam o resto do formulário. */
    .seg{display:inline-flex;align-self:flex-start;background:var(--slate-soft);
      border-radius:var(--radius-sm);padding:3px;gap:3px}
    .seg-opt{display:inline-flex;align-items:center;gap:7px;padding:7px 14px;border-radius:8px;
      font-size:13.5px;font-weight:600;color:#475569;cursor:pointer;transition:.15s}
    .seg-opt input{position:absolute;opacity:0;width:0;height:0}
    .seg-opt.on{background:var(--surface);color:var(--primary);box-shadow:var(--shadow)}

    /* Campo de lugar: o texto continua sendo texto, o mapa é um atalho. */
    .place{position:relative;display:flex;gap:8px;align-items:center}
    .place input{flex:1;min-width:0}
    .place-btn{display:grid;place-items:center;width:40px;height:40px;flex:none;
      border:1px solid var(--line);border-radius:var(--radius-sm);background:#fff;
      color:var(--muted);cursor:pointer;transition:.15s}
    .place-btn:hover{border-color:var(--primary);color:var(--primary)}
    .place-btn.on{border-color:var(--primary);color:var(--primary);background:var(--primary-soft)}
    .place-btn svg{width:18px;height:18px}
    .modal-card.wide{max-width:760px}
    .map-search{display:flex;gap:8px;margin-bottom:10px}
    .map-search input{flex:1;padding:10px 12px;border:1px solid var(--line);
      border-radius:var(--radius-sm);font-family:inherit;font-size:14px}
    .map-hits{max-height:150px;overflow-y:auto;border:1px solid var(--line);
      border-radius:var(--radius-sm);margin-bottom:10px}
    .map-hits:empty{display:none}
    .map-hit{display:block;width:100%;padding:9px 12px;border:none;background:none;
      font-family:inherit;font-size:13px;text-align:left;color:var(--ink);cursor:pointer}
    .map-hit:hover{background:var(--primary-soft);color:var(--primary)}
    .map-canvas{height:340px;border-radius:var(--radius-sm);border:1px solid var(--line);
      z-index:0;background:var(--slate-soft)}
    .map-picked{font-size:13px;color:var(--muted);margin-top:10px;min-height:20px}
    .map-box{height:420px;border-radius:12px}

    /* Linha de tabela que leva a algum lugar. O link continua dentro dela —
       isto só aumenta a área de clique. */
    tr.row-link{cursor:pointer}
    tr.row-link:hover{background:var(--primary-soft)}

    /* Abas — uma tela com muitos assuntos. Sem JS os painéis ficam todos
       visíveis, um embaixo do outro, que é como a tela era antes. */
    .tabs{display:none;gap:4px;margin-bottom:20px;padding:4px;background:var(--slate-soft);
      border-radius:var(--radius-sm);overflow-x:auto;scrollbar-width:none}
    .tabs::-webkit-scrollbar{display:none}
    .tabbed .tabs{display:flex}
    .tab-btn{display:inline-flex;align-items:center;gap:7px;flex:none;padding:8px 14px;
      border:none;border-radius:8px;background:none;font-family:inherit;font-size:13.5px;
      font-weight:600;color:#475569;cursor:pointer;white-space:nowrap;transition:.15s}
    .tab-btn:hover{color:var(--ink)}
    .tab-btn.on{background:var(--surface);color:var(--primary);box-shadow:var(--shadow)}
    .tab-n{display:inline-grid;place-items:center;min-width:19px;height:19px;padding:0 5px;
      border-radius:999px;background:#dfe4ee;color:#475569;font-size:11px;font-weight:700}
    .tab-btn.on .tab-n{background:var(--primary-soft);color:var(--primary)}
    .tabbed .tab-panel{display:none}
    .tabbed .tab-panel.on{display:block}

    /* Fatos: rótulo e valor. No monitor cabem lado a lado; no celular o valor
       vira linha própria — endereço de fazenda não cabe na metade de 390px. */
    .facts{margin:0}
    .fact{display:flex;align-items:baseline;justify-content:space-between;gap:18px;
      padding:9px 0;border-bottom:1px solid var(--line)}
    .fact:last-child{border-bottom:0;padding-bottom:0}
    .fact dt{color:var(--muted);flex:none}
    .fact dd{margin:0;text-align:right;min-width:0}
    .fact.total{font-weight:700;border-top:1px solid var(--line);border-bottom:0;margin-top:2px}

    /* Resumo da viagem — o que se sabe antes de fechar o frete. */
    .trip{margin-top:22px;padding:16px 18px;border-radius:var(--radius);
      background:linear-gradient(180deg,#f8f9ff,#f3f4fb);border:1px solid #e6e8f7}
    .trip-title{margin:0 0 14px;font-size:12px;text-transform:uppercase;
      letter-spacing:.06em;color:var(--muted);font-weight:700}
    .trip-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:14px}
    .trip-cell{display:flex;flex-direction:column;gap:2px;min-width:0}
    .trip-cell .k{font-size:12px;color:var(--muted);font-weight:600}
    .trip-cell .v{font-size:19px;font-weight:800;letter-spacing:-.02em}
    .trip-cell .s{font-size:11.5px;color:var(--muted)}
    .trip-note{margin:14px 0 0;font-size:12px;color:var(--muted)}

    /* Combo — busca dentro de um <select> longo, e cadastro no lugar quando o
       que se procura ainda não existe. O <select> real continua ali, escondido:
       é ele que o formulário envia. */
    .combo{position:relative}
    .combo select{position:absolute;opacity:0;pointer-events:none;width:1px;height:1px}
    .combo-trigger{display:flex;align-items:center;justify-content:space-between;gap:8px;
      width:100%;padding:10px 12px;border:1px solid var(--line);border-radius:var(--radius-sm);
      background:#fff;font-family:inherit;font-size:14px;color:var(--ink);cursor:pointer;
      text-align:left;transition:.15s}
    .combo-trigger:hover{border-color:#cbd5e1}
    .combo.open .combo-trigger{border-color:var(--primary);box-shadow:0 0 0 3px var(--primary-soft)}
    .combo-trigger.empty{color:var(--muted)}
    .combo-trigger svg{width:16px;height:16px;color:var(--muted);flex:none}
    .combo-pop{display:none;position:absolute;z-index:40;top:calc(100% + 4px);left:0;right:0;
      background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-sm);
      box-shadow:0 12px 28px rgba(15,23,42,.14);overflow:hidden}
    .combo.open .combo-pop{display:block}
    .combo-search{width:100%;border:none!important;border-bottom:1px solid var(--line)!important;
      border-radius:0!important;padding:10px 12px!important;font-size:13.5px}
    .combo-search:focus{outline:none;box-shadow:none!important}
    .combo-list{max-height:230px;overflow-y:auto}
    .combo-opt{display:block;width:100%;padding:9px 12px;border:none;background:none;
      font-family:inherit;font-size:13.5px;color:var(--ink);text-align:left;cursor:pointer}
    .combo-opt:hover,.combo-opt.on{background:var(--primary-soft);color:var(--primary)}
    .combo-opt.sel{font-weight:700}
    .combo-empty{padding:12px;font-size:13px;color:var(--muted)}
    .combo-add{display:flex;align-items:center;gap:7px;width:100%;padding:10px 12px;
      border:none;border-top:1px solid var(--line);background:#fff;font-family:inherit;
      font-size:13.5px;font-weight:600;color:var(--primary);cursor:pointer;text-align:left}
    .combo-add:hover{background:var(--primary-soft)}
    .combo-add svg{width:15px;height:15px;flex:none}

    /* Modal — cadastro rápido sem sair da tela. */
    .modal{position:fixed;inset:0;z-index:60;display:grid;place-items:center;padding:18px;
      background:rgba(15,23,42,.45)}
    .modal-card{background:var(--surface);border-radius:var(--radius);box-shadow:0 24px 60px rgba(15,23,42,.28);
      width:100%;max-width:420px;padding:20px;max-height:90vh;overflow-y:auto}
    .modal-title{font-size:16px;font-weight:700;margin-bottom:2px}
    .modal-sub{font-size:12.5px;color:var(--muted);margin-bottom:16px}
    .modal-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:18px}

    /* Campo de dinheiro: o R$ mora dentro do campo e os milhares se separam
       enquanto se digita — 100000 e 1000000 são indistinguíveis de relance. */
    .money{position:relative;display:flex;align-items:center}
    .money-prefix{position:absolute;left:12px;color:var(--muted);font-weight:600;
      pointer-events:none;font-size:14px}
    .money input{padding-left:38px!important;font-variant-numeric:tabular-nums}

    /* Ações de formulário — sempre no mesmo lugar e na mesma ordem: sair à
       esquerda, confirmar à direita. Antes cada tela escolhia a sua. */
    .form-actions{display:flex;gap:10px;margin-top:22px;flex-wrap:wrap;
      justify-content:flex-end;align-items:center;
      /* Gruda no rodapé da janela enquanto o formulário passa da dobra e
         assenta sozinha no fim quando ele acaba: formulário que cabe na tela
         não ganha barra flutuante, porque não precisa. */
      position:sticky;bottom:14px;z-index:6;padding:12px 14px;
      border:1px solid transparent;border-radius:var(--radius-sm);transition:.18s}
    /* Cara de barra flutuante só enquanto ela está flutuando de verdade —
       parada no fim do formulário, ela é só o fim do formulário. */
    .form-actions.is-stuck{background:var(--surface);border-color:var(--line);
      box-shadow:0 8px 22px rgba(49,63,73,.10)}
    /* Sticky não funciona dentro de caixa que rola, e o corpo do cartão rola
       de lado por causa das tabelas. Formulário não tem tabela para rolar. */
    .card-body:has(.form-actions){overflow:visible}
    /* Um "voltar" ou aviso que precise ficar do outro lado. */
    .form-actions .far-left{margin-right:auto}

    /* Filter bar — search takes the free space, selects sit on the right,
       active filters show as removable chips below. */
    .filters{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
      box-shadow:var(--shadow);padding:14px 16px;margin-bottom:20px}
    .filters-row{display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap}
    .filters .search{flex:1 1 240px;min-width:200px}
    .filters .search .box{position:relative;display:flex;align-items:center}
    .filters .search svg{position:absolute;left:12px;width:16px;height:16px;color:var(--muted);pointer-events:none}
    .filters .search input{padding-left:36px}
    .filters .f{flex:0 1 175px;min-width:140px}
    .filters label{display:block;font-size:11px;text-transform:uppercase;letter-spacing:.05em;
      color:var(--muted);font-weight:700;margin-bottom:5px}
    .filters input,.filters select{width:100%;padding:9px 12px;border:1px solid var(--line);
      border-radius:var(--radius-sm);font-family:inherit;font-size:13.5px;background:#fff;
      color:var(--ink);transition:.15s;height:38px}
    .filters select{appearance:none;-webkit-appearance:none;padding-right:32px;cursor:pointer;
      background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
      background-repeat:no-repeat;background-position:right 10px center;background-size:15px}
    .filters input:focus,.filters select:focus{outline:none;border-color:var(--primary);
      box-shadow:0 0 0 3px var(--primary-soft)}
    .filters-active{display:flex;gap:8px;align-items:center;flex-wrap:wrap;
      margin-top:12px;padding-top:12px;border-top:1px solid var(--line)}
    .fchip{display:inline-flex;align-items:center;gap:6px;background:var(--primary-soft);
      color:var(--primary);padding:4px 6px 4px 11px;border-radius:999px;font-size:12.5px;font-weight:600}
    .fchip a{display:grid;place-items:center;width:18px;height:18px;border-radius:50%;
      color:var(--primary);opacity:.65;font-size:13px;line-height:1}
    .fchip a:hover{opacity:1;background:rgba(79,70,229,.14)}
    .filters-count{margin-left:auto;color:var(--muted);font-size:12.5px;font-weight:600}
    /* The "Filtros" header only exists on a phone — see the media query. */
    .filters-toggle{display:none}
    .fbadge{display:grid;place-items:center;min-width:19px;height:19px;padding:0 5px;
      border-radius:999px;background:var(--primary);color:#fff;font-size:11px;font-weight:700}

    /* Progress */
    .wear{height:9px;border-radius:999px;background:#eef1f6;overflow:hidden;min-width:130px}
    .wear > span{display:block;height:100%;border-radius:999px;background:var(--primary)}
    .wear.hot > span{background:var(--red)}

    .alert{padding:12px 16px;border-radius:var(--radius-sm);font-weight:500;margin-bottom:16px;border:1px solid transparent}
    .alert.success{background:var(--green-soft);color:#0b7350;border-color:#c7ebda}
    .alert.error,.alert.danger{background:var(--red-soft);color:#b3123c;border-color:#f6cdd7}
    .alert.info{background:var(--primary-soft);color:#3730a3;border-color:#dcdcfb}
    .alert.warning{background:var(--amber-soft);border-color:var(--amber)}

    .grid-2{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:20px}
    /* Main list + a narrow context panel beside it. */
    .grid-wide{display:grid;grid-template-columns:minmax(0,1.75fr) minmax(0,1fr);gap:20px}
    /* Duas colunas só quando cabem de verdade. Abaixo disso, uma embaixo da
       outra lê melhor que duas espremidas. */
    @container (max-width: 900px){
      .grid-wide,.grid-2{grid-template-columns:minmax(0,1fr)}
    }
    .flex{display:flex} .between{justify-content:space-between} .items-center{align-items:center}
    .gap{gap:10px} .mt{margin-top:22px} .mb{margin-bottom:16px}
    h2.sec{font-size:15px;font-weight:700;margin:26px 0 12px;letter-spacing:-.01em}

    /* Phone chrome: an app-style tab bar at the bottom, and the full menu as
       a drawer behind it. Hidden on desktop, where the sidebar does the job. */
    .tabbar,.scrim{display:none}

    @media(max-width:820px){
      /* Área de toque: no dedo, 30px de altura é um alvo que se erra. O mínimo
         de 44px é o que o botão precisa ter para ser acertado de primeira. */
      .btn{min-height:44px}
      .btn-sm{padding:10px 16px;min-height:44px}
      .shell{grid-template-columns:minmax(0,1fr)}
      /* height:auto, e não os 100vh do computador: no iPhone, 100vh inclui a
         faixa atrás da barra do navegador, e o bloco "Minha conta · Sair", que
         fica no pé da gaveta, caía justamente ali — presente, e invisível.
         Com top e bottom fixos, a altura é a da tela que a pessoa vê. */
      .sidebar{position:fixed;top:0;left:0;bottom:0;height:auto;padding-bottom:calc(16px + env(safe-area-inset-bottom));
        width:272px;max-width:86vw;z-index:60;
        transform:translateX(-100%);transition:transform .22s ease;will-change:transform}
      body.nav-open{overflow:hidden}
      body.nav-open .sidebar{transform:none;box-shadow:0 24px 70px rgba(2,6,23,.55)}
      .scrim{display:block;position:fixed;inset:0;z-index:55;background:rgba(2,6,23,.55);
        opacity:0;pointer-events:none;transition:opacity .22s ease}
      body.nav-open .scrim{opacity:1;pointer-events:auto}

      .tabbar{display:flex;gap:2px;padding:6px;position:fixed;z-index:50;
        left:12px;right:12px;bottom:calc(12px + env(safe-area-inset-bottom));
        background:var(--surface);border:1px solid var(--line);border-radius:19px;
        box-shadow:0 14px 34px rgba(15,23,42,.20);
        transition:transform .26s ease,opacity .2s ease;will-change:transform}
      /* Rolando a lista para baixo a barra sai de cena (app.js); volta ao subir. */
      .tabbar.oculta{transform:translateY(calc(100% + 24px + env(safe-area-inset-bottom)));opacity:0;pointer-events:none}
      .tab{flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;gap:3px;
        padding:8px 2px;border:0;border-radius:14px;background:none;cursor:pointer;
        font:600 10.5px/1.2 inherit;font-family:inherit;color:var(--muted)}
      /* Sem transição no dedo: a aba precisa acender no mesmo quadro do toque,
         antes de o Safari congelar a página para navegar. */
      @media(pointer:fine){.tab{transition:color .15s ease,background-color .15s ease}}
      .tab svg{width:20px;height:20px}
      .tab span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
      .tab.active{color:var(--primary);background:var(--primary-soft)}
      /* Filters: search takes the row, selects pair up two by two — a select
         at its desktop width leaves half the phone empty next to it. */
      /* Four cards of one number each, one under the other, is a whole screen
         of scrolling to read four numbers. Two by two, compact. */
      .stats{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-bottom:16px}
      .stat{padding:12px 13px}
      .stat .label{font-size:11px;gap:6px}
      .stat .label .ic{width:24px;height:24px;border-radius:7px}
      .stat .label .ic .ic-sv{width:14px;height:14px}
      .stat .ic svg{width:13px;height:13px}
      .stat .value{font-size:17px;margin-top:7px}
      .stat .sub{font-size:11px}
      /* The yearly bar chart gives up on a phone; months swipe by instead. */
      #resultChart{display:none}
      /* The side padding is what lets the first and last cards reach the
         middle. The card fills the content box, so its width is whatever the
         padding leaves — and that same padding is exactly the gap a centred
         card needs on each side. Any other basis lands them off-centre. */
      .months{display:flex;gap:11px;overflow-x:auto;scroll-snap-type:x mandatory;
        scrollbar-width:none;padding:2px 13% 4px}
      .months .month{flex:0 0 100%}
      .months.single{padding:2px 0 4px;max-width:none}
      .months.single .month{flex:1 1 auto;min-width:0}
      .months::-webkit-scrollbar{display:none}

      /* The action you came to do rides the title line instead of pushing the
         list down; the secondary ones become a single swipe strip below. */
      .page-head{gap:10px;margin-bottom:18px}
      .page-head:has(>.btn-primary){display:grid;grid-template-columns:minmax(0,1fr) auto;
        align-items:start;column-gap:10px;row-gap:10px}
      .page-head>:first-child{grid-column:1;grid-row:1;margin-right:0}
      .page-head>.btn-primary{grid-column:2;grid-row:1;white-space:nowrap}
      .page-actions{grid-column:1/-1;flex-wrap:nowrap;overflow-x:auto;
        scrollbar-width:none;padding-bottom:1px}
      .page-actions::-webkit-scrollbar{display:none}
      .page-actions>*{flex:none}

      /* The controls fold away behind "Filtros" — on a phone they cost half
         the screen before you see a single row. What stays is what's actually
         filtering right now (the chips) and how much it left. */
      .filters{padding:10px 13px}
      .filters-toggle{display:flex;align-items:center;gap:9px;width:100%;padding:5px 0;
        background:none;border:0;cursor:pointer;color:var(--text);
        font-family:inherit;font-size:13.5px;font-weight:700}
      .filters-toggle>svg{width:17px;height:17px;color:var(--muted)}
      .filters-toggle .chev{margin-left:auto;transition:transform .18s ease}
      .filters.open .filters-toggle .chev{transform:rotate(180deg)}
      .filters-row{display:none}
      .filters.open .filters-row{display:flex;padding-top:12px}
      /* Closed, the chips sit right under the header — no rule to divide. */
      .filters:not(.open) .filters-active{margin-top:7px;padding-top:0;border-top:0}
      .filters-active:empty{display:none}
      .filters .search{flex:1 1 100%}
      .filters .f{flex:1 1 calc(50% - 6px);min-width:0}
      /* A marca troca de lugar com o título — e o chip da conta fica onde
         está, que é onde vai entrar a marca da transportadora um dia. */
      .topbar-brand{display:block}
      .topbar h1{display:none}
      .topbar-inner{padding:0 18px}
      /* Nome da transportadora + selo do teste + sino não cabem em 390px: o
         nome encolhe com reticências (o completo fica no title) em vez de
         empurrar a página para o lado. */
      .topbar-inner>.flex{min-width:0}
      .topbar .chip{min-width:0;flex-shrink:1}
      .topbar .chip svg{flex-shrink:0}
      .topbar .chip-txt{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
      .content{padding:18px 18px 92px}
      /* minmax(0,…): a plain 1fr is min-width:auto, so a wide table stretches
         the column instead of scrolling inside it. */
      .form-grid,.grid-2,.grid-wide{grid-template-columns:minmax(0,1fr)}
      /* Sete abas enroladas em três linhas viravam um bloco cinza no alto da
         tela. Numa faixa só, que rola de lado: a aba ativa vem para o meio
         sozinha (app.js), a última aba visível aparece cortada e a borda
         esmaece — os dois dizem "tem mais aqui" sem esconder o que existe. */
      .tabs{flex-wrap:nowrap;overflow-x:auto;padding:4px;scroll-snap-type:x proximity;
        scroll-padding:0 24px;-webkit-overflow-scrolling:touch}
      .tab-btn{padding:9px 13px;font-size:13px;scroll-snap-align:start}
      .tabs.tem-mais{-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 36px),transparent);
        mask-image:linear-gradient(to right,#000 calc(100% - 36px),transparent)}
      .tabs.tem-antes{-webkit-mask-image:linear-gradient(to right,transparent,#000 36px);
        mask-image:linear-gradient(to right,transparent,#000 36px)}
      .tabs.tem-antes.tem-mais{-webkit-mask-image:linear-gradient(to right,transparent,#000 36px,#000 calc(100% - 36px),transparent);
        mask-image:linear-gradient(to right,transparent,#000 36px,#000 calc(100% - 36px),transparent)}

      /* Valor curto continua na mesma linha do rótulo — empilhar "35" embaixo
         de "Toneladas" só faria a tela crescer. Quem empilha é o valor longo:
         lado a lado, um endereço de fazenda vira três linhas espremidas. */
      .fact.long{flex-direction:column;gap:1px;padding:10px 0}
      .fact.long dt{font-size:12px;font-weight:600}
      .fact.long dd{text-align:left;width:100%}

      /* Tabela de verdade não cabe em 390px. Cada linha vira um bloco com o
         nome da coluna do lado do valor — rolar de lado para ler um valor é
         pior que ler uma linha por vez. */
      table.tbl.stack thead{display:none}
      table.tbl.stack,table.tbl.stack tbody,table.tbl.stack tr,table.tbl.stack td{display:block}
      table.tbl.stack tr{padding:10px 2px;border-bottom:1px solid var(--line)}
      table.tbl.stack tr:last-child{border-bottom:0}
      table.tbl.stack td{display:flex;align-items:baseline;justify-content:space-between;
        gap:14px;padding:3px 0;border:0;text-align:left}
      table.tbl.stack td::before{content:attr(data-l);color:var(--muted);font-size:12px;
        font-weight:600;flex:none}
      table.tbl.stack td:empty{display:none}
      table.tbl.stack td.t-right{text-align:right}
      /* Célula que só existia para alinhar o rótulo do total na largura toda:
         empilhado, o rótulo já vem do data-l da própria linha. */
      table.tbl.stack td.hide-sm{display:none}

      /* Próximas parcelas de um plano: cinco colunas (número, vencimento,
         situação, valor e o botão de pagar) não cabem na largura do telefone.
         Em tabela, o valor quebrava em duas linhas e o "Pagar" saía pela borda
         do cartão. Viram duas linhas: o que vence e quanto em cima, a situação
         e a ação embaixo. */
      table.tbl.parcelas thead{display:none}
      table.tbl.parcelas,table.tbl.parcelas tbody{display:block}
      table.tbl.parcelas tr{display:grid;grid-template-columns:max-content minmax(0,1fr) max-content;
        column-gap:10px;row-gap:8px;align-items:center;padding:12px 2px;border-bottom:1px solid var(--line)}
      table.tbl.parcelas tr:last-child{border-bottom:0}
      table.tbl.parcelas td{display:block;padding:0;border:0;text-align:left}
      table.tbl.parcelas td.c-num{grid-column:1;grid-row:1;color:var(--muted);font-size:13px}
      /* O "#" some do cabeçalho junto com ele: sem esta marca, o número ficaria
         solto ao lado da data, parecendo parte dela. */
      table.tbl.parcelas td.c-num::before{content:"#"}
      table.tbl.parcelas td.c-venc{grid-column:2;grid-row:1;font-weight:600}
      table.tbl.parcelas td.c-valor{grid-column:3;grid-row:1;text-align:right;white-space:nowrap;font-weight:600}
      table.tbl.parcelas td.c-status{grid-column:1/3;grid-row:2}
      table.tbl.parcelas td.c-acao{grid-column:3;grid-row:2;text-align:right}
      table.tbl.parcelas td.c-acao:empty{display:none}

      /* Lista longa (livro-caixa): cada linha vira um cartão que mostra só o
         que decide — descrição, valor, data, placa — e abre no toque para o
         resto. Arrastar a tabela de lado para achar o valor era pior que
         tocar na linha certa. */
      table.tbl.resumo thead{display:none}
      table.tbl.resumo,table.tbl.resumo tbody{display:block}
      table.tbl.resumo tr{display:grid;grid-template-columns:max-content max-content minmax(0,1fr) max-content;
        column-gap:10px;row-gap:7px;align-items:baseline;padding:18px 6px;border-bottom:1px solid var(--line);cursor:pointer}
      table.tbl.resumo tr:last-child{border-bottom:0}
      table.tbl.resumo td{display:block;padding:0;border:0;text-align:left;min-width:0}
      table.tbl.resumo td.c-desc{grid-column:1/4;grid-row:1;max-width:none;white-space:normal;
        display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-weight:600;font-size:15px;line-height:1.35}
      /* O valor fica só na primeira linha: ocupando as duas, ele espremia a
         segunda e o status saía cortado. */
      table.tbl.resumo td.c-valor{grid-column:4;grid-row:1;align-self:start;text-align:right;white-space:nowrap;font-size:15px;padding-left:6px}
      table.tbl.resumo td.c-data,table.tbl.resumo td.c-placa,table.tbl.resumo td.c-cat{grid-row:2;font-size:13px;color:var(--muted)}
      table.tbl.resumo td.c-data{grid-column:1}
      table.tbl.resumo td.c-placa{grid-column:2}
      table.tbl.resumo td.c-cat{grid-column:3/5;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
      table.tbl.resumo td.c-placa .badge{font-size:12px;padding:3px 8px}
      /* Quanto falta receber fica à vista no cartão (quadro de fretes): é a
         pergunta que se faz ao passar o olho na lista, não detalhe de toque. */
      table.tbl.resumo td.c-receb{grid-column:1/5;grid-row:3;font-size:13px}
      table.tbl.resumo td.c-receb .badge{font-size:12px;padding:3px 8px}
      table.tbl.resumo td.c-receb .sub{display:inline;margin-left:6px}
      /* Título do cartão que abre o detalhe: laranja, para deixar claro que é clicável. */
      table.tbl.resumo td.c-desc a.titulo{color:var(--primary);text-decoration:none}
      table.tbl.resumo td.c-desc a.titulo:active{color:var(--primary-600)}
      /* Data com etiqueta embaixo (vencimento): no cartão ficam lado a lado. */
      table.tbl.resumo td.c-data br{display:none}
      table.tbl.resumo td.c-data .badge{margin-left:6px;font-size:11px;padding:2px 7px}
      /* O resto fica atrás do toque. Aberto, cada célula é "rótulo: valor". */
      table.tbl.resumo td.c-mais{display:none;grid-column:1/5;justify-content:space-between;gap:14px;padding-top:8px;font-size:13px}
      table.tbl.resumo td.c-mais::before{content:attr(data-l);color:var(--muted);font-size:12px;font-weight:600;flex:none}
      table.tbl.resumo tr.aberta td.c-mais{display:flex}
      table.tbl.resumo tr.aberta td.c-mais:first-of-type{margin-top:4px}
      /* Ação não é dado: sem rótulo, e o botão toma a largura do cartão. */
      table.tbl.resumo td.c-acao::before{content:none}
      table.tbl.resumo tr.aberta td.c-acao{display:block;padding-top:10px}
      table.tbl.resumo td.c-acao form{width:100%}
      table.tbl.resumo td.c-acao .btn{display:flex;width:100%;justify-content:center;padding:11px 14px;font-size:14px}
      table.tbl.resumo td.c-acao a:not(.btn){display:block;text-align:center;padding:10px;
        border:1px solid var(--line);border-radius:10px;color:var(--ink);font-weight:600;font-size:13px}
      /* Frete já finalizado não tem ação: a célula vazia não vira espaço em branco. */
      table.tbl.resumo tr.aberta td.c-acao:not(:has(a,button)){display:none}
      table.tbl.resumo td.empty{grid-column:1/5;text-align:center}

      /* Um mapa de 420px come a tela toda do celular junto com o cabeçalho. */
      .map-box{height:300px}

      /* Salvar não pode exigir rolar até o fim. As ações descolam e ficam ao
         alcance do polegar, logo acima da barra de navegação — e o conteúdo
         ganha espaço embaixo para nada ficar escondido atrás delas. */
      /* Tela de ação tem uma barra só: as ações do formulário tomam o lugar
         da dock, que some enquanto a pessoa decide. Confirmou ou cancelou,
         ela cai numa lista e a dock volta com ela. Duas barras empilhadas
         comiam um terço da tela. */
      body:has(.form-actions) .tabbar{display:none}
      .form-actions{position:fixed;left:12px;right:12px;z-index:49;margin:0;
        bottom:calc(12px + env(safe-area-inset-bottom));
        padding:10px;gap:8px;background:var(--surface);border:1px solid var(--line);
        border-radius:18px;box-shadow:0 12px 30px rgba(49,63,73,.18)}
      .form-actions .btn{flex:1 1 0;min-width:0;justify-content:center;padding:11px 14px}
      /* Sair é o caminho menos provável: ocupa o que sobrar, não a metade. */
      .form-actions .btn-ghost{flex:0 0 auto}
      body:has(.form-actions) .content{padding-bottom:110px}

      /* Secondary columns step aside on a phone so the value stays visible. */
      .hide-sm{display:none}
      .so-sm{display:inline}
      .chip.so-sm{display:inline-flex}
      .truncate-sm{max-width:130px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
      table.tbl th,table.tbl td{padding-left:10px;padding-right:10px}
    }

    /* Shell chrome (logout form, account-switch modal) — sempre presente,
       por isso mora aqui e não no bloco de css, que cada página sobrescreve. */
    .base-logout-form{margin-left:auto;line-height:0}
    /* "Sair" com palavra e 44px de alvo: no celular, um ícone solto de 18px
       era invisível na prática. */
    .base-logout-btn{display:inline-flex;align-items:center;gap:6px;min-height:40px;padding:0 10px;
      border:1px solid rgba(255,255,255,.12);border-radius:10px;background:none;color:#cbd5e1;
      cursor:pointer;font:600 12px/1 inherit;font-family:inherit;-webkit-tap-highlight-color:rgba(255,108,2,.18)}
    .base-logout-btn:hover,.base-logout-btn:active{background:rgba(255,255,255,.08);color:#fff}
    .side-eu{display:flex;align-items:center;gap:10px;min-width:0;flex:1;border-radius:10px;padding:2px;margin:-2px}
    .side-eu:hover .who,.side-user.active .who{color:#fff}
    .side-user.active{box-shadow:inset 0 0 0 1px rgba(255,108,2,.55)}
    .base-modal-field{margin-top:12px}
    .base-modal-err{color:var(--red);font-size:12.5px;margin-top:10px}
    /* Faixa fixa da impersonação: quem está atendendo não pode esquecer
       em qual conta está agindo. */
    .impersonando{background:var(--sidebar);color:#fff;padding:9px 16px;
      display:flex;align-items:center;gap:12px;font-size:13px;flex-wrap:wrap}
    .impersonando form{margin-left:auto}
    .impersonando button{background:var(--primary);color:#fff;border:0;
      border-radius:var(--radius-pill);padding:5px 14px;font-weight:600;
      font-size:12.5px;cursor:pointer}
    /* Avisos de ação (messages do Django). */
    .msgs{display:flex;flex-direction:column;gap:8px;margin-bottom:16px}
    .msg{border-radius:var(--radius-sm);padding:11px 14px;font-size:13.5px;
      border:1px solid var(--line);background:var(--surface);color:var(--ink)}
    .msg-success{background:var(--green-soft);border-color:var(--green)}
    .msg-info{background:var(--primary-soft);border-color:var(--primary)}
    .msg-warning{background:var(--amber-soft);border-color:var(--amber)}
    .msg-error{background:var(--red-soft);border-color:var(--red)}

/* Campo de 16px onde se digita com o dedo. O Safari do iPhone dá zoom sozinho
   ao focar um campo com fonte menor que 16px — a tela salta, some metade do
   formulário e a pessoa tem que pinçar de volta para enxergar o que digitou.
   Não é preferência de tamanho: 16px é o limiar que desliga esse zoom. Vale
   pelo tipo de ponteiro, não pela largura, porque quem faz isso é o dedo — um
   iPad deitado tem 1024px de largura e o mesmo comportamento.

   Travar o zoom pelo maximum-scale da viewport resolveria numa linha e é o
   caminho errado: tiraria também o zoom que a pessoa dá de propósito, que é
   como quem enxerga pouco lê a tela. */
@media (pointer:coarse){
  input,select,textarea,
  .field input,.field select,.field textarea,
  .filters input,.filters select,
  .map-search input,
  .combo-search{font-size:16px}
}

/* Utilitários: o que antes se repetia como .il-N em template após template.
   Nome diz o efeito, e o mesmo nome vale em qualquer tela. */
.discreto{color:var(--muted)}
.nota{color:var(--muted);font-size:12px}
.forte{font-weight:700}
