/* ============================================================================
   DESSEM · Mapa de intercâmbio (pages/dessem_mapa_intercambio.py) — o mapa vivo
   do SIN, o painel de análise e a fita do dia.

   Duas regras, e este arquivo inteiro sai delas:

   1. **Só tokens.** Nenhuma cor de tema hardcoded: tudo sai das variáveis de
      `00_tokens.css` (`--text`, `--card`, `--border`, `--accent`, …). O tema
      claro é `[data-bs-theme="light"]` (o escuro é o default do `:root`). As
      poucas exceções são a paleta Okabe-Ito (cega-friendly) das secções e dos
      estados de limite, que não existe no design system e por isso vira token
      local em `.mi-page` — declarada uma vez, usada por nome daqui para baixo.
   2. **Prefixos `mi-` / `mx-` / `mz-`.** Nada colide com outra página, então
      este arquivo pode carregar em qualquer ordem sem precisar de `!important`
      (o único aparece no bloco de `prefers-reduced-motion`, que precisa vencer
      a animação).

   Os três prefixos, e por que são três: `mi-` é o mapa (diagrama, inputs,
   fita), `mx-` é a camada "por que o limite é esse" e `mz-` são as abas e os
   modos cenário/período. Os nomes são os MESMOS do projeto de origem
   (`dash_preco/assets/css/mapa_intercambio.css`) de propósito: os módulos do
   motor portados em paralelo (`components/dessem_explicacao_limite.py`,
   `dessem_estresse_view.py`, `dessem_periodo_view.py`) continuam emitindo-os.

   O SVG do diagrama é desenhado por `assets/dessem_mapa_sin.js`, que não pinta
   nada em linha: toda cor de fio, seta, caixa e barra é resolvida por classe
   aqui. É o que permite o toggle claro/escuro funcionar sem redesenhar o mapa.
   ============================================================================ */

/* ---------------------------------------------------------------- tokens */
/* Paleta Okabe-Ito: as três secções e os estados de carregamento precisam ser
   distinguíveis por quem não separa vermelho de verde — o alarme nunca é só
   "ficou vermelho", vem sempre com borda mais grossa e barra cheia junto.

   Os valores do BLOCO PADRÃO são os do tema ESCURO (o default do dash): no
   fundo escuro o laranja e o azul do Okabe-Ito original ficam abafados, e as
   versões claras da mesma família mantêm a distinção com contraste. */
.mi-page {
  /* Razão entre a largura do DESENHO (1020) e a do viewBox (1180, que inclui
     a margem do bloco do NE). O CSS não lê o spec, então os três números que
     dependem dela — os dois coeficientes `cqi` da fonte dos inputs e o
     `min-width` do wrapper — trazem a conta no comentário e devem ser
     refeitos junto se VIEWBOX mudar (ver `data/dessem_intercambio.py`).
     0,864 = 1020/1180. */
  --mi-ok: var(--accent);
  --mi-bad: #FF8442;
  --mi-warn: #E69F00;
  /* Okabe-Ito. ⚠️ --mi-cut1 NÃO pode repetir --mi-warn (#E69F00): a barra de
     carga em atenção e o arco da secção EXP_NE dividiam o mesmo diagrama com a
     mesma cor. O azul abaixo estava livre desde que o sistema de status saiu. */
  --mi-cut1: #56B4E9;
  --mi-cut2: #CC79A7;
  --mi-cut3: #009E73;
  /* Faixa «perto» da fita (≥ 95 %): entre o âmbar de atenção e o laranja de
     «no limite», para a escada ≥80 % → ≥95 % → limite se ler como escada. */
  --mi-perto: #E8730C;
  --mi-wire: var(--quiet);
  padding-bottom: var(--sp-8);
}

/* No tema claro voltam os tons cheios do Okabe-Ito: sobre painel branco o
   laranja claro e o azul claro perdem contraste — e o âmbar (#E69F00, ~2,3:1
   sobre branco) é cor de TEXTO em avisos e no estado «suspeito», então também
   escurece, junto com o «perto» da fita. */
[data-bs-theme="light"] .mi-page {
  --mi-bad: #D55E00;
  --mi-warn: #A66A00;
  --mi-perto: #BF5A00;
  --mi-cut1: #0072B2;
}

/* ------------------------------------------------------------- estrutura */
/* O diagrama tem largura mínima real: abaixo de ~720 px de wrapper a fonte
   dos inputs bate no piso do `clamp` enquanto a caixa continua encolhendo, e
   o número passa a estourar a caixa. Em vez de encolher até virar sopa, o
   CARD rola na horizontal — a página nunca rola para o lado.
   (Eram 620 px enquanto o viewBox tinha 1020 de largura; com 1180 é preciso
   mais wrapper para o DESENHO ter o mesmo tamanho — 620 × 1180/1020.) */
.mi-scroll { overflow-x: auto; }

/* Wrapper do diagrama. A razão (aspect-ratio) vem inline do Python
   (`aspect_ratio_css()`), da MESMA fonte que o viewBox do SVG — é o que
   garante que os inputs, posicionados em % daqui, caiam dentro das caixas.
   `container-type: inline-size` existe para os inputs medirem a fonte em
   `cqi`: eles precisam encolher com o diagrama, não com a janela. */
.mi-wrap {
  position: relative;
  width: 100%;
  /* 1100 e não 900: o viewBox ganhou 160 unidades de margem à direita (o
     bloco do NE) e sem alargar o wrapper o desenho encolheria 14%. */
  max-width: 1100px;
  min-width: 720px;
  margin: 0 auto;
  container-type: inline-size;
}
.mi-host { position: absolute; inset: 0; }
.mi-svg { width: 100%; height: 100%; display: block; }

/* ------------------------------------------------------- fios e fluxo */
.mi-wire {
  fill: none; stroke: var(--mi-wire); stroke-width: 3;
  stroke-linecap: round; stroke-linejoin: round;
}

/* Tracejado que corre no sentido real do fluxo. É a única informação da tela
   que não depende de ler número nenhum. */
.mi-flow {
  fill: none; stroke: var(--mi-ok); stroke-width: 3.2;
  stroke-linecap: round; stroke-dasharray: 7 12;
  opacity: .95; pointer-events: none;
}
.mi-flow.fwd { animation: mi-flowF 1.05s linear infinite; }
.mi-flow.rev { animation: mi-flowR 1.05s linear infinite; }
.mi-flow.off { display: none; }
.mi-flow.is-bad { stroke: var(--mi-bad); }
@keyframes mi-flowF { to { stroke-dashoffset: -38; } }
@keyframes mi-flowR { to { stroke-dashoffset: 38; } }

.mi-arrow { fill: var(--mi-ok); stroke: none; }
.mi-arrow.is-bad { fill: var(--mi-bad); }

/* ------------------------------------------------------------------ nós */
.mi-node { fill: var(--well); stroke: var(--mi-wire); stroke-width: 1.6; }
.mi-node-name {
  font-size: 27px; font-weight: 700; fill: var(--text); text-anchor: middle;
}
.mi-node-cmo {
  font-size: 18px; font-weight: 600; fill: var(--mi-ok); text-anchor: middle;
  font-variant-numeric: tabular-nums;
}
.mi-node-unit {
  font-size: 10px; font-weight: 600; letter-spacing: .08em;
  fill: var(--text-dim); text-anchor: middle;
}
.mi-dot { fill: var(--text); }
.mi-dot-label { font-size: 14px; font-weight: 600; fill: var(--text-dim); }
.mi-hz { font-size: 13px; font-weight: 600; fill: var(--text); }
.mi-conv-linha { stroke: var(--mi-wire); stroke-width: 1.4; stroke-dasharray: 5 5; }

/* --------------------------------------------------------------- caixas */
.mi-box-bg { fill: var(--card); stroke: var(--border); stroke-width: 1.2; }
.mi-box-lbl {
  font-size: 12.5px; font-weight: 600; letter-spacing: .05em; fill: var(--text);
}
.mi-box-unit {
  font-size: 10px; font-weight: 600; letter-spacing: .06em; fill: var(--quiet);
}
.mi-box-note { font-size: 9px; font-weight: 500; fill: var(--text-dim); }

/* Caixa compacta (fluxo sem limite, como Itaipu): o rótulo tem a largura toda
   para si, mas são só 80 px úteis — "ITAIPU 50 HZ" a 12,5 px não cabe. A
   unidade divide a faixa de baixo com a borda da caixa; 9 px é o que cabe
   entre o pé do input e o fundo. */
.mi-box-simples .mi-box-lbl { font-size: 10.5px; }
.mi-box-simples .mi-box-unit { font-size: 9px; }

/* Barra de carregamento |fluxo| / |limite|. */
.mi-track { fill: var(--border); }
.mi-bar { fill: var(--mi-ok); }
.mi-bar.warn { fill: var(--mi-warn); }
.mi-bar.bad { fill: var(--mi-bad); }

/* -------------------------------------------------------------- secções */
.mi-cut-arc {
  fill: none; stroke-width: 2.4; stroke-linecap: round;
  /* stroke-dasharray vem do spec (`traco`): cada secção tem o seu, para que
     dois arcos que se cruzam continuem separáveis em preto e branco. */
}
.mi-cut .mi-box-bg { stroke-dasharray: 6 4; stroke-width: 1.4; }
.mi-cut-1 .mi-cut-arc, .mi-cut-1 .mi-box-bg { stroke: var(--mi-cut1); }
.mi-cut-2 .mi-cut-arc, .mi-cut-2 .mi-box-bg { stroke: var(--mi-cut2); }
.mi-cut-3 .mi-cut-arc, .mi-cut-3 .mi-box-bg { stroke: var(--mi-cut3); }
/* Numa secção, a cor do arco manda no rótulo — é ela que amarra a caixa ao
   traço lá no diagrama. */
.mi-cut-1 .mi-box-lbl { fill: var(--mi-cut1); }
.mi-cut-2 .mi-box-lbl { fill: var(--mi-cut2); }
.mi-cut-3 .mi-box-lbl { fill: var(--mi-cut3); }

/* Alarme de limite por último: vence a cor da secção, porque é o estado mais
   urgente da caixa. */
.at-lim .mi-box-bg { stroke: var(--mi-bad); stroke-width: 1.8; stroke-dasharray: none; }

/* Toggle das secções: o JS devolve `mi-hide-<id>` no className do wrapper e
   uma classe só apaga o arco, a caixa e os dois inputs da secção. */
.mi-hide-exp_ne .mi-cut[data-sec="exp_ne"],
.mi-hide-exp_ne .mi-in[data-sec="exp_ne"],
.mi-hide-fns_fnese .mi-cut[data-sec="fns_fnese"],
.mi-hide-fns_fnese .mi-in[data-sec="fns_fnese"],
.mi-hide-imp_seco .mi-cut[data-sec="imp_seco"],
.mi-hide-imp_seco .mi-in[data-sec="imp_seco"] { display: none; }

/* ------------------------------------------------------ inputs por cima */
/* Os números das caixas são `dcc.Input` HTML posicionados em % sobre o SVG
   (Python: `posicao_input_pct`), e não texto SVG: é o que mantém a edição
   what-if com teclado, foco e acessibilidade nativos. */
.mi-in {
  position: absolute;
  margin: 0;
  padding: 0;
  display: block;
}
/* Dash 4 embrulha o input em `div.dash-input-container`. As duas formas
   precisam preencher o label. */
.mi-in .dash-input-container,
.mi-in input {
  width: 100%;
  height: 100%;
  display: block;
}
/* ⚠️ O wrapper do Dash 4 traz `container-type: inline-size` embutido no bundle
   do dcc. Isso o torna o container de consulta mais próximo, e as medidas em
   `cqi` do input passam a se referir aos ~97 px da caixinha em vez dos 900 px
   do `.mi-wrap`: `clamp(10px, 1.9cqi, 16px)` desabava no piso de 10 px (e o
   limite, em 9 px). Medido em 16/09/2026 no projeto de origem — Dash 4.0.0
   dava 10/9 px onde o 3.2.0 dá 16/11 px; aqui o dash é 4.1.0 e o wrapper é o
   mesmo. `normal` devolve a consulta ao wrapper certo.
   A borda e o fundo do wrapper também precisam sumir: eles desenhavam uma
   segunda moldura sobre a do `<input>`. */
.mi-in .dash-input-container {
  container-type: normal;
  border: 0;
  background: none;
  padding: 0;
}
.mi-in input {
  box-sizing: border-box;
  min-width: 0;
  padding: 0 3px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--card);
  color: var(--text);
  /* A mesma pilha monoespaçada de `10_app.css` (.mono/code): o número da
     caixa é para ser comparado com o da caixa vizinha, e fonte proporcional
     desalinha a coluna de milhar. */
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-weight: 600;
  text-align: center;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  /* Fallback para navegador sem container queries; a linha seguinte manda onde
     `cqi` existe, para a fonte acompanhar o diagrama e não a janela. */
  /* Os coeficientes caíram 1020/1180 quando o viewBox ganhou a margem do
     bloco do NE: `cqi` mede o wrapper, mas a caixa que precisa caber mede em
     unidades do viewBox — sem isso a fonte deixava de encolher junto com o
     desenho e o número estourava a caixa nas larguras pequenas. */
  font-size: clamp(10px, 1.8vw, 16px);
  font-size: clamp(10px, 1.64cqi, 16px);
}
.mi-in input:hover { border-color: var(--text-dim); }
.mi-in input:focus,
.mi-in input:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-glow);
}
/* Limite: menor e apagado — é teto, não medição. */
.mi-in-lim input {
  color: var(--text-dim);
  font-weight: 500;
  font-size: clamp(9px, 1.33vw, 11px);
  font-size: clamp(9px, 1.21cqi, 11px);
}
/* Campo manual: mesmo preenchimento da caixa tracejada do SVG que ele cobre —
   um relance basta para ver que ali não há dado de rodada por trás. */
.mi-in-manual input { background: var(--well); }

/* |fluxo| ≥ |limite|: os dois inputs do par acendem juntos, junto com a borda
   da caixa e a barra cheia — três sinais, nenhum deles só cor. */
.mi-in.is-bad input {
  color: var(--mi-bad);
  border-color: var(--mi-bad);
}
/* Valor que não é mais o da rodada. Tracejado sutil, sem cor: "editado" não é
   erro, é cenário. */
.mi-in.is-editado input { border-style: dashed; }

/* Rótulo acessível de cada input (o leitor de tela precisa saber qual caixa é;
   na tela, quem diz isso é o rótulo desenhado no SVG). O Bootstrap já traz
   `.visually-hidden`; a cópia escopada aqui garante a página mesmo se a folha
   dele mudar de nome — o custo é uma regra. */
.mi-page .visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --------------------------------------------- transporte do tempo (IPER) */
.mi-campo-tempo { flex: 1 1 340px; min-width: 260px; }
.mi-tempo { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.mi-tempo .mi-slider { flex: 1 1 140px; min-width: 110px; }
.mi-transp {
  width: 32px; height: 32px; border-radius: var(--r-md); flex: none;
  border: 1px solid var(--border); background: var(--well);
  color: var(--text); cursor: pointer;
  display: flex; align-items: center; justify-content: center; font-size: 13px;
}
.mi-transp:hover { background: var(--card-hover); border-color: var(--text-dim); }
.mi-transp.is-on {
  background: var(--accent); color: var(--accent-fg); border-color: var(--accent);
}
.mi-relogio {
  font-size: 15px; font-weight: 700; color: var(--text);
  min-width: 118px; text-align: center; font-variant-numeric: tabular-nums;
}

.mi-page .mi-slider .rc-slider-rail { background: var(--border); }
.mi-page .mi-slider .rc-slider-track { background: var(--accent); }
.mi-page .mi-slider .rc-slider-handle {
  border-color: var(--accent);
  background: var(--accent);
  opacity: 1;
}
.mi-page .mi-slider .rc-slider-dot-active { border-color: var(--accent); }
.mi-page .mi-slider .rc-slider-mark-text { color: var(--text-dim); font-size: var(--fs-xs); }
.mi-page .mi-slider .rc-slider-mark-text-active { color: var(--text); }

/* Bootstrap zera a margem de `figure`, mas a página não deve depender disso:
   o diagrama é o herói e não pode ganhar recuo de 40 px se a folha mudar. */
.mi-figure { margin: 0; }

/* ------------------------------------------------------- avisos e notas */
.mi-avisos:empty { display: none; }
.mi-aviso {
  display: block; margin: 0 0 var(--sp-2);
  border-left: 3px solid var(--mi-warn); background: var(--well);
  padding: var(--sp-2) var(--sp-3); border-radius: 0 var(--r-md) var(--r-md) 0;
  font-size: var(--fs-sm); color: var(--text);
}
.mi-aviso-tit { margin-right: 6px; }
.mi-aviso-txt { color: var(--text-dim); }
.mi-dica { color: var(--quiet); font-size: var(--fs-xs); }

/* Nota de rodapé de card/painel. Uma classe só, porque a origem tinha duas
   (`theme-note` global e as locais) e as duas queriam dizer o mesmo. */
.mi-nota { color: var(--text-dim); font-size: var(--fs-sm); margin: var(--sp-2) 0; }

/* ------------------------------------------------------ lista de secções */
/* Coluna estreita ao lado do diagrama, sem card. O dcc.Checklist embrulha
   opção por opção num `<label>` próprio (checkbox + rótulo). O label é um grid
   `auto 1fr`: o rótulo estica por ser a 2ª coluna, sem seletor que dependa de
   como o Dash embrulha o conteúdo por dentro. A linha quebra (`flex-wrap`): o
   nome por extenso ocupa a linha de baixo e o valor desce se a coluna aperta. */
.mi-sec { padding-top: var(--sp-2); }
.mi-sec-titulo {
  font-size: var(--fs-xs); font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--quiet); margin-bottom: 2px;
}
.mi-sec-list > label {
  display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start;
}
.mi-sec-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0 6px;
  padding: 5px 0;
}
.mi-sec-list > label + label { border-top: 1px solid var(--border); }
.mi-sec-nome { font-size: 11.5px; font-weight: 600; letter-spacing: .03em; }
.mi-sec-valor {
  margin-left: auto; font-size: 11.5px; color: var(--text-dim);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.mi-sec-desc { flex-basis: 100%; font-size: 10.5px; color: var(--quiet); }
.mi-sec-check { accent-color: var(--accent); margin: 8px 6px 0 0; }
.mi-sec-nota { font-size: 10.5px; color: var(--quiet); margin: var(--sp-2) 0 0; }

/* --------------------------------------------- balanço ao lado do nó */
/* Carga e geração do subsistema, no overlay, sobre o espaço vazio vizinho do
   seu nó (as posições vêm do spec, em % do wrapper). Sem moldura e em cinza:
   é anotação do mapa, não mais uma caixa editável — o que tem borda ali é o
   que se pode digitar. A fonte mede em `cqi` pelo mesmo motivo dos inputs:
   encolhe com o diagrama, não com a janela. */
.mi-bal {
  position: absolute;
  margin: 0;
  display: flex; flex-direction: column; justify-content: center;
  font-size: clamp(7px, 1.12cqi, 12px);
  /* 1,3 e não 1,4: com as 7 fontes dentro, 15 linhas a 1,4 passavam dos 240
     pontos de altura da caixa e a última linha do bloco do S vazava a borda
     de baixo do SVG. */
  line-height: 1.3;
  /* sem `pointer-events: none`: o número é para poder ser selecionado e
     copiado, e o clique no vazio do SVG não faz nada de todo modo. */
}
.mi-bal-tit {
  border-bottom: 1px solid var(--border); padding-bottom: 1px; margin-bottom: 2px;
  font-weight: 700; color: var(--text); letter-spacing: .04em;
}
.mi-bal-row { display: flex; align-items: baseline; gap: 6px; }
.mi-bal-k { color: var(--quiet); white-space: nowrap; }
/* A abertura por fonte é a conta da linha "Renov." logo acima: recuo e corpo
   menor dizem isso sem precisar de um cabeçalho de grupo, que custaria uma
   linha inteira nos 240 pontos de altura que o bloco tem. */
.mi-bal-grupo { display: contents; }
.mi-bal-sub { font-size: .8em; }
.mi-bal-sub .mi-bal-k { padding-left: 1em; }
/* A unidade fica numa coluna própria, à direita: sem isso os números perdiam
   o alinhamento de milhar quando uma linha (a EAR) não tem unidade. */
.mi-bal-v {
  margin: 0 0 0 auto; display: flex; align-items: baseline; gap: 3px;
  color: var(--text-dim); font-weight: 600;
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.mi-bal-un {
  flex: none; width: 1.6em;
  font-family: inherit; font-size: .8em; font-weight: 500; color: var(--quiet);
}

.mi-sw { width: 10px; height: 10px; border-radius: 3px; flex: none; display: inline-block; }
.mi-sw-1 { background: var(--mi-cut1); }
.mi-sw-2 { background: var(--mi-cut2); }
.mi-sw-3 { background: var(--mi-cut3); }

/* ------------------------------------------------------------- legenda */
.mi-legend {
  display: flex; flex-wrap: wrap; gap: 6px 18px;
  padding: 10px 6px 4px; color: var(--text-dim); font-size: 11.5px;
}
.mi-legend span { display: inline-flex; align-items: center; gap: 6px; }
.mi-legend .mi-sw-bad { background: var(--mi-bad); }

/* ------------------------------------------------------------ respostas */
@media (prefers-reduced-motion: reduce) {
  /* Sem a corrida do tracejado o sentido continua legível pela seta; a opacidade
     menor evita que a linha estática compita com o fio de baixo. */
  .mi-flow { animation: none !important; opacity: .45; }
}

/* --------------------------------------------------------------- fita do dia */
/* As 48 meias-horas de cada elemento com limite, lado a lado. O diagrama diz
   ONDE; a fita diz QUANDO. Duas leituras da mesma verdade, do mesmo store.

   Dois canais de propósito: a ALTURA da barra é |fluxo| ÷ |limite| (contínua,
   legível em preto e branco) e a COR marca as faixas. Quem não separa vermelho
   de laranja continua lendo a fita pela altura. */
.mi-fita-wrap { overflow-x: auto; padding: 2px 0 6px; }
.mi-fita-wrap:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.mi-fita {
  width: 100%; min-width: 620px;
  table-layout: fixed; border-collapse: collapse;
}
.mi-fita-rot {
  width: 116px; text-align: right; padding-right: 8px;
  font-size: 11px; font-weight: 600; color: var(--text-dim);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
/* Título de submercado: separa os blocos sem virar linha de dado — não tem
   célula, então o JS (que varre `[data-dono]`) passa reto por ela. */
.mi-fita-grupo {
  text-align: left; padding: 7px 0 2px;
  font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--quiet); border-bottom: 1px solid var(--border);
}
.mi-fita-grupo-tr:first-child .mi-fita-grupo { padding-top: 2px; }
.mi-fita-hora {
  height: 14px; font-size: 9.5px; font-weight: 600; color: var(--quiet);
  text-align: left; padding: 0; font-variant-numeric: tabular-nums;
}
.mi-fita-cel {
  height: 15px; padding: 0;
  border-left: 1px solid var(--card);
  /* A barra cresce de baixo para cima; --f vem do JS, entre 0 e 1. */
  background:
    linear-gradient(to top, currentColor calc(var(--f, 0) * 100%), transparent 0)
    no-repeat;
  color: var(--border);
  cursor: pointer;
}
.mi-fita-cel.aten  { color: var(--mi-warn); }
.mi-fita-cel.perto { color: var(--mi-perto); }
/* No limite ganha contorno além da cor: é o único estado que exige ação, e não
   pode depender de o leitor distinguir dois tons de laranja. */
.mi-fita-cel.at-lim {
  color: var(--mi-bad);
  box-shadow: inset 0 0 0 1px var(--mi-bad);
}
.mi-fita-cel.sem-dado {
  background: repeating-linear-gradient(45deg, transparent 0 3px, var(--border) 3px 4px);
  cursor: default;
}
/* A meia-hora que o diagrama está mostrando. */
.mi-fita-cel.is-agora { border-left-color: var(--accent); }
.mi-fita tbody tr:hover .mi-fita-cel { background-color: var(--well); }

.mi-fita-legenda { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; }
.mi-fita-legenda span { display: inline-flex; align-items: center; gap: 5px; }
.mi-fita-sw {
  width: 9px; height: 11px; flex: none; display: inline-block; border-radius: 2px;
}
.mi-fita-sw.aten   { background: var(--mi-warn); }
.mi-fita-sw.perto  { background: var(--mi-perto); }
.mi-fita-sw.at-lim { background: var(--mi-bad); box-shadow: inset 0 0 0 1px var(--mi-bad); }

@media (prefers-reduced-motion: reduce) {
  .mi-fita tbody tr:hover .mi-fita-cel { background-color: transparent; }
}

/* ------------------------------------------------- KPI e tabelas da página */
/* A tira de KPI e as tabelas do painel são locais porque o conteúdo delas é
   escrito pelo CLIENTSIDE célula a célula (`data-mx` / `data-mz` /
   `data-mapa-cel`): um `dash_table.DataTable` não deixa o navegador reescrever
   uma célula sem refazer a tabela inteira, que é justamente o que o scrub não
   pode pagar. */
.mx-kpis {
  display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-5);
  margin: var(--sp-2) 0 0;
}
.mx-kpi .v {
  font-size: var(--fs-xl); font-weight: 700; color: var(--text-strong);
  line-height: 1.1; font-variant-numeric: tabular-nums;
}
.mx-kpi .v small { font-size: var(--fs-xs); font-weight: 500; color: var(--text-dim); }
.mx-kpi .k { font-size: var(--fs-xs); color: var(--text-dim); margin-top: 2px; }

.mx-tablewrap { overflow-x: auto; margin: var(--sp-2) 0; }
.mx-table table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.mx-table th, .mx-table td {
  padding: 5px 8px; border-bottom: 1px solid var(--border-soft);
  text-align: left; white-space: nowrap;
}
.mx-table thead th {
  color: var(--text-dim); font-weight: 600; font-size: var(--fs-xs);
  text-transform: uppercase; letter-spacing: .04em;
  border-bottom: 1px solid var(--border);
}
.mx-table tbody td { font-variant-numeric: tabular-nums; }
.mx-table tbody tr:hover { background: var(--well); }

/* ═══════════════════════════════════════════ camada "por que o limite é esse"

   Prefixo `mx-`. O elemento memorável desta camada é UM: a memória de cálculo
   (`.mx-ledger`), que é lida como um livro-razão — coluna de contribuição
   alinhada, régua antes do total, o total confrontado com o que o DESSEM
   gravou. Todo o resto (gráficos, tabelas de definição) é deliberadamente
   quieto, senão a conta deixa de ser o centro.                               */

/* Caixa do diagrama que tem restrição explicável: só o cursor muda, porque a
   caixa já carrega cor demais (secção, limite, carregamento). */
.mi-box-explica { cursor: pointer; }
.mi-box-explica:hover .mi-box-bg { stroke-width: 2; }
.mi-box.is-foco .mi-box-bg {
  stroke: var(--accent); stroke-width: 2.4; stroke-dasharray: none;
}

/* ------------------------------------------------------------ a barra/gate */
.mx-painel { padding: 0; overflow: hidden; }
.mx-bar {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  width: 100%; padding: 14px 18px; border: 0; background: transparent;
  color: var(--text); text-align: left; cursor: pointer;
}
.mx-bar:hover { background: var(--well); }
.mx-bar:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.mx-bar-titulo { font-size: var(--fs-lg); font-weight: 650; }
.mx-bar-sub { color: var(--text-dim); font-size: 12.5px; }
.mx-seta {
  color: var(--accent); transition: transform var(--t-base) var(--ease);
  display: inline-block;
}
.mx-bar.is-aberta .mx-seta { transform: rotate(180deg); }

/* ------------------------------------------------------------ os 11 chips */
.mx-chips-wrap {
  padding: 12px 18px 10px; border-top: 1px solid var(--border);
}
.mx-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; }
.mx-chip {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 5px 11px; border-radius: var(--r-pill); cursor: pointer;
  border: 1px solid var(--border); background: var(--card);
  color: var(--text-dim); font-size: 12.5px; line-height: 1.2;
}
.mx-chip:hover { border-color: var(--accent); color: var(--text); }
.mx-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.mx-chip-nome { font-weight: 600; letter-spacing: .01em; }
.mx-chip-re { font-variant-numeric: tabular-nums; opacity: .8; }
.mx-chip.is-foco {
  border-color: var(--accent); color: var(--text);
  background: var(--accent-soft); font-weight: 600;
}
/* Fonte do limite: um traço à esquerda, porque "de onde vem o limite" é a
   primeira coisa que muda a leitura — e três das onze não têm fórmula. */
.mx-chip[data-mx-fonte="RSTTAB"] { border-left: 3px solid var(--mi-cut2); }
.mx-chip[data-mx-fonte="FIXO"]   { border-left: 3px solid var(--quiet); }

/* --------------------------------------------------------------- o corpo */
.mx-corpo-in { padding: 4px 18px 18px; }
.mx-foco { margin-bottom: 10px; }
.mx-foco-tit { margin-bottom: 2px; font-size: var(--fs-lg); font-weight: 650; }
.mx-foco-tit small { font-family: inherit; font-size: 13px; color: var(--text-dim); }
.mx-foco-nota { color: var(--text-dim); font-size: 13px; max-width: 74ch; margin: 0; }
.mx-aviso {
  border-left: 3px solid var(--mi-warn); background: var(--well);
  padding: 8px 12px; border-radius: 0 var(--r-md) var(--r-md) 0;
  font-size: 13px; margin: 8px 0;
}
.mx-topo { margin: 12px 0 4px; }
.mx-kpi-estado .v { font-size: 20px; }
.mx-linha { margin-left: 0; margin-right: 0; }
.mx-graf { width: 100%; }

/* ------------------------------------------------- o livro-razão da conta */
.mx-bloco {
  border: 1px solid var(--border); border-radius: var(--r-2xl);
  padding: 12px 14px; background: var(--card);
}
.mx-bloco + .mx-bloco { margin-top: 12px; }
/* Quem manda na meia-hora ganha a borda do acento. Numa RE com duas LPPs as
   duas contas ficam na tela — o que vale é a de MENOR limite, e ver a
   perdedora ao lado é o que torna a regra do mínimo visível. */
.mx-bloco.is-manda { border-color: var(--accent); }
.mx-bloco:not(.is-manda) { opacity: .62; }
.mx-bloco-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.mx-bloco-tit { font-size: 15px; margin: 0; }
.mx-bloco-tit small { font-family: inherit; color: var(--text-dim); font-size: 12.5px; }
.mx-manda {
  display: none; font-size: 11px; letter-spacing: .03em;
  color: var(--accent); border: 1px solid currentColor;
  border-radius: var(--r-pill); padding: 1px 8px;
}
.mx-bloco.is-manda .mx-manda { display: inline-block; }
.mx-eq { font-size: 14px; margin: 8px 0 2px; }
.mx-eq-resto { color: var(--text-dim); }
.mx-coeflin { font-size: 15px; font-weight: 600; }
.mx-curva { font-size: 12.5px; color: var(--text-dim); margin-bottom: 8px; }
.mx-eq-nota { display: block; font-size: 11.5px; }
.mx-chipnum {
  background: var(--well); border-radius: var(--r-sm); padding: 0 6px;
  color: var(--text);
}
.mx-val { font-variant-numeric: tabular-nums; }
.mx-ledger table { font-size: 13px; }
.mx-ledger td, .mx-ledger tfoot th { text-align: right; }
.mx-ledger tbody th, .mx-ledger thead th:first-child { text-align: left; }
.mx-ledger thead th:not(:first-child) { text-align: right; }
.mx-ledger tfoot th { text-align: left; }
.mx-tr-total th, .mx-tr-total td { border-top: 2px solid var(--text); }
.mx-total { font-size: 15px; font-weight: 700; }
.mx-delta { color: var(--text-dim); margin-left: 10px; }
.mx-vazio { color: var(--text-dim); text-align: left; font-style: italic; }

/* ------------------------------------------------------- blocos fechados */
.mx-det {
  border: 1px solid var(--border); border-radius: var(--r-2xl);
  margin-top: 14px; background: var(--card);
}
.mx-det > summary {
  padding: 11px 14px; cursor: pointer; font-weight: 600;
  list-style-position: inside;
}
.mx-det > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.mx-sum-sub { font-weight: 400; color: var(--text-dim); }
.mx-det-corpo { padding: 0 14px 14px; }
.mx-def-bloco + .mx-def-bloco { margin-top: 16px; }
.mx-def-tit { font-size: 14px; margin: 10px 0 4px; }
.mx-def-tit small { font-family: inherit; color: var(--text-dim); font-weight: 400; }
.mx-det table { font-size: 12.5px; }
.mx-criterios .mx-num { text-align: right; font-variant-numeric: tabular-nums; }
/* A coluna do critério primário é a que se lê primeiro; a do preço-sombra fica
   ao lado como diagnóstico, não como segunda verdade. */
.mx-criterios .mx-primario { font-weight: 700; }
.mx-rodape { margin-top: 12px; }

@media (max-width: 720px) {
  .mx-corpo-in { padding: 4px 12px 14px; }
  .mx-chips-wrap { padding-left: 12px; padding-right: 12px; }
  .mx-bar { padding: 12px; }
}
@media (prefers-reduced-motion: reduce) {
  .mx-seta { transition: none !important; }
}

/* A frase derivada do deck, logo abaixo da nota fixa da restrição. Fica mais
   discreta de propósito: a nota diz o que a restrição É, esta diz o que ESTE
   caso faz — e os números dela mudam de deck para deck. */
.mx-foco-deck {
  margin: 2px 0 0; font-size: 12px; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

/* ============================================================================
   Modos do painel: cenário e período — prefixo `mz-`.

   Três perguntas sobre o MESMO sujeito (a restrição escolhida nos chips `mx-`),
   e por isso abas e não secções novas: ver `components/dessem_mapa_modos.py`. A
   troca de aba é só classe — os três corpos ficam no DOM, então voltar não
   redesenha figura nenhuma.
   ============================================================================ */

/* ------------------------------------------------------------------- abas */
.mz-abas {
  display: flex; flex-wrap: wrap; gap: 4px;
  padding: 0 18px; border-bottom: 1px solid var(--border);
}
.mz-aba {
  display: flex; flex-direction: column; gap: 1px;
  padding: 9px 14px 8px; border: 0; border-bottom: 2px solid transparent;
  background: transparent; color: var(--text-dim); cursor: pointer;
  text-align: left; border-radius: var(--r-md) var(--r-md) 0 0;
}
.mz-aba:hover { background: var(--well); color: var(--text); }
.mz-aba:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.mz-aba.is-on {
  color: var(--text); border-bottom-color: var(--accent);
  background: var(--well);
}
.mz-aba-tit { font-weight: 600; font-size: 14px; }
.mz-aba-sub { font-size: 11.5px; color: var(--text-dim); }

/* Corpo de cada modo. `display:none` e não `visibility`: um Plotly escondido
   por visibilidade continua medindo largura errada ao reaparecer, e a figura
   sairia estreita até alguém mexer na janela. */
.mz-modo { display: none; }
.mz-modo.is-on { display: block; }
.mz-linha { margin: 0; padding: 14px 6px 4px; }
.mz-corpo { padding: 0 12px 14px; }

/* -------------------------------------------------------------- controles */
.mz-controles { padding: 4px 12px 8px; }
.mz-sub { font-size: 14px; margin: 0 0 6px; }
.mz-campo { margin-bottom: 14px; }
.mz-radio { display: flex; flex-direction: column; gap: 6px; font-size: 13px; }
.mz-radio label { display: flex; align-items: flex-start; gap: 7px; cursor: pointer; }
.mz-radio-in { margin-top: 3px; accent-color: var(--accent); }

/* --------------------------------------------------- formulário do cenário */
.mz-form { list-style: none; padding: 0; margin: 0 0 8px; }
.mz-ch-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 0 8px 10px; border-top: 1px solid var(--border);
}
.mz-ch { display: flex; flex-direction: column; gap: 0; min-width: 0; }
.mz-ch-nome { font-weight: 600; font-size: 13px; font-variant-numeric: tabular-nums; }
.mz-ch-papel { color: var(--text-dim); font-size: 11px; }
.mz-ch-faixa { color: var(--text-dim); font-size: 11px; font-variant-numeric: tabular-nums; }
.mz-ch-in { display: flex; align-items: baseline; gap: 5px; flex: 0 0 auto; }
/* Em Dash 4 o `dcc.Input` cai dentro de um `div.dash-input-container` que é ele
   próprio um flex, e é ESSE div que precisa da largura: mandar 92 px no
   `<input>` deixava uma caixa de 36 px para digitar, porque o input encolhia
   como item de flex do wrapper. Mesma armadilha do `.mi-in input` do diagrama. */
.mz-ch-in > div { flex: 0 0 92px; width: 92px; }
.mz-ch-in input {
  width: 100%; padding: 5px 8px; text-align: right;
  font-variant-numeric: tabular-nums; font-size: 13px;
  border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--card); color: var(--text);
}
.mz-ch-in input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.mz-ch-un { color: var(--text-dim); font-size: 11px; white-space: nowrap; }
/* A linha de PARAM é a que troca a curva — é o efeito que o modo existe para
   mostrar, e por isso ela se destaca das linhas de controlador. */
.mz-ch-row.is-param { border-left: 3px solid var(--mi-cut2); padding-left: 7px; }

/* ------------------------------------------------- o recorte da meia-hora */
.mz-agora-wrap {
  border: 1px solid var(--border); border-radius: var(--r-2xl);
  padding: 10px 12px 4px; margin: 12px 0 4px; background: var(--card);
}
.mz-agora { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; }
.mz-agora-rot { color: var(--text-dim); font-size: 12px; }
.mz-agora-h { font-size: 17px; font-weight: 700; font-variant-numeric: tabular-nums; }
.mz-agora-pat, .mz-agora-est {
  font-size: 11.5px; padding: 1px 8px; border-radius: var(--r-pill);
  border: 1px solid var(--border); color: var(--text-dim);
}
.mz-agora-est[data-mz-estado="trava"] { border-color: var(--mi-cut1); color: var(--mi-cut1); }
.mz-agora-est[data-mz-estado="ja_travado"] { border-color: var(--mi-bad); color: var(--mi-bad); }
.mz-agora-est[data-mz-estado="suspeito"] { border-color: var(--mi-warn); color: var(--mi-warn); }
.mz-kpis, .mz-kpis-dia { margin-top: 6px; }
.mz-val { font-variant-numeric: tabular-nums; }
.mz-val.is-cen { color: var(--mi-cut2); }
/* O mesmo âmbar da caixa que acende no diagrama: é o que liga o nome ao mapa. */
.mz-quem { font-size: 16px; display: inline-flex; align-items: center; gap: 6px; }
.mz-quem::before {
  content: ""; width: 9px; height: 9px; border-radius: 50%;
  background: var(--mi-warn); flex: 0 0 auto;
}
.mz-num { text-align: right; font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------- tags do cenário */
.mz-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.mz-tag {
  display: inline-flex; gap: 6px; align-items: baseline;
  padding: 2px 9px; border-radius: var(--r-pill); font-size: 12px;
  border: 1px solid var(--mi-cut2); color: var(--mi-cut2);
}
.mz-tag.is-vazio { border-color: var(--border); color: var(--text-dim); }
.mz-tag-k { font-weight: 600; }
.mz-tag-v { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------- veredito e estados */
/* A única peça "alta" dos dois modos: é a resposta, e tudo em volta é o que a
   sustenta. Maior e mais leve que um KPI, para ler como frase. */
.mz-veredito {
  font-size: var(--fs-lg); line-height: 1.45;
  margin: 10px 0 8px; padding-left: 12px; max-width: 70ch;
  border-left: 3px solid var(--border);
}
.mz-veredito.mz-est-trava { border-left-color: var(--mi-cut1); }
.mz-veredito.mz-est-ja_travado { border-left-color: var(--mi-bad); }
.mz-veredito.mz-est-suspeito { border-left-color: var(--mi-warn); }
.mz-veredito.mz-est-nao_trava_ate_teto { border-left-color: var(--mi-cut3); }

.mz-estados {
  display: flex; flex-wrap: wrap; gap: 6px; list-style: none;
  padding: 0; margin: 0 0 6px;
}
.mz-est {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 3px 10px; border-radius: var(--r-pill); font-size: 12px;
  border: 1px solid var(--border); background: var(--card);
}
.mz-est-n { font-weight: 700; font-variant-numeric: tabular-nums; }
.mz-est-de { color: var(--text-dim); }
.mz-est.is-zero { opacity: .45; }
/* Estado não é legível só pela cor: o nome vai sempre junto. A cor é o segundo
   canal, e a borda esquerda o terceiro. */
.mz-est.mz-est-trava { border-color: var(--mi-cut1); }
.mz-est.mz-est-ja_travado { border-color: var(--mi-bad); }
.mz-est.mz-est-suspeito { border-color: var(--mi-warn); }
.mz-est.mz-est-nao_trava_ate_teto { border-color: var(--mi-cut3); }
/* "Não aperta neste sentido" fica com a borda neutra de propósito: é o único
   estado que não diz nada sobre aperto, e a mesma cor cinza o representa na
   figura (`dessem_estresse_view._COR_ESTADO`). */
.mz-est.mz-est-nao_amarra_neste_sentido { border-color: var(--border); }
/* O nome do estado é o PRIMEIRO canal do chip (a cor é o segundo, a borda o
   terceiro): sem peso ele lia depois do número. */
.mz-est-nome { font-weight: 600; }

.mz-cobertura td:first-child, .mz-cobertura th { text-align: left; }
/* Nas três tabelas abaixo só a coluna que se COMPARA é alinhada à direita: o
   nome da restrição e o "sim/não" são texto, e alinhá-los à direita jogava o
   rótulo para longe do cabeçalho. */
.mz-culpados th { text-align: left; }
.mz-culpados tbody td.mz-num,
.mz-movidas tbody td.mz-num,
.mz-cobertura tbody td.mz-num {
  text-align: right; font-variant-numeric: tabular-nums;
}
.mz-movidas th { text-align: left; }

/* O rádio do sentido mora ABAIXO do formulário (ver `controles_cenario`): ele
   pertence à secção "até onde dá para ir", que fecha o corpo, e não ao que se
   digita acima. A régua é o que diz isso sem precisar de um segundo título. */
.mz-campo-sentido {
  margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border);
}

/* --------------------------------------------------- "até onde dá para ir"
   A sensibilidade fecha o corpo do cenário, separada por uma régua. A régua NÃO
   é decoração: acima dela tudo é medido (o dia da rodada com um número
   trocado); daqui para baixo tudo responde SOB PREMISSA, e o veredito é a única
   peça "alta" da secção. */
.mz-ateonde {
  display: block; margin-top: 18px; padding-top: 14px;
  border-top: 1px solid var(--border);
}

/* ------------------------------------------- as duas secções do formulário
   "Quem move o fluxo" e "Quem move o limite" são efeitos OPOSTOS sobre a mesma
   folga (um consome o espaço por baixo, o outro é a régua por cima), e por isso
   a régua entre elas é mais grossa que a das linhas. As LINHAS são as mesmas
   `.mz-ch-*` nos dois lados: é o mesmo gesto, e dois vocabulários para a mesma
   ação seriam dois para aprender. */
.mz-form-sec + .mz-form-sec {
  margin-top: 16px; padding-top: 12px; border-top: 2px solid var(--border);
}
/* Aviso da própria manopla (nome que não casou com o deck, par de sentido que
   não colapsou). A palavra "aviso:" é o primeiro canal; o âmbar é o segundo. */
.mz-ch-aviso { color: var(--mi-warn); font-size: 11px; }

/* Quem trava o empurrão, no diagrama.
   ⚠️ Não pode usar --mi-cut1/2/3: as três caixas de secção (EXP_NE, FNS_FNESE,
   IMP_SECO) já são tracejadas nessas cores, e um culpado em azul tracejado
   ficava idêntico à caixa da EXP_NE. O âmbar é a única cor Okabe-Ito que
   nenhuma caixa usa, e ainda assim ele não é o único canal: o pontilhado é mais
   curto que o `6 4` das secções, vai um halo junto, e o painel escreve o nome
   do culpado ao lado do mesmo ponto âmbar (`.mz-quem`). O `at-lim` (vermelho,
   contínuo) continua querendo dizer "está no limite AGORA" — os dois podem
   estar na mesma caixa ao mesmo tempo, e precisam continuar legíveis juntos. */
.mi-box.is-culpado .mi-box-bg {
  stroke: var(--mi-warn); stroke-width: 3; stroke-dasharray: 2 3;
  filter: drop-shadow(0 0 4px var(--mi-warn));
}

@media (max-width: 720px) {
  .mz-abas { padding: 0 8px; }
  .mz-aba { padding: 8px 10px; }
  .mz-aba-sub { display: none; }
  .mz-corpo, .mz-controles { padding-left: 8px; padding-right: 8px; }
}

/* ═══════════════════════════════════════════ modo "período"
   A terceira aba: a mesma restrição ao longo de N dias. Duas peças novas — o
   wrapper de figura que NÃO é `.mx-graf`, e a lista de mudanças do deck. */

/* Mesma trava de altura de `.mx-graf`, classe diferente de propósito:
   `dessemMapa.marcarAgora` varre `.mx-graf` para mover `shapes[0]`, e as
   figuras do período não têm shape — entrar naquela varredura dá erro de JS
   silencioso a cada movimento do slider. */
.mz-graf-per { width: 100%; }

.mz-custo { margin: 6px 0 0; font-size: 11.5px; }

/* ------------------------------------------------- o que mudou no deck */
.mz-mud-sec { margin-top: 18px; }

/* "Nenhuma mudança" é resposta, não ausência de resposta: ganha o mesmo peso
   de um veredito, senão é lido como "a tela não olhou". */
.mz-sem-mud {
  font-size: 15px; font-weight: 600; margin: 0 0 4px;
  padding-left: 10px; border-left: 3px solid var(--mi-cut3);
}
.mz-mud-total { font-size: 14px; margin: 0 0 8px; }

/* Sequência cronológica de verdade (um dia depois do outro), então o trilho à
   esquerda carrega informação: é a linha do tempo do deck. */
.mz-mud {
  list-style: none; margin: 0; padding: 0 0 0 14px;
  border-left: 2px solid var(--border);
}
.mz-mud-item { position: relative; margin-bottom: 8px; }
.mz-mud-item::before {
  content: ""; position: absolute; left: -19px; top: 14px;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--text-dim);
}
.mz-mud-det { margin: 0; }
.mz-mud-sum { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 9px; }
.mz-mud-dia {
  font-variant-numeric: tabular-nums; font-weight: 700;
  min-width: 5ch;
}
.mz-mud-rot { font-weight: 600; }
.mz-mud-sub { font-weight: 400; color: var(--text-dim); font-size: 12px; }

/* ------------------------------------------------------ tabelas de diff */
.mz-diff { font-size: 12.5px; }
.mz-diff tbody td.mz-num { text-align: right; font-variant-numeric: tabular-nums; }
.mz-diff + .mx-def-tit { margin-top: 14px; }
/* A coluna do sinal: larga o bastante para o "−"/"+" respirar e alinhada ao
   centro, porque não é número nem texto — é o marcador da linha. */
.mz-diff-sig {
  width: 2.2em; text-align: center; font-weight: 700; font-size: 14px;
  line-height: 1;
}
/* A cor é o SEGUNDO canal. O primeiro é a célula "−"/"+" que o Python emite em
   toda linha, e por isso o diff continua legível em cinza e para quem não
   separa vermelho de verde. A borda grossa à esquerda é o terceiro. */
.mz-diff-out { color: var(--mi-bad); box-shadow: inset 3px 0 0 var(--mi-bad); }
/* Verde-azulado do Okabe-Ito e não o verde de status: sobre painel branco o
   `--ok` em texto fino fica no limite do contraste. */
.mz-diff-in { color: var(--mi-cut3); box-shadow: inset 3px 0 0 var(--mi-cut3); }
.mz-diff-out td, .mz-diff-in td { border-bottom-color: var(--border); }

@media (max-width: 720px) {
  .mz-mud { padding-left: 10px; }
  .mz-mud-sub { flex-basis: 100%; }
}
