/* ============================================================
   Optyma System — design system (bi-tema, aprovado)
   dark = base; claro sob prefers-color-scheme / [data-theme].
   Violeta é a MARCA da Optyma; verde/âmbar/vermelho são SEMÂNTICOS (status)
   e ficam IGUAIS em qualquer marca (não confundir com --accent-2, que é a
   segunda cor de MARCA — só a Vitta usa por enquanto).

   Duas marcas rodam neste mesmo arquivo — qual bloco vale depende do
   atributo `data-brand` no <html> (injetado via `brand_theme`, ver
   `Config.brand_theme`): "optyma" (== este bloco :root, sem sufixo, é o
   padrão/fallback) ou "vitta" (bloco próprio mais abaixo, seção VITTA).
   `data-theme` (claro/escuro) é um eixo TOTALMENTE separado — preferência
   pessoal do usuário, nada a ver com qual marca está rodando.
   ============================================================ */
:root{
  --bg:#0d0b14; --bg-deep:#08060d;
  --surface:#16131f; --surface-2:#1b1727; --surface-3:#221c31;
  --ink:#eceaf3; --ink-soft:#b3aec4; --ink-faint:#837e97; --ink-ghost:#565167;
  --rule:#262233; --rule-strong:#332d47;
  --accent:#7c4fd6; --accent-bright:#a486ea; --accent-text:#b59cf0;
  --accent-soft:rgba(124,79,214,0.16); --accent-line:rgba(124,79,214,0.5);
  --accent-2:#a486ea; --accent-2-soft:rgba(124,79,214,0.16);
  --ok:#54c08a; --ok-soft:rgba(84,192,138,0.14);
  --warn:#e0a83f; --warn-soft:rgba(224,168,63,0.14);
  --crit:#e5555f; --crit-soft:rgba(229,85,95,0.15);
  --info:#4f8fe0; --info-soft:rgba(79,143,224,0.14);
  --card-top:#17141f; --card-bot:#131019;
  --sidebar-top:#120f1b; --sidebar-bot:#0c0a12;
  --topbar-bg:rgba(13,11,20,0.82);
  --shadow-card:0 1px 0 rgba(255,255,255,0.03) inset, 0 20px 40px -32px rgba(0,0,0,0.7);
  --grid-line:rgba(255,255,255,0.05);
  --donut-hole:#141019;
  --avatar-fg:#fff;
  --font-sans:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;
  --font-display:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;
  --font-mono:ui-monospace,'SF Mono','Cascadia Mono','JetBrains Mono','Roboto Mono',Consolas,monospace;
  --radius:6px; --radius-lg:10px;
  --ease:cubic-bezier(0.22,0.61,0.36,1);
}
:root[data-theme="light"]{
  --bg:#f4f3fa; --bg-deep:#ebe8f4;
  --surface:#ffffff; --surface-2:#f6f5fb; --surface-3:#edebf6;
  --ink:#191325; --ink-soft:#4e4860; --ink-faint:#877f96; --ink-ghost:#b4aec6;
  --rule:#e7e4f1; --rule-strong:#d6d1e5;
  --accent:#7c4fd6; --accent-bright:#6a3fca; --accent-text:#5f37b8;
  --accent-soft:rgba(124,79,214,0.10); --accent-line:rgba(124,79,214,0.42);
  --accent-2:#6a3fca; --accent-2-soft:rgba(124,79,214,0.10);
  --ok:#2f9e6a; --ok-soft:rgba(47,158,106,0.13);
  --warn:#b07615; --warn-soft:rgba(176,118,21,0.13);
  --crit:#d23b45; --crit-soft:rgba(210,59,69,0.11);
  --info:#2f6fc4; --info-soft:rgba(47,111,196,0.12);
  --card-top:#ffffff; --card-bot:#fbfaff;
  --sidebar-top:#faf9fd; --sidebar-bot:#f2f0f9;
  --topbar-bg:rgba(244,243,250,0.82);
  --shadow-card:0 1px 2px rgba(24,20,40,0.04), 0 18px 40px -30px rgba(70,50,120,0.26);
  --grid-line:rgba(40,25,80,0.07);
  --donut-hole:#ffffff;
}
@media (prefers-color-scheme:light){
  :root:not([data-theme="dark"]){
    --bg:#f4f3fa; --bg-deep:#ebe8f4;
    --surface:#ffffff; --surface-2:#f6f5fb; --surface-3:#edebf6;
    --ink:#191325; --ink-soft:#4e4860; --ink-faint:#877f96; --ink-ghost:#b4aec6;
    --rule:#e7e4f1; --rule-strong:#d6d1e5;
    --accent:#7c4fd6; --accent-bright:#6a3fca; --accent-text:#5f37b8;
    --accent-soft:rgba(124,79,214,0.10); --accent-line:rgba(124,79,214,0.42);
    --accent-2:#6a3fca; --accent-2-soft:rgba(124,79,214,0.10);
    --ok:#2f9e6a; --ok-soft:rgba(47,158,106,0.13);
    --warn:#b07615; --warn-soft:rgba(176,118,21,0.13);
    --crit:#d23b45; --crit-soft:rgba(210,59,69,0.11);
    --info:#2f6fc4; --info-soft:rgba(47,111,196,0.12);
    --card-top:#ffffff; --card-bot:#fbfaff;
    --sidebar-top:#faf9fd; --sidebar-bot:#f2f0f9;
    --topbar-bg:rgba(244,243,250,0.82);
    --shadow-card:0 1px 2px rgba(24,20,40,0.04), 0 18px 40px -30px rgba(70,50,120,0.26);
    --grid-line:rgba(40,25,80,0.07);
    --donut-hole:#ffffff;
  }
}

/* ============================================================
   VITTA — direção "Sève" (fechada 2026-08-26).
   Verde-seiva é a MARCA; --ok/--warn/--crit/--info continuam os mesmos
   valores semânticos de cima (não são "cor da marca", são "estado").
   IMPORTANTE: --accent muda de tom entre claro/escuro de propósito (não é
   a mesma cor escurecida/clareada) — o verde-escuro da marca (#2f6b3c)
   fica sujo/sem contraste num fundo escuro, por isso o escuro usa um verde
   mais claro e saturado (#63c77e). Ver [[project_vitta_brand]].
   ============================================================ */
:root[data-brand="vitta"]{
  --bg:#10190f; --bg-deep:#0a120a;
  --surface:#182219; --surface-2:#1e2c1f; --surface-3:#253626;
  --ink:#e9efe3; --ink-soft:#93a68c; --ink-faint:#6e8267; --ink-ghost:#465340;
  --rule:#263429; --rule-strong:#34492f;
  --accent:#63c77e; --accent-bright:#7dda95; --accent-text:#8fe0a3;
  --accent-soft:rgba(99,199,126,0.16); --accent-line:rgba(99,199,126,0.5);
  --accent-2:#f0ae55; --accent-2-soft:rgba(240,174,85,0.16);
  --card-top:#192419; --card-bot:#131c13;
  --sidebar-top:#121c12; --sidebar-bot:#0c140b;
  --topbar-bg:rgba(16,25,15,0.82);
  --shadow-card:0 1px 0 rgba(255,255,255,0.03) inset, 0 20px 40px -32px rgba(0,0,0,0.7);
  --grid-line:rgba(255,255,255,0.05);
  --donut-hole:#131c13;
  --avatar-fg:#0e1710;
  --font-display:Constantia,Cambria,Georgia,serif;
}
:root[data-brand="vitta"][data-theme="light"]{
  --bg:#eff2e7; --bg-deep:#e5ead9;
  --surface:#f8faf3; --surface-2:#f1f5ea; --surface-3:#e9efdd;
  --ink:#1b2a1e; --ink-soft:#5b6c55; --ink-faint:#86937e; --ink-ghost:#b7c2ac;
  --rule:#d7dfc9; --rule-strong:#c3ceb0;
  --accent:#2f6b3c; --accent-bright:#24572f; --accent-text:#245a2f;
  --accent-soft:rgba(47,107,60,0.10); --accent-line:rgba(47,107,60,0.42);
  --accent-2:#b5691f; --accent-2-soft:rgba(181,105,31,0.13);
  --card-top:#f8faf3; --card-bot:#f1f5ea;
  --sidebar-top:#f4f7ee; --sidebar-bot:#ecf1e1;
  --topbar-bg:rgba(239,242,231,0.82);
  --shadow-card:0 1px 2px rgba(20,30,15,0.05), 0 18px 40px -30px rgba(50,80,40,0.22);
  --grid-line:rgba(30,50,20,0.07);
  --donut-hole:#f8faf3;
  --avatar-fg:#fff;
}
@media (prefers-color-scheme:light){
  :root[data-brand="vitta"]:not([data-theme="dark"]){
    --bg:#eff2e7; --bg-deep:#e5ead9;
    --surface:#f8faf3; --surface-2:#f1f5ea; --surface-3:#e9efdd;
    --ink:#1b2a1e; --ink-soft:#5b6c55; --ink-faint:#86937e; --ink-ghost:#b7c2ac;
    --rule:#d7dfc9; --rule-strong:#c3ceb0;
    --accent:#2f6b3c; --accent-bright:#24572f; --accent-text:#245a2f;
    --accent-soft:rgba(47,107,60,0.10); --accent-line:rgba(47,107,60,0.42);
    --accent-2:#b5691f; --accent-2-soft:rgba(181,105,31,0.13);
    --card-top:#f8faf3; --card-bot:#f1f5ea;
    --sidebar-top:#f4f7ee; --sidebar-bot:#ecf1e1;
    --topbar-bg:rgba(239,242,231,0.82);
    --shadow-card:0 1px 2px rgba(20,30,15,0.05), 0 18px 40px -30px rgba(50,80,40,0.22);
    --grid-line:rgba(30,50,20,0.07);
    --donut-hole:#f8faf3;
    --avatar-fg:#fff;
  }
}
/* Wordmark da Vitta usa a fonte de exibição (itálico), a da Optyma não muda
   (--font-display == --font-sans nela, ver bloco :root do topo). */
[data-brand="vitta"] .brand{ font-family:var(--font-display); font-style:italic; }

*{box-sizing:border-box;}
html{background:var(--bg);}
body{margin:0;}
.op{
  background:var(--bg); color:var(--ink); font-family:var(--font-sans);
  -webkit-font-smoothing:antialiased; line-height:1.5; min-height:100vh;
  display:grid; grid-template-columns:250px 1fr;
  transition:background .25s var(--ease), color .25s var(--ease);
}
.op ::selection{background:rgba(124,79,214,0.3);}
a{color:inherit;text-decoration:none;}
h1,h2,h3{margin:0;font-weight:700;letter-spacing:-0.02em;}

/* ---------- sidebar ---------- */
.sidebar{background:linear-gradient(180deg,var(--sidebar-top),var(--sidebar-bot));border-right:1px solid var(--rule);display:flex;flex-direction:column;position:sticky;top:0;height:100vh;}
.brand{display:flex;align-items:baseline;gap:2px;padding:22px 22px 20px;font-weight:700;font-size:1.5rem;letter-spacing:-0.04em;}
.brand .dot{color:var(--accent);background:linear-gradient(135deg,#9a72e8,#6b45c9);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;}
.brand-tag{font-family:var(--font-mono);font-size:0.6rem;font-weight:500;letter-spacing:0.22em;text-transform:uppercase;color:var(--ink-faint);margin-left:7px;align-self:center;border:1px solid var(--rule-strong);border-radius:100px;padding:3px 7px;}
nav{padding:6px 12px;display:flex;flex-direction:column;gap:2px;overflow-y:auto;flex:1;}
.nav-label{font-family:var(--font-mono);font-size:0.62rem;letter-spacing:0.18em;text-transform:uppercase;color:var(--ink-ghost);padding:16px 10px 7px;}
.nav-item{display:flex;align-items:center;gap:11px;padding:9px 10px;border-radius:var(--radius);color:var(--ink-soft);font-size:0.9rem;transition:background .15s var(--ease),color .15s var(--ease);cursor:pointer;position:relative;}
.nav-item svg{width:17px;height:17px;flex:none;opacity:.85;}
.nav-item:hover{background:var(--surface-2);color:var(--ink);}
.nav-item.active{background:linear-gradient(90deg,var(--accent-soft),transparent);color:var(--ink);}
.nav-item.active::before{content:'';position:absolute;left:-12px;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:var(--accent);}
.nav-item.active svg{opacity:1;color:var(--accent-text);}
.nav-badge{margin-left:auto;font-family:var(--font-mono);font-size:0.66rem;font-weight:600;background:var(--surface-3);color:var(--ink-soft);border-radius:100px;padding:2px 7px;min-width:20px;text-align:center;}
.nav-badge.warn{background:var(--warn-soft);color:var(--warn);}
.sidebar-foot{border-top:1px solid var(--rule);padding:14px 16px;display:flex;align-items:center;gap:11px;}
.avatar{width:34px;height:34px;border-radius:50%;flex:none;background:linear-gradient(135deg,#7c4fd6,#4a2e86);color:var(--avatar-fg);display:flex;align-items:center;justify-content:center;font-weight:700;font-size:0.82rem;}
.sidebar-foot .who{font-size:0.82rem;font-weight:600;line-height:1.3;}
.sidebar-foot .role{font-family:var(--font-mono);font-size:0.66rem;color:var(--ink-faint);letter-spacing:0.04em;}
.sidebar-foot>div:not(.avatar){min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.logout-form{flex:none;margin-left:auto;}
.logout-btn{width:30px;height:30px;border-radius:8px;border:1px solid transparent;background:transparent;color:var(--ink-faint);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .15s,color .15s;}
.logout-btn:hover{background:var(--surface-3);color:var(--crit);}
.logout-btn svg{width:16px;height:16px;}

/* ---------- flash messages ---------- */
.flashes{display:flex;flex-direction:column;gap:8px;margin:0 0 18px;}
.flash{padding:11px 16px;border-radius:10px;font-size:0.86rem;border:1px solid transparent;}
.flash.erro{background:var(--crit-soft);color:var(--crit);border-color:color-mix(in srgb, var(--crit) 30%, transparent);}
.flash.ok{background:var(--ok-soft);color:var(--ok);border-color:color-mix(in srgb, var(--ok) 30%, transparent);}

/* destaque temporário ao chegar via link "#comprovante-<id>" (banner de
   comprovante recusado, base_portal.html + app.js) — chama atenção pro
   card/linha certo entre vários itens da lista. */
.anchor-destaque{animation:anchor-pulso 2.4s ease-out 1;border-radius:8px;}
@keyframes anchor-pulso{
  0%,65%{outline:2px solid var(--crit);outline-offset:2px;background:var(--crit-soft);}
  100%{outline:2px solid transparent;outline-offset:2px;background:transparent;}
}
@media (prefers-reduced-motion:reduce){.anchor-destaque{animation:none;outline:2px solid var(--crit);outline-offset:2px;}}

/* ---------- main ---------- */
.main{min-width:0;}
.topbar{position:sticky;top:0;z-index:20;background:var(--topbar-bg);backdrop-filter:blur(14px);border-bottom:1px solid var(--rule);padding:16px 30px;display:flex;align-items:center;justify-content:space-between;gap:20px;}
.topbar h1{font-size:1.32rem;}
.topbar .sub{margin:3px 0 0;font-size:0.8rem;color:var(--ink-faint);}
.topbar-right{display:flex;align-items:center;gap:14px;}
.seg{display:inline-flex;background:var(--surface);border:1px solid var(--rule);border-radius:var(--radius);overflow:hidden;}
.seg button,.seg a{background:none;border:none;color:var(--ink-faint);font-family:var(--font-mono);font-size:0.74rem;letter-spacing:0.04em;padding:7px 12px;cursor:pointer;transition:color .15s,background .15s;text-decoration:none;display:inline-block;}
.seg button.on,.seg a.on{background:var(--accent-soft);color:var(--accent-text);}
.seg button:hover:not(.on),.seg a:hover:not(.on){color:var(--ink);}
.themebtn{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;background:var(--surface);border:1px solid var(--rule);border-radius:var(--radius);color:var(--ink-soft);cursor:pointer;transition:color .15s,border-color .15s;}
.themebtn:hover{color:var(--accent-text);border-color:var(--accent-line);}
.themebtn svg{width:17px;height:17px;}
.live{display:inline-flex;align-items:center;gap:8px;font-family:var(--font-mono);font-size:0.72rem;letter-spacing:0.1em;text-transform:uppercase;color:var(--ok);}
.live::before{content:'';width:7px;height:7px;border-radius:50%;background:var(--ok);box-shadow:0 0 0 0 rgba(84,192,138,0.5);animation:pulse 2.4s var(--ease) infinite;}
@keyframes pulse{0%{box-shadow:0 0 0 0 rgba(84,192,138,0.45);}70%{box-shadow:0 0 0 7px rgba(84,192,138,0);}100%{box-shadow:0 0 0 0 rgba(84,192,138,0);}}

.content{padding:26px 30px 60px;display:flex;flex-direction:column;gap:22px;max-width:1500px;}

/* ---------- cards ---------- */
.card{min-width:0;background:linear-gradient(180deg,var(--card-top),var(--card-bot));border:1px solid var(--rule);border-radius:var(--radius-lg);padding:20px 22px;box-shadow:var(--shadow-card);}
.card-h{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:16px;}
.card-h .t{font-size:0.95rem;font-weight:600;}
.lbl{font-family:var(--font-mono);font-size:0.66rem;letter-spacing:0.16em;text-transform:uppercase;color:var(--ink-faint);}

.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;}
.kpi{--kpi-c:var(--accent);--kpi-c-soft:var(--accent-soft);min-width:0;background:linear-gradient(180deg,var(--card-top),var(--card-bot));border:1px solid var(--rule);border-radius:var(--radius-lg);padding:16px 18px;display:flex;flex-direction:column;gap:2px;position:relative;z-index:0;overflow:hidden;box-shadow:var(--shadow-card);}
.kpi.hero{border-color:var(--rule-strong);}
.kpi.hero::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,var(--kpi-c),transparent);opacity:.7;}
.kpi.hero::after{content:'';position:absolute;z-index:-1;top:-60%;right:-25%;width:70%;height:160%;background:radial-gradient(circle,var(--kpi-c-soft),transparent 68%);pointer-events:none;}
/* variantes de cor por KPI — cada cartão com o seu próprio sombreado semântico */
.kpi.c-ok{--kpi-c:var(--ok);--kpi-c-soft:var(--ok-soft);}
.kpi.c-warn{--kpi-c:var(--warn);--kpi-c-soft:var(--warn-soft);}
.kpi.c-info{--kpi-c:var(--info);--kpi-c-soft:var(--info-soft);}
.kpi .cap{display:flex;align-items:center;gap:7px;}
.kpi .num{font-family:var(--font-mono);font-size:1.62rem;font-weight:600;letter-spacing:-0.02em;font-variant-numeric:tabular-nums;margin-top:5px;}
.kpi .num .cur{font-size:0.9rem;color:var(--ink-faint);margin-right:3px;font-weight:500;}
.kpi .foot{display:flex;align-items:center;gap:8px;margin-top:8px;}
.spark{width:100%;height:34px;display:block;margin-top:10px;}
.delta{font-family:var(--font-mono);font-size:0.72rem;font-weight:600;display:inline-flex;align-items:center;gap:3px;padding:2px 7px;border-radius:100px;}
.delta.up{background:var(--ok-soft);color:var(--ok);}
.delta.down{background:var(--crit-soft);color:var(--crit);}
.delta .arw{font-size:0.7rem;}
.kpi .vs{font-size:0.72rem;color:var(--ink-ghost);}

.row2{display:grid;grid-template-columns:1.7fr 1fr;gap:22px;align-items:start;}
.row3{display:grid;grid-template-columns:repeat(3,1fr);gap:22px;}
/* colunas de verdade independentes (cada uma empilha o que for seu, sem
   travar na altura da coluna vizinha) — usar quando os cards da esquerda e
   da direita não têm relação de altura nenhuma entre si (ex.: gráfico curto
   ao lado de uma lista longa, e mais um card embaixo só do lado curto). */
.cols2{display:grid;grid-template-columns:1.7fr 1fr;gap:22px;align-items:start;}
.cols2 .col{display:flex;flex-direction:column;gap:22px;min-width:0;}

/* cards de altura FIXA — não variam com a quantidade de dados do cliente
   (1 máquina ou 20, 2 repasses ou 200): o conteúdo que passar do espaço rola
   por dentro (.scroll-area), a moldura do card nunca muda de tamanho. */
.card.fixed-h{display:flex;flex-direction:column;}
.card.fixed-h.h-sm{height:250px;}
.card.fixed-h.h-lg{height:600px;}
.card.fixed-h .scroll-area{flex:1;min-height:0;overflow-y:auto;padding-right:14px;margin-right:-14px;}

/* scrollbar fina, no tom do sistema — Firefox (scrollbar-width/-color) +
   Chrome/Edge/Safari (::-webkit-scrollbar). Some transparente quando não
   está em uso, sem a barra cinza padrão do SO destoando do tema. */
.scroll-area,.tablewrap,nav{scrollbar-width:thin;scrollbar-color:var(--rule-strong) transparent;}
.scroll-area::-webkit-scrollbar,.tablewrap::-webkit-scrollbar,nav::-webkit-scrollbar{width:7px;height:7px;}
.scroll-area::-webkit-scrollbar-track,.tablewrap::-webkit-scrollbar-track,nav::-webkit-scrollbar-track{background:transparent;}
.scroll-area::-webkit-scrollbar-thumb,.tablewrap::-webkit-scrollbar-thumb,nav::-webkit-scrollbar-thumb{background:var(--rule-strong);border-radius:100px;border:2px solid transparent;background-clip:padding-box;}
.scroll-area::-webkit-scrollbar-thumb:hover,.tablewrap::-webkit-scrollbar-thumb:hover,nav::-webkit-scrollbar-thumb:hover{background:var(--ink-faint);background-clip:padding-box;}

.chartwrap{position:relative;height:250px;}
.chartwrap canvas{width:100%;height:100%;display:block;}
.chart-legend{display:flex;gap:20px;}
.chart-legend span{display:inline-flex;align-items:center;gap:7px;font-size:0.78rem;color:var(--ink-soft);}
.swatch{width:9px;height:9px;border-radius:2px;flex:none;}

.donut-wrap{display:flex;align-items:center;gap:22px;}
.donut{width:132px;height:132px;border-radius:50%;flex:none;position:relative;background:conic-gradient(#7c4fd6 0 52%,#a486ea 52% 73%,#54c08a 73% 92%,#e0a83f 92% 100%);}
.donut::after{content:'';position:absolute;inset:20px;border-radius:50%;background:var(--donut-hole);}
.donut .mid{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:2;}
.donut .mid b{font-family:var(--font-mono);font-size:1.15rem;font-variant-numeric:tabular-nums;}
.donut .mid span{font-family:var(--font-mono);font-size:0.6rem;letter-spacing:0.14em;text-transform:uppercase;color:var(--ink-faint);}
.leg{display:flex;flex-direction:column;gap:11px;flex:1;}
.leg-row{display:flex;align-items:center;gap:10px;font-size:0.85rem;}
.leg-row .nm{color:var(--ink-soft);}
.leg-row .pc{margin-left:auto;font-family:var(--font-mono);font-variant-numeric:tabular-nums;color:var(--ink);}

.bignum{font-family:var(--font-mono);font-size:1.72rem;font-weight:600;font-variant-numeric:tabular-nums;letter-spacing:-0.02em;}
.bignum .cur{font-size:0.85rem;color:var(--ink-faint);font-weight:500;margin-right:3px;}
.statline{display:flex;align-items:center;justify-content:space-between;padding:11px 0;border-top:1px solid var(--rule);font-size:0.86rem;}
.statline:first-of-type{border-top:none;}
.statline .k{color:var(--ink-soft);display:flex;align-items:center;gap:8px;}
.statline .v{font-family:var(--font-mono);font-variant-numeric:tabular-nums;color:var(--ink);}
.statline .v.destaque{color:var(--accent-text);font-weight:600;}

/* comprovante fotográfico da venda (frente/verso — migration 023) */
.comprovante-upload{display:flex;gap:6px;flex-wrap:wrap;}
.comprovante-upload .upload-form{display:inline-flex;}
.upload-btn{cursor:pointer;}
.upload-btn input[type="file"]{position:absolute;width:1px;height:1px;overflow:hidden;opacity:0;pointer-events:none;}
.comprovante-hint{display:block;margin-top:6px;font-size:0.72rem;color:var(--ink-faint);}

/* overlay "Enviando foto..." (aparece no submit, some quando a próxima
   página carrega por cima — ver web/static/js/app.js) */
.processando-overlay{position:fixed;inset:0;z-index:9999;background:rgba(8,7,14,0.72);backdrop-filter:blur(2px);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;color:#fff;
  font-family:var(--font-sans);font-size:0.92rem;font-weight:600;}
.processando-spinner{width:34px;height:34px;border-radius:50%;border:3px solid rgba(255,255,255,0.25);
  border-top-color:#fff;animation:upload-spin 0.8s linear infinite;}
@media (prefers-reduced-motion: reduce){.processando-spinner{animation-duration:1.6s;}}
@keyframes upload-spin{to{transform:rotate(360deg);}}

/* destaque breve no card/linha da venda ao voltar do upload (scroll-back) —
   só background (box-shadow em <tr> não renderiza de forma confiável em
   todos os navegadores, já que a linha de tabela nem sempre forma uma caixa
   própria pra sombra). */
.comprovante-destaque{animation:comprovante-flash 2.2s ease-out;}
@keyframes comprovante-flash{
  0%{background-color:var(--accent-soft);}
  100%{background-color:transparent;}
}
.mode-tag{font-family:var(--font-mono);font-size:0.64rem;letter-spacing:0.06em;padding:2px 7px;border-radius:100px;border:1px solid var(--rule-strong);color:var(--ink-faint);white-space:nowrap;}

/* ---------- portal do lojista: banner de antecipação em destaque na Home ----------
   Quase toda venda a prazo vira pedido de antecipação (core do negócio) — o
   valor disponível + o CTA ficam num card próprio, com o acento da marca,
   logo abaixo dos KPIs (antes do gráfico/máquinas), pra não depender de
   trocar de aba pra ver o que mais importa no dia a dia. */
.antecip-banner{
  display:flex;align-items:center;justify-content:space-between;gap:18px;flex-wrap:wrap;
  border-color:var(--accent-line);
  background:linear-gradient(135deg,var(--accent-soft),transparent 65%),linear-gradient(180deg,var(--card-top),var(--card-bot));
}
.antecip-banner-info{display:flex;flex-direction:column;gap:5px;min-width:0;}
.antecip-banner-valor{font-family:var(--font-mono);font-size:1.5rem;font-weight:600;color:var(--ink);display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;font-variant-numeric:tabular-nums;}
.antecip-banner-sub{font-size:0.78rem;color:var(--ink-faint);font-weight:400;font-family:var(--font-sans);}
.antecip-banner .btn{flex:none;}

.pill{font-family:var(--font-mono);font-size:0.68rem;font-weight:600;padding:3px 9px;border-radius:100px;display:inline-flex;align-items:center;gap:5px;letter-spacing:0.02em;}
.pill.ok{background:var(--ok-soft);color:var(--ok);}
.pill.warn{background:var(--warn-soft);color:var(--warn);}
.pill.crit{background:var(--crit-soft);color:var(--crit);}
.pill.acc{background:var(--accent-soft);color:var(--accent-text);}
.pill.mut{background:var(--surface-3);color:var(--ink-faint);}
.dotm{width:6px;height:6px;border-radius:50%;}

.bars{display:flex;flex-direction:column;gap:13px;}
.bar-row{display:grid;grid-template-columns:1fr auto;gap:4px 12px;align-items:center;font-size:0.85rem;}
.bar-row .nm{color:var(--ink-soft);}
.bar-row .vl{font-family:var(--font-mono);font-size:0.8rem;font-variant-numeric:tabular-nums;color:var(--ink);}
.track{grid-column:1/-1;height:6px;border-radius:100px;background:var(--surface-3);overflow:hidden;}
.track i{display:block;height:100%;border-radius:100px;background:linear-gradient(90deg,#6b45c9,#a486ea);}

.tablewrap{overflow-x:auto;}
table{width:100%;border-collapse:collapse;min-width:820px;}
th{text-align:left;font-family:var(--font-mono);font-size:0.66rem;letter-spacing:0.1em;text-transform:uppercase;color:var(--ink-faint);font-weight:500;padding:0 16px 12px;border-bottom:1px solid var(--rule);}
th.r,td.r{text-align:right;}
td{padding:13px 16px;border-bottom:1px solid var(--rule);font-size:0.86rem;color:var(--ink-soft);}
tbody tr:last-child td{border-bottom:none;}
tbody tr{transition:background .12s;}
tbody tr:hover{background:var(--surface-2);}
td .mono{font-family:var(--font-mono);font-variant-numeric:tabular-nums;}
td .cli{color:var(--ink);font-weight:500;}
td .val{font-family:var(--font-mono);font-variant-numeric:tabular-nums;color:var(--ink);font-weight:600;}
.modamini{display:inline-flex;align-items:center;gap:6px;}
.txid{color:var(--ink-faint);}

/* Detalhamento de repasse em lote (Liquidações & Repasses/portal "Repasses")
   — <details> nativo, sem JS: uma linha do histórico é 1 repasse de verdade
   (1 Pix), que pode cobrir várias transações/parcelas de uma vez; isto abre
   o breakdown item a item sem precisar de outra tela. */
details summary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:6px;}
details summary::-webkit-details-marker{display:none;}
details summary::before{content:'▸';color:var(--ink-faint);font-size:0.7em;transition:transform .15s var(--ease);}
details[open] summary::before{transform:rotate(90deg);}
ul.detalhe-lote{list-style:none;margin:10px 0 0;padding:10px 0 0 14px;border-top:1px dashed var(--rule);display:grid;gap:8px;}
ul.detalhe-lote li{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:0.82rem;}
ul.detalhe-lote li .val{font-family:var(--font-mono);font-variant-numeric:tabular-nums;color:var(--ink);}

/* ---------- auth (login) ---------- */
.auth-wrap{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px;background:var(--bg);}
.auth-card{width:100%;max-width:380px;background:linear-gradient(180deg,var(--card-top),var(--card-bot));border:1px solid var(--rule-strong);border-radius:var(--radius-lg);padding:34px 30px;box-shadow:var(--shadow-card);position:relative;}
.auth-card::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;border-radius:var(--radius-lg) var(--radius-lg) 0 0;background:linear-gradient(90deg,transparent,var(--accent),transparent);opacity:.6;}
.auth-brand{display:flex;align-items:baseline;gap:2px;font-weight:700;font-size:1.7rem;letter-spacing:-0.04em;color:var(--ink);margin-bottom:6px;}
.field{display:grid;gap:7px;margin-bottom:16px;}
.field label{font-family:var(--font-mono);font-size:0.68rem;letter-spacing:0.06em;text-transform:uppercase;color:var(--ink-soft);}
.field input,.field select,.field textarea{background:var(--surface-2);border:1px solid var(--rule-strong);border-radius:var(--radius);padding:12px 14px;color:var(--ink);font-family:var(--font-sans);font-size:0.95rem;width:100%;}
.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft);}
.field select{appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b8b9e' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 12px center;background-size:16px;padding-right:38px;}
.hint{font-size:0.74rem;color:var(--ink-faint);}
.input-sm{background:var(--surface-2);border:1px solid var(--rule-strong);border-radius:var(--radius);padding:7px 10px;color:var(--ink);font-family:var(--font-sans);font-size:0.82rem;}
.input-sm:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft);}
.input-sm::placeholder{color:var(--ink-ghost);}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:12px 18px;border:none;border-radius:var(--radius);font-family:var(--font-sans);font-weight:600;font-size:0.92rem;cursor:pointer;color:#fff;background:linear-gradient(135deg,#9a72e8,#7c4fd6 55%,#5f37b8);transition:transform .15s var(--ease);}
.btn:hover{transform:translateY(-1px);}
.btn.btn-auto{width:auto;padding-left:22px;padding-right:22px;}
.btn.btn-outline{background:transparent;color:var(--ink-soft);border:1px solid var(--rule-strong);}
.btn.btn-outline:hover{background:var(--surface-3);color:var(--ink);}
.btn.btn-sm{width:auto;padding:6px 13px;font-size:0.78rem;white-space:nowrap;}
.btn.btn-danger-outline{background:transparent;color:var(--crit);border:1px solid color-mix(in srgb, var(--crit) 35%, transparent);}
.btn.btn-danger-outline:hover{background:var(--crit-soft);}

/* ---------- formulários de gestão (Clientes, Máquinas) ---------- */
.form-card{background:linear-gradient(180deg,var(--card-top),var(--card-bot));border:1px solid var(--rule);border-radius:var(--radius-lg);padding:26px 28px;box-shadow:var(--shadow-card);}
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:0 20px;}
.form-grid .field.span2{grid-column:1/-1;}
.form-actions{display:flex;gap:12px;margin-top:8px;}
.form-actions .btn{flex:none;}
.toolbar{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:18px;flex-wrap:wrap;}
.toolbar form{display:flex;gap:8px;}
.toolbar .field{margin-bottom:0;min-width:260px;}
.empty-state{padding:48px 24px;text-align:center;color:var(--ink-soft);}
.id-row{display:flex;align-items:center;gap:8px;}
.copy-btn{width:24px;height:24px;flex:none;border:none;background:transparent;color:var(--ink-faint);display:flex;align-items:center;justify-content:center;border-radius:6px;cursor:pointer;transition:background .15s,color .15s;}
.copy-btn:hover{background:var(--surface-3);color:var(--ink);}
.copy-btn svg{width:14px;height:14px;}
.copy-btn.copied{color:var(--ok);}
.empty-state p{margin:0 0 18px;}
.inline-form{display:inline;}

/* ---------- tela de Transações: filtros + paginação ---------- */
.filtros-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:0 16px;}
.filtros-grid .field.span2{grid-column:1/3;}
.filtros-form .form-actions{margin-top:2px;}
.filtros-form .btn{width:auto;}
.pagination{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:16px 2px;border-top:1px solid var(--rule);margin-top:4px;}
.pagination-info{font-size:0.82rem;color:var(--ink-soft);}
.pagination-nav{display:flex;gap:10px;}
.pagination-nav .btn{width:auto;}

@media (max-width:720px){.form-grid{grid-template-columns:1fr;}.filtros-grid{grid-template-columns:1fr 1fr;}.filtros-grid .field.span2{grid-column:1/-1;}}

/* ---------- popup de confirmação de repasse (dados bancários + PIX) ---------- */
.modal-repasse{
  width:min(480px,92vw);padding:26px 28px;margin:auto;
  background:linear-gradient(180deg,var(--card-top),var(--card-bot));
  color:var(--ink);border:1px solid var(--rule-strong);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-card);
}
.modal-repasse::backdrop{background:rgba(8,6,13,0.6);}
:root[data-theme="light"] .modal-repasse::backdrop{background:rgba(25,19,37,0.35);}
.modal-repasse-title{margin:0 0 4px;font-size:1.05rem;}
.modal-repasse-valor{margin:0 0 14px;font-size:0.9rem;color:var(--ink-soft);}
.modal-repasse-valor .val{color:var(--ink);font-weight:700;font-size:1.1rem;}
/* valor TOTAL destacado (fila de repasses: cabeçalho da página E de cada
   cliente) — pedido do usuário, 2026-08-19: "8.964,06 é o valor total...
   deveria ficar bem destacado", distinto do que falta aprovar/já está
   aprovado, que ficam no .lbl/.sub normal ao lado. Reutilizável (não
   escopado a um container específico) — usado dentro de `.card-h .t` e de
   `.topbar .sub`, cada um com seu próprio tamanho base de texto ao redor. */
.total-destacado{font-family:var(--font-mono);font-variant-numeric:tabular-nums;color:var(--ink);font-weight:700;}
.card-h .t .total-destacado{font-size:1.05rem;}
.topbar .sub .total-destacado{font-size:0.95rem;}
.modal-repasse-aviso{background:var(--warn-soft);color:var(--warn);border-radius:var(--radius);padding:10px 12px;font-size:0.82rem;margin-bottom:14px;}
/* 3 botões agora (Cancelar / Pix automático / Confirmar, migration 029) —
   sem quebra de linha eles ficam mais largos que o modal e geram scroll
   horizontal (achado ao vivo, 2026-08-19). Quebra pra 2ª linha em vez disso;
   o botão primário (Confirmar) fica por último e alinhado à direita. */
.modal-repasse .form-actions{flex-wrap:wrap;justify-content:flex-end;}
.modal-repasse .form-actions .btn{flex:none;white-space:nowrap;}
#mr-dados{margin-bottom:4px;}
#mr-dados .statline .v{text-align:right;}

.placeholder{padding:60px 30px;text-align:center;color:var(--ink-soft);}

@media (max-width:1120px){.kpis{grid-template-columns:repeat(2,1fr);}.row2,.row3{grid-template-columns:1fr;}}
@media (max-width:900px){
  .op{grid-template-columns:66px 1fr;}
  .brand{padding:20px 0;justify-content:center;font-size:1.15rem;}
  .brand-tag,.nav-label,.nav-item span,.nav-badge,.sidebar-foot .who,.sidebar-foot .role{display:none;}
  .nav-item{justify-content:center;padding:11px 0;}
  .nav-item.active::before{display:none;}
  .sidebar-foot{justify-content:center;}
}
@media (max-width:560px){.kpis{grid-template-columns:1fr;}.content,.topbar{padding-left:18px;padding-right:18px;}.topbar-right .seg{display:none;}}
@media (prefers-reduced-motion:reduce){.live::before{animation:none;}.op{transition:none;}}

/* ---------- portal do lojista: navegação mobile (barra inferior fixa) ----------
   Escopado a `.op-portal` (só o portal do lojista, marcado em base_portal.html) —
   o admin continua com a sidebar de sempre (colapsa pra ícone-só em ≤900px, ver
   acima), inalterado. Abaixo de 680px o lojista troca a sidebar inteira por uma
   barra fixa no rodapé (padrão de app nativo — os lojistas usam o celular todo
   dia, 1 toque é melhor que abrir uma gaveta). */
.bottom-nav{display:none;}
.topbar-logout-form{display:none;}
/* lista de vendas em cards (mobile) — a tabela de 7 colunas (Venda/Máquina/
   Modalidade/Valor/Líquido/Status/Quando) não cabe na largura do celular sem
   scroll lateral (achado 2026-08-06, testando ao vivo). Escondida por padrão
   em qualquer tela; só aparece dentro de `.op-portal` em ≤680px, no lugar da
   tabela (ver regras dentro do media query abaixo). */
.tx-cards{display:none;}

@media (max-width:680px){
  .op-portal{grid-template-columns:1fr;}
  .op-portal .sidebar{display:none;}
  .op-portal .topbar{padding:14px 16px;flex-wrap:wrap;row-gap:8px;}
  .op-portal .topbar h1{font-size:1.08rem;}
  /* período (Hoje/7d/30d/Mês) — SÓ existe na Visão geral (`.topbar-right-
     periodo`, marcada em base_portal.html via `nav_active`) — mesmo .seg do
     dashboard do admin, mas ali a regra genérica ≤560px (ver acima) some com
     ele de vez; aqui o lojista SÓ tem essa tela pra trocar o período, então
     não pode desaparecer. Especificidade (3 classes) já vence a regra
     genérica sem precisar de !important. `width:100%` + `margin-left:auto`
     no themeToggle só entram nessa tela — nas outras (Extrato/Antecipação/
     Repasses/Dados bancários), sem .seg nenhum, o `.topbar-right` volta a
     ficar do tamanho do próprio conteúdo (2 ícones), senão eles "flutuavam"
     pro centro da tela nessas telas (achado real, 2026-08-12: o width:100%
     não pode ser incondicional). Os botões do .seg ganham a MESMA altura dos
     ícones de tema/sair (34px), em vez de ficarem menores. */
  .op-portal .topbar-right.topbar-right-periodo{flex-wrap:wrap;row-gap:8px;column-gap:10px;width:100%;}
  .op-portal .topbar-right .seg{display:inline-flex;}
  .op-portal .topbar-right .seg a{
    height:34px;display:inline-flex;align-items:center;justify-content:center;
    padding:0 12px;font-size:0.76rem;box-sizing:border-box;
  }
  .op-portal .topbar-right.topbar-right-periodo #themeToggle{margin-left:auto;}
  .op-portal .content{padding:16px 16px calc(88px + env(safe-area-inset-bottom));}
  .op-portal .card-h{flex-wrap:wrap;row-gap:10px;}
  .op-portal .cols2{grid-template-columns:1fr;}
  /* achado 2026-08-06: o 2x2 forçado nos 4 KPIs não ficou bom no celular —
     voltou ao formato anterior (Vendas/A receber seguem as regras genéricas
     de .kpis já existentes, sem override aqui). `.mobile-hide` é utilitário
     genérico (não só pros KPIs) pra esconder cards só no mobile, mantendo-os
     normais no desktop — Ticket médio/Taxa média e o card Minhas máquinas
     usam essa classe hoje. */
  .op-portal .mobile-hide{display:none;}
  .op-portal .antecip-banner{flex-direction:column;align-items:stretch;}
  .op-portal .antecip-banner .btn{width:100%;}
  .op-portal .card.fixed-h{height:auto;}
  .op-portal .card.fixed-h .scroll-area{max-height:280px;}
  .op-portal .topbar-logout-form{display:block;}

  .op-portal .bottom-nav{
    /* flex-direction/overflow-y explícitos: sem isso, o seletor genérico
       `nav{flex-direction:column;overflow-y:auto}` (da sidebar) "vaza" pra
       cá — mesmo elemento <nav>, e nenhuma dessas 2 propriedades era
       redeclarada aqui, então a regra menos específica vencia nelas
       (achado real, 2026-08-06: os 4 itens empilhavam verticais, cada um
       ocupando a largura toda, em vez de lado a lado). */
    display:flex;flex-direction:row;overflow-y:visible;
    position:fixed;left:0;right:0;bottom:0;z-index:30;
    background:linear-gradient(180deg,var(--sidebar-top),var(--sidebar-bot));
    border-top:1px solid var(--rule);
    padding:7px 4px calc(7px + env(safe-area-inset-bottom));
  }
  .op-portal .bottom-nav-item{
    flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;
    padding:6px 2px;border-radius:var(--radius);color:var(--ink-faint);
    font-family:var(--font-mono);font-size:0.6rem;letter-spacing:0.01em;
    text-align:center;transition:color .15s var(--ease);
  }
  .op-portal .bottom-nav-item svg{width:20px;height:20px;opacity:.85;}
  .op-portal .bottom-nav-item.active{color:var(--accent-text);}
  .op-portal .bottom-nav-item.active svg{opacity:1;}

  /* Vendas recentes (Home) e Extrato: tabela vira lista de cards — sem
     scroll lateral nenhum, cada venda em 3 linhas (ID+status, modalidade,
     valor→líquido+quando). `.tx-table-wrap` marca as 2 tabelas que recebem
     esse tratamento (ver home.html/extrato.html); outras tabelas do portal
     (ex.: Minhas máquinas) não têm essa classe e continuam como estão. */
  .op-portal .tx-table-wrap{display:none;}
  .op-portal .tx-cards{display:flex;flex-direction:column;gap:10px;}
  .op-portal .tx-card{
    background:linear-gradient(180deg,var(--card-top),var(--card-bot));
    border:1px solid var(--rule);border-radius:var(--radius);
    padding:12px 14px;display:flex;flex-direction:column;gap:7px;
  }
  .op-portal .tx-card-top{display:flex;align-items:center;justify-content:space-between;gap:10px;}
  .op-portal .tx-card-mod{display:flex;align-items:center;gap:6px;color:var(--ink-faint);font-size:0.78rem;}
  /* flex-wrap:wrap aqui — se "valor→líquido" e a data não couberem lado a
     lado (achado 2026-08-06: quebrava NO MEIO do "R$", ex. "R$" numa linha e
     "1.250,00" na de baixo, porque o item de flex encolhia o próprio texto),
     a data cai inteira pra linha de baixo — nunca quebra dentro do valor. */
  .op-portal .tx-card-bottom{display:flex;align-items:baseline;justify-content:space-between;gap:10px;flex-wrap:wrap;}
  .op-portal .tx-card-vals{
    display:flex;align-items:baseline;gap:7px;font-family:var(--font-mono);
    font-variant-numeric:tabular-nums;font-size:0.92rem;white-space:nowrap;
  }
  .op-portal .tx-card-vals .arrow{color:var(--ink-faint);font-size:0.8rem;}
  .op-portal .tx-card-vals .liquido{color:var(--accent-text);font-weight:600;}
  .op-portal .tx-card-quando{
    color:var(--ink-faint);font-family:var(--font-mono);font-size:0.72rem;
    white-space:nowrap;
  }

  /* filtros do Extrato (Status/Modalidade/De/Até): em 2 colunas (regra
     genérica de ≤720px), o <input type="date"> nativo do iOS não encolhe
     abaixo do próprio conteúdo mínimo — a coluna "Até" estourava a largura
     da tela (achado 2026-08-06, screenshot real). 1 coluna só no mobile do
     portal resolve, cada campo ocupa a largura toda (já é 100% por padrão). */
  .op-portal .filtros-grid{grid-template-columns:1fr;}
  .op-portal .filtros-grid .field.span2{grid-column:1/-1;}
}

/* ===== Utilitários gerados pro CSP (style-src sem 'unsafe-inline') =====
   Cada classe corresponde a um style="..." que existia direto no HTML.
   Ver web/security.py e a faxina de CSP (2026-08-24). Não são pensadas
   como sistema de utilitários geral — 1 classe por valor único que já
   existia, só pra sair do atributo style= inline. */
.u-as-center { align-self:center; }
.u-bc-accent-line { border-color:var(--accent-line); }
.u-bg-hex54c08a { background:#54c08a; }
.u-bg-hex7c4fd6 { background:#7c4fd6; }
.u-bg-warn { background:var(--warn); }
.u-c-accent-text { color:var(--accent-text); }
.u-c-accent-text_td-none { color:var(--accent-text); text-decoration:none; }
.u-c-accent-text_td-none_fs-0_85rem { color:var(--accent-text); text-decoration:none; font-size:0.85rem; }
.u-c-crit { color:var(--crit); }
.u-c-inherit_td-none { color:inherit; text-decoration:none; }
.u-c-ink { color:var(--ink); }
.u-c-ink-faint_fs-0_82rem_m-8px-0-0 { color:var(--ink-faint); font-size:0.82rem; margin:8px 0 0; }
.u-c-ink-faint_fs-0_8rem { color:var(--ink-faint); font-size:0.8rem; }
.u-c-ink-ghost_fs-0_74rem_ta-center_m-16px-0-0_ff-font-mono { color:var(--ink-ghost); font-size:0.74rem; text-align:center; margin:16px 0 0; font-family:var(--font-mono); }
.u-c-ink-soft_fs-0_85rem_m-0-0-22px { color:var(--ink-soft); font-size:0.85rem; margin:0 0 22px; }
.u-c-ink-soft_fs-0_9rem_m-0-0-22px { color:var(--ink-soft); font-size:0.9rem; margin:0 0 22px; }
.u-c-ok { color:var(--ok); }
.u-cur-pointer { cursor:pointer; }
.u-d-flex_ai-center_gap-12px { display:flex; align-items:center; gap:12px; }
.u-d-flex_ai-center_gap-8px_tt-none_ff-font-sans_fs-0_9rem_c-ink { display:flex; align-items:center; gap:8px; text-transform:none; font-family:var(--font-sans); font-size:0.9rem; color:var(--ink); }
.u-d-flex_fd-column_gap-2px_ai-flex-end_maxw-240px { display:flex; flex-direction:column; gap:2px; align-items:flex-end; max-width:240px; }
.u-d-flex_gap-4px { display:flex; gap:4px; }
.u-d-flex_gap-4px_jc-flex-end { display:flex; gap:4px; justify-content:flex-end; }
.u-d-flex_gap-6px { display:flex; gap:6px; }
.u-d-flex_gap-6px_jc-flex-end { display:flex; gap:6px; justify-content:flex-end; }
.u-d-flex_gap-6px_jc-flex-end_ai-center_flexwrap-wrap { display:flex; gap:6px; justify-content:flex-end; align-items:center; flex-wrap:wrap; }
.u-d-flex_gap-6px_jc-flex-end_ai-center_flexwrap-wrap_mt-6px { display:flex; gap:6px; justify-content:flex-end; align-items:center; flex-wrap:wrap; margin-top:6px; }
.u-d-flex_gap-6px_jc-flex-end_ai-start { display:flex; gap:6px; justify-content:flex-end; align-items:start; }
.u-d-flex_gap-6px_jc-flex-end_flexwrap-wrap { display:flex; gap:6px; justify-content:flex-end; flex-wrap:wrap; }
.u-d-flex_gap-8px_ai-center_flexwrap-wrap { display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
.u-d-flex_gap-8px_flexwrap-wrap_mt-neg4px { display:flex; gap:8px; flex-wrap:wrap; margin-top:-4px; }
.u-d-none { display:none; }
.u-fs-0_6rem { font-size:0.6rem; }
.u-fs-0_78rem { font-size:0.78rem; }
.u-fs-0_78rem_wb-break-all { font-size:0.78rem; word-break:break-all; }
.u-fs-1_1rem { font-size:1.1rem; }
.u-fs-1_2rem { font-size:1.2rem; }
.u-fs-1_3rem { font-size:1.3rem; }
.u-fs-1rem_c-ink-faint { font-size:1rem; color:var(--ink-faint); }
.u-gtc-2fr-2fr-1fr-1fr-auto_gap-10px_ai-end { grid-template-columns:2fr 2fr 1fr 1fr auto; gap:10px; align-items:end; }
.u-gtc-repeat-3-1fr { grid-template-columns:repeat(3,1fr); }
.u-gtc-repeat-4-1fr { grid-template-columns:repeat(4,1fr); }
.u-gtc-repeat-auto-fit-minmax-160px-1fr { grid-template-columns:repeat(auto-fit, minmax(160px,1fr)); }
.u-jc-center { justify-content:center; }
.u-jc-flex-end { justify-content:flex-end; }
.u-m-0 { margin:0; }
.u-m-0-0-12px { margin:0 0 12px; }
.u-m-0-0-18px { margin:0 0 18px; }
.u-m-0-0-22px { margin:0 0 22px; }
.u-m-0-0-6px { margin:0 0 6px; }
.u-m-0-0-8px { margin:0 0 8px; }
.u-m-0_fs-0_8rem { margin:0; font-size:0.8rem; }
.u-m-12px-0-0 { margin:12px 0 0; }
.u-m-6px-0-0 { margin:6px 0 0; }
.u-m-6px-0-0_pl-16px_ta-left { margin:6px 0 0; padding-left:16px; text-align:left; }
.u-m-8px-0 { margin:8px 0; }
.u-m-8px-0-0 { margin:8px 0 0; }
.u-m-8px-0-0_fs-0_8rem { margin:8px 0 0; font-size:0.8rem; }
.u-m-neg10px-0-16px { margin:-10px 0 16px; }
.u-m-neg6px-0-6px { margin:-6px 0 6px; }
.u-maxw-260px { max-width:260px; }
.u-maxw-280px_ow-break-word { max-width:280px; overflow-wrap:break-word; }
.u-maxw-440px_ta-center { max-width:440px; text-align:center; }
.u-maxw-560px { max-width:560px; }
.u-mb-10px { margin-bottom:10px; }
.u-mb-12px { margin-bottom:12px; }
.u-mb-16px { margin-bottom:16px; }
.u-mb-18px { margin-bottom:18px; }
.u-mb-8px { margin-bottom:8px; }
.u-minw-220px { min-width:220px; }
.u-minw-260px { min-width:260px; }
.u-ml-10px { margin-left:10px; }
.u-ml-6px { margin-left:6px; }
.u-ml-8px { margin-left:8px; }
.u-mt-10px { margin-top:10px; }
.u-mt-12px { margin-top:12px; }
.u-mt-14px { margin-top:14px; }
.u-mt-16px { margin-top:16px; }
.u-mt-18px_pt-14px_bt-1px-solid-rule { margin-top:18px; padding-top:14px; border-top:1px solid var(--rule); }
.u-mt-4px { margin-top:4px; }
.u-mt-6px { margin-top:6px; }
.u-mt-8px { margin-top:8px; }
.u-p-16px-20px_mb-16px { padding:16px 20px; margin-bottom:16px; }
.u-pb-8px { padding-bottom:8px; }
.u-pb-8px_mt-16px { padding-bottom:8px; margin-top:16px; }
.u-pt-0 { padding-top:0; }
.u-ta-center { text-align:center; }
.u-ta-left_d-inline-block { text-align:left; display:inline-block; }
.u-ta-right { text-align:right; }
.u-td-none { text-decoration:none; }
.u-td-underline { text-decoration:underline; }
.u-w-100pct { width:100%; }
.u-w-150px { width:150px; }
.u-w-64px_ta-right { width:64px; text-align:right; }
.u-w-auto { width:auto; }
.u-ws-pre-wrap_minw-220px { white-space:pre-wrap; min-width:220px; }

/* ===== Cores por modalidade (badges/donut) — CSP: era style="background:{{ }}"
   inline, agora classe fixa por modalidade (conjunto fechado, ver MODALIDADES
   em web/repository.py). "outro" é o mesmo cinza de fallback do Python
   quando a modalidade não bate com nenhuma conhecida. */
.mod-color-credito { background: #7c4fd6; }
.mod-color-credito_parcelado { background: #a486ea; }
.mod-color-pix { background: #54c08a; }
.mod-color-debito { background: #e0a83f; }
.mod-color-outro { background: #8b8b9e; }

/* filtro de período ativo (tela Relatórios) — era style condicional inline */
.mode-tag-active { border-color: var(--accent); color: var(--accent-text); }
