/* Alcance Hub · folha de estilo única.
   Derivada de mockup/mockup-v0.2.html (referência visual aprovada). O visual não muda:
   as diferenças em relação ao mockup são apenas as necessárias para (a) servir as fotos
   como <picture>/<img> em vez de background-image, (b) eliminar todo atributo style=
   do HTML, para a CSP poder dispensar 'unsafe-inline', e (c) remover o slider de
   simulação, que era exclusivo do mockup. */

  :root{
    /* `--faint` era #6E7F91 e dava 3,68:1 contra `--bg` e 3,94:1 contra o fundo do card
       (branco a 62% sobre `--bg` = #F9FAFC). A WCAG 2.1, critério 1.4.3 (Contrast
       Minimum), nível AA, exige **4,5:1** para texto normal — e nenhum dos lugares onde
       `--faint` aparece é texto grande (o maior é 16px normal; a norma só dispensa a
       partir de 18,66px, ou 14px em negrito). O tom é o mesmo: hsl(210,86°, 13,73%) de
       matiz e saturação idênticos, só a claridade HSL cai de 50,00% para 44,25% — a menor
       mudança que fecha a norma. Passa a 4,55:1 contra `--bg` e 4,86:1 contra o card.
       `--muted` já cumpria (7,42:1 e 7,93:1) e por isso não muda. */
    --bg:#EEF3F8; --ink:#10202F; --muted:#3F5062; --faint:#617080;
    --azul:#00528B; --on-azul:#FFFFFF; --laranja:#E88024; --sun:#F2A552;
    --glass:rgba(255,255,255,.62); --glass-strong:rgba(255,255,255,.86); --line:rgba(16,32,47,.12); --line-strong:rgba(16,32,47,.22);
    /* ORDEM-008, adendo 4 §B. As três eram #1F8A5B, #B8860B e #C43C3C e reprovavam a WCAG
       2.1, critério 1.4.3, nível AA (4,5:1 para texto normal) onde aparecem escritas: a
       variação em pílula de 14% da própria cor (`.up`, `.dn`, `.flag`) e o rótulo de fonte
       desatualizada. Mesma regra do `--faint`: matiz e saturação idênticas, a claridade HSL
       desce só até fechar a norma e para.

         --ok    h 153,64° s 63,31% l 33,14% → h 154,00° s 63,38% l 27,84%   3,51 → 4,53:1
         --warn  h  42,66° s 88,72% l 38,24% → h  42,58° s 88,57% l 27,45%   2,70 → 4,53:1
         --crit  h   0,00° s 53,54% l 50,20% → h   0,00° s 53,78% l 46,67%   4,03 → 4,52:1

       O `--crit` entra por um motivo melhor que os outros dois: ele só reprovava **quando o
       dado aparecia** (uma queda na lista de câmbio ou de mercado), e falha que depende do
       dado é a que escapa de toda auditoria que teve sorte com a fixture.

       ADENDO 5 §B · DUAS NORMAS DIFERENTES, E POR ISSO DUAS COLUNAS. Não junte estas seis de
       volta em três: a distinção é o que impede alguém de "consertar" isto daqui a três meses
       e reabrir um dos dois defeitos. Cada uma das três cores aparece de duas formas, e cada
       forma responde a um critério distinto:

       · **Escrita** (`.up`, `.dn`, a legenda de `.flag`, `.desatualizado`, `.barh .l b`) →
         critério **1.4.3**, Contrast Minimum, **4,5:1**. As três reprovavam. É para isso que
         existem as `-txt`, e é a elas que todo uso de `color:` aponta.
       · **Pintando** (o ponto de estado, o quadradinho da bandeira, as barras assinadas, a
         faixa `.fg`/`.fy`/`.fr` das 12 bandeiras) → critério **1.4.11**, Non-text Contrast,
         **3:1** — e as três **já cumpriam**: 4,15:1, 3,12:1 e 4,95:1 contra o fundo do card,
         que é onde de fato aparecem (nenhuma se apoia no `--bg` liso).

       O adendo 4 escureceu os três tokens de uma vez e o preenchimento foi de carona, sem
       norma nenhuma pedindo. Deu no que a captura `027c-cor-energia-depois` mostrou: a faixa
       das 12 bandeiras virou bronze ao lado da palavra "Bandeira **amarela**". Aplicar 4,5:1
       onde a norma pede 3:1 é aplicar a norma errada.

       Medido contra a pílula de 14% feita da cor de preenchimento, que é a que ficou:
       `--ok` 3,51 → **4,63:1**, `--warn` 2,70 → **4,78:1**, `--crit` 4,03 → **4,54:1**.

       No tema escuro as três já cumpriam como texto, e por isso lá `-txt` é a própria cor: o
       par existe em todo tema para o CSS ter um só lugar onde olhar, não porque o escuro
       precise de duas. */
    --ok:#1F8A5B; --warn:#B8860B; --crit:#C43C3C;
    --ok-txt:#1A744D; --warn-txt:#846008; --crit-txt:#B73737;
    /* E6, item 9. Estes três já existiam no arquivo, cravados nas classes dos cards de
       portal (`.portal-propostas`, `.portal-leads`, `.portal-ativos`). Viraram token
       porque os modais passaram a precisar deles também: cor repetida em dois lugares
       envelhece separada, e a regra "nenhuma cor fora da paleta" só é verificável se a
       paleta for um lugar. **Nenhum valor novo** — são os mesmos hexadecimais. */
    --verde:#3EB489; --roxo:#B37FE0; --ouro:#E0B24A;
    /* ORDEM-044 · A SEXTA COR DOS CARDS DE PORTAL, para o Portal de CRM. As cinco em uso
       eram azul, laranja, verde, roxo e ouro; o que sobrava de matiz livre, longe das
       cinco **e** longe do vermelho de `--crit`, é a faixa do magenta.

       hsl(327°, 53%, 51%). A saturação fica dentro da família (verde 49%, roxo 61%), e a
       matiz é a mais afastada que o espaço permitia: **55° de roxo** (272°) e **33° do
       `--crit`** (0°), que é o ponto vermelho de "Fora do ar" e o vizinho que mais
       importava não imitar.

       A CLARIDADE NÃO É GOSTO, É O ÚNICO VALOR QUE FECHA OS DOIS TEMAS. Onde `--c` aparece
       no card é o traço do ícone sobre o selo (`color-mix(--c 18%, transparent)` sobre o
       fundo do card), e o critério que se aplica a ele é o 1.4.11, Non-text Contrast, 3:1.
       Medido (`#F9FAFC` no claro, `#080E17` no escuro):

         traço × selo   claro **3,53:1**   escuro **3,56:1**
         traço × card   claro **4,51:1**   escuro **4,12:1**

       Varrendo matiz 318–345°, saturação 35–75% e claridade 38–58%, o máximo do pior dos
       dois temas é ~3,55 e está em l≈52%: subir a claridade melhora o escuro e estraga o
       claro, descer faz o contrário. **É por isso que esta cor é uma só e não tem par no
       bloco escuro**, como `--laranja`, `--verde`, `--roxo` e `--ouro` — e, diferente das
       quatro, ela fecha os 3:1 **nos dois** temas (elas dão 1,70 a 2,42 no claro, porque
       nasceram do mockup e o selo é decorativo ao lado do nome escrito do portal). */
    --magenta:#C4418A;
    --shadow:0 10px 30px rgba(16,32,47,.12);
    --tint:rgba(238,243,248,.28); --veil:rgba(238,243,248,.92);
    --flip:#14202D; --flip-ink:#F4F7FA; --flip-line:rgba(0,0,0,.55);
    --overlay:rgba(16,32,47,.45);
    --selo-img:rgba(255,255,255,.92); --selo-img-borda:rgba(0,0,0,.06);
  }
  @media (prefers-color-scheme: dark){
    :root:not([data-theme="light"]){
      --bg:#070C14; --ink:#E9EFF6; --muted:#A3B1C1; --faint:#6F8092;
      --azul:#4FA3E3; --on-azul:#061019; --laranja:#E88024; --sun:#F2A552;
      --glass:rgba(10,16,26,.42); --glass-strong:rgba(10,16,26,.72); --line:rgba(255,255,255,.10); --line-strong:rgba(255,255,255,.18);
      --ok:#4CC08A; --warn:#E8B93A; --crit:#EF6B6B;
      --ok-txt:#4CC08A; --warn-txt:#E8B93A; --crit-txt:#EF6B6B;
      --shadow:0 14px 40px rgba(0,0,0,.45);
      --tint:rgba(5,9,18,.45); --veil:rgba(7,12,20,.94);
      --flip:#0E1620; --flip-ink:#F4F7FA; --flip-line:rgba(0,0,0,.7);
      --overlay:rgba(2,6,12,.62);
      --selo-img:rgba(226,232,240,.82); --selo-img-borda:rgba(0,0,0,.18);
    }
  }
  :root[data-theme="dark"]{
    --bg:#070C14; --ink:#E9EFF6; --muted:#A3B1C1; --faint:#6F8092;
    --azul:#4FA3E3; --on-azul:#061019; --laranja:#E88024; --sun:#F2A552;
    --glass:rgba(10,16,26,.42); --glass-strong:rgba(10,16,26,.72); --line:rgba(255,255,255,.10); --line-strong:rgba(255,255,255,.18);
    --ok:#4CC08A; --warn:#E8B93A; --crit:#EF6B6B;
    --ok-txt:#4CC08A; --warn-txt:#E8B93A; --crit-txt:#EF6B6B;
    --shadow:0 14px 40px rgba(0,0,0,.45);
    --tint:rgba(5,9,18,.45); --veil:rgba(7,12,20,.94);
    --flip:#0E1620; --flip-ink:#F4F7FA; --flip-line:rgba(0,0,0,.7);
    --overlay:rgba(2,6,12,.62);
    --selo-img:rgba(226,232,240,.82); --selo-img-borda:rgba(0,0,0,.18);
  }

  *{box-sizing:border-box}
  html,body{margin:0}
  body{background:var(--bg);color:var(--ink);font-family:"IBM Plex Sans",system-ui,-apple-system,Segoe UI,sans-serif;font-size:15px;line-height:1.5;min-height:100vh;overflow-x:hidden;transition:background .8s,color .4s}
  a{color:inherit;text-decoration:none}
  button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
  h1,h2,h3{margin:0;font-family:"Sora","IBM Plex Sans",sans-serif;text-wrap:balance}
  :focus-visible{outline:2px solid var(--laranja);outline-offset:3px;border-radius:6px}

  /* ---------- photographic background with day cycle ---------- */
  .bg{position:fixed;inset:0;z-index:0;overflow:hidden;background:linear-gradient(180deg,#1B3A5C 0%,#0E2238 55%,#3A2414 100%)}
  .bg-layer{position:absolute;inset:-2%;opacity:0;transition:opacity 1.6s ease;transform:scale(1.02)}
  .bg-layer img{display:block;width:100%;height:100%;object-fit:cover;object-position:center 40%}
  .bg-layer.on{opacity:1}
  .bg-tint{position:absolute;inset:0;background:var(--tint);transition:background 1.2s}
  .bg-veil{position:absolute;inset:0;background:linear-gradient(180deg,rgba(0,0,0,.18) 0%,transparent 22%,transparent 48%,var(--veil) 100%);transition:background 1.2s}
  @media (prefers-reduced-motion: reduce){ .bg-layer{transition:none} }

  /* ---------- layout ---------- */
  .page{position:relative;z-index:1;max-width:1720px;margin:0 auto;padding:22px clamp(18px,3vw,56px) 56px;display:flex;flex-direction:column;gap:clamp(28px,4vh,52px)}

  .topbar{display:flex;align-items:center;justify-content:space-between;gap:16px}
  .brand img{height:56px;width:auto;display:block}
  .brand .logo-dark{display:none}
  :root[data-theme="dark"] .brand .logo-dark{display:block}
  :root[data-theme="dark"] .brand .logo-light{display:none}
  @media (prefers-color-scheme: dark){ :root:not([data-theme="light"]) .brand .logo-dark{display:block} :root:not([data-theme="light"]) .brand .logo-light{display:none} }
  .top-right{display:flex;align-items:center;gap:10px}
  .conta{display:flex;align-items:center;gap:10px;font-size:12.5px}
  .conta-nome{color:var(--muted)}
  .conta-entrar,.conta-sair{padding:6px 11px;border-radius:999px;border:1px solid var(--line);color:var(--ink);background:var(--glass-strong);backdrop-filter:blur(10px);transition:border-color .2s,background .2s}
  .conta-entrar{background:var(--azul);color:var(--on-azul);border-color:transparent;font-weight:600}
  .chip{display:inline-flex;align-items:center;gap:6px;padding:6px 11px;border:1px solid var(--line);border-radius:999px;background:var(--glass-strong);backdrop-filter:blur(10px);font-size:12px;color:var(--muted)}
  .chip .dot{width:7px;height:7px;border-radius:50%;background:var(--laranja)}
  .seg{display:inline-flex;padding:3px;border:1px solid var(--line);border-radius:999px;background:var(--glass-strong);backdrop-filter:blur(10px)}
  .seg button{display:inline-flex;align-items:center;gap:6px;padding:6px 11px;border-radius:999px;font-size:12px;color:var(--muted);transition:background .2s,color .2s}
  .seg button svg{width:15px;height:15px}
  .seg button[aria-pressed="true"]{background:var(--azul);color:var(--on-azul)}

  /* ---------- hero ---------- */
  .hero{display:grid;grid-template-columns:1fr auto;align-items:end;gap:28px;padding-top:clamp(8px,5vh,60px)}
  .greet{font-size:clamp(28px,3.6vw,54px);font-weight:600;letter-spacing:-.02em;line-height:1.05;text-shadow:0 2px 24px rgba(0,0,0,.25)}
  .greet em{font-style:normal;color:var(--laranja)}
  .date{margin-top:10px;color:var(--ink);opacity:.85;font-size:clamp(14px,1.2vw,17px);text-shadow:0 1px 12px rgba(0,0,0,.25)}
  .search{display:flex;align-items:center;gap:10px;max-width:760px;width:100%;padding:6px 8px 6px 18px;border:1px solid var(--line-strong);border-radius:16px;background:var(--glass-strong);backdrop-filter:blur(18px);box-shadow:var(--shadow);margin-top:26px}
  .search svg{width:20px;height:20px;color:var(--muted);flex:none}
  .search input{flex:1;min-width:0;background:none;border:0;outline:0;color:var(--ink);font:inherit;font-size:16px;padding:10px 0}
  .search input::placeholder{color:var(--faint)}
  .search .kbd{font-family:"IBM Plex Mono",monospace;font-size:11px;color:var(--muted);border:1px solid var(--line);border-radius:6px;padding:3px 7px}
  .search button{padding:10px 16px;border-radius:11px;background:var(--azul);color:var(--on-azul);font-weight:600;font-size:14px}

  /* A coluna do relógio (rótulo abaixo dos dígitos) vem do mockup; a regra se perdeu
     quando o bloco do relógio antigo foi substituído, e o rótulo ficou colado nas
     plaquinhas — cuja sombra ainda cobria o texto. */
  .clockwrap{display:flex;flex-direction:column;align-items:flex-end;gap:14px}

  /* ---------- relógio · pqina/flip 1.8.0, vendorizado em static/vendor ----------
     O CSS da biblioteca não é tocado; tudo aqui é sobreposição, para o relógio continuar
     com a identidade do mockup: Sora, plaquinha var(--flip), dígito var(--flip-ink), dois
     pontos em laranja, raio e sombra do mockup.
     No Flip o tamanho do card vem do font-size, então --h (a altura que o mockup usava)
     vira font-size aqui, com o mesmo fator 0.82 do mockup. */
  /* O Flip dimensiona a plaquinha pelo font-size x line-height (o dele é 1.4, e mexer
     nisso encolhe a caixa e faz o rótulo ficar por baixo dos dígitos). Para a plaquinha
     ficar com a altura --h do mockup, o font-size é --h/1.4. */
  /* tabular-nums: sem isso o "1" da Sora é mais estreito que os outros dígitos e o
     relógio muda de largura a cada segundo. */
  .flipclock{--h:clamp(72px,8.4vw,150px);display:flex;align-items:center;gap:8px;
    font-family:"Sora",sans-serif;font-weight:600;font-size:calc(var(--h)*.714);line-height:1.4;
    font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
  .flipclock .tick-group{display:flex;gap:8px}
  .flipclock .tick-flip{border-radius:calc(var(--h)*.09);box-shadow:0 12px 30px rgba(0,0,0,.35)}
  .flipclock .tick-flip-panel{background-color:var(--flip);color:var(--flip-ink)}
  .flipclock .tick-flip-panel-back-shadow,
  .flipclock .tick-flip-shadow-top,
  .flipclock .tick-flip-shadow-bottom{opacity:.5}
  .flipclock .tick-credits{display:none}   /* a licença MIT vai em static/vendor/flip/1.8.0/LICENSE */

  /* dois pontos do mockup, em laranja */
  .flipclock .sep{display:flex;flex-direction:column;gap:calc(var(--h)*.14);padding:0 2px}
  .flipclock .sep i{width:calc(var(--h)*.08);height:calc(var(--h)*.08);border-radius:50%;background:var(--laranja);display:block}

  /* segundos: 62% do tamanho, alinhados pela base */
  .flipclock .segundos{display:flex;align-items:center;gap:8px;align-self:flex-end;--h:clamp(45px,5.2vw,93px);font-size:calc(var(--h)*.714)}

  .clocklbl{font-family:"IBM Plex Mono",monospace;font-size:clamp(11px,.9vw,13px);letter-spacing:.14em;text-transform:uppercase;color:var(--ink);opacity:.75}

  /* Movimento reduzido: a biblioteca não consulta a preferência do sistema, então a
     desligamos aqui. `?animacao=1` põe data-animacao no <html> e devolve a animação,
     como pedido explícito de quem está olhando. */
  @media (prefers-reduced-motion: reduce){
    :root:not([data-animacao="1"]) .flipclock .tick-flip-card{transition:none!important;animation:none!important}
  }

  /* ---------- sections ----------
     `[hidden]` do HTML vale `display:none` por folha do navegador, e folha do navegador
     perde para QUALQUER regra de autor: o bloco sem-rolagem mais abaixo declara
     `.sec{display:flex}`, e sem esta linha a seção da barra de links apareceria vazia para
     quem não entrou, abrindo um vão entre os portais e o painel. Declarada aqui, perto de
     `.sec`, e não junto da barra — o defeito é da regra de `.sec`, não da barra. */
  .sec[hidden]{display:none}
  .sec-head{display:flex;align-items:baseline;justify-content:space-between;gap:16px;margin-bottom:14px}
  .sec-head h2{font-size:13px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--ink);opacity:.8}
  /* A opacidade era .6, o que dava #69747F sobre `--bg` e 4,27:1 — abaixo dos 4,5:1 da
     WCAG 2.1 AA (1.4.3) para texto normal de 12px. Não é `--muted` nem `--faint`, como a
     ORDEM-008 §7.3 supunha: é `--ink` esmaecido, e por isso se corrige pela opacidade e
     não pela paleta. .62 é o menor passo que fecha: #64707B, 4,54:1. */
  .sec-head span{font-size:12px;color:var(--ink);opacity:.62}

  /* ---------- portals ----------
     SEIS COLUNAS desde a ORDEM-044, e não cinco: o Portal de CRM é o sexto card, e a faixa
     dos portais é uma linha só em todo o modo sem rolagem. Duas colunas e uma sobrando é o
     que o `overflow:hidden` da página transformaria em card cortado. O número de colunas é o
     número de portais do `config.js`, e **trocá-lo é o que acontece quando um portal entra** —
     o custo em altura está medido junto da linha-irmã, no bloco sem-rolagem. */
  .portals{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}
  @media (min-width:1900px){ .portals{grid-template-columns:repeat(6,1fr)} }
  .portal{cursor:pointer;position:relative;display:flex;flex-direction:column;gap:14px;padding:20px 20px 18px;border:1px solid var(--line);border-radius:18px;background:var(--glass);backdrop-filter:blur(18px);transition:transform .25s ease,border-color .25s ease;overflow:hidden;min-height:240px;box-shadow:var(--shadow)}
  .portal::before{content:"";position:absolute;inset:0;background:radial-gradient(420px 160px at var(--mx,50%) var(--my,0%),color-mix(in srgb,var(--c) 22%,transparent),transparent 70%);opacity:0;transition:opacity .3s}
  .portal:hover{transform:translateY(-4px);border-color:color-mix(in srgb,var(--c) 55%,var(--line))}
  .portal:hover::before{opacity:1}
  .portal .head{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
  .portal .icon{width:44px;height:44px;border-radius:12px;display:grid;place-items:center;background:color-mix(in srgb,var(--c) 18%,transparent);color:var(--c)}
  .portal .icon svg{width:24px;height:24px}
  .status{display:inline-flex;align-items:center;gap:6px;font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
  .status i{width:7px;height:7px;border-radius:50%;background:var(--ok);box-shadow:0 0 0 3px color-mix(in srgb,var(--ok) 25%,transparent)}
  /* E6, item 5: "Em construção" é ausência, não alerta — sai do âmbar de "Instável",
     com quem dividia a cor e virava o mesmo ponto para quem bate o olho. */
  .status.dev i{background:var(--faint);box-shadow:0 0 0 3px color-mix(in srgb,var(--faint) 25%,transparent)}
  /* Selo sem nada a dizer (portal no ar, ou ainda não medido): some sem deixar buraco
     nem mexer na altura do cabeçalho do card. */
  .status.vazio{display:none}
  /* E5.2 · estados vindos de /api/saude. `instavel` é âmbar (pode ser um reinício) e só
     `fora` é vermelho — ver a justificativa dos três estados em app/portais.py. */
  .status.instavel i{background:var(--warn);box-shadow:0 0 0 3px color-mix(in srgb,var(--warn) 25%,transparent)}
  .status.fora i{background:var(--crit);box-shadow:0 0 0 3px color-mix(in srgb,var(--crit) 25%,transparent)}
  .status.desconhecido i{background:var(--faint);box-shadow:none}
  .portal h3{font-size:18px;font-weight:600;letter-spacing:-.01em}
  .portal p{margin:4px 0 0;color:var(--muted);font-size:13.5px;line-height:1.5}
  /* ORDEM-008, item 2 (§B do adendo): `margin-top:auto` empurrava as labels para a base
     do card e abria 34 a 68 px de buraco entre a descrição e elas. As labels passam a vir
     logo depois do texto, e o que sobra fica na base — num lugar só. */
  .tools{display:flex;flex-wrap:wrap;gap:6px}
  .tools a{font-size:12px;padding:5px 9px;border-radius:8px;border:1px solid var(--line);color:var(--ink);background:var(--glass);transition:border-color .2s,background .2s}
  .tools a:hover{border-color:var(--c);background:color-mix(in srgb,var(--c) 14%,transparent)}

  /* ---------- widgets ----------
     `--wgap` e `--colw` (mais abaixo) são declarados na SEÇÃO, não na grade: o cabeçalho
     `.sec-head` é irmão de `.widgets`, e em CSS não se sobe de um irmão para o outro. Quem
     precisa do mesmo vão e da mesma largura de coluna que a linha de cards é o cabeçalho —
     ORDEM-018, item 1 —, e declarar na mãe é o único ponto que os dois enxergam.
     A substituição de variável é por TOKEN: o `100%` de `--colw` é resolvido no ponto de
     uso, contra a caixa de conteúdo de quem usa, e `.sec-panel` e `.widgets` têm exatamente
     a mesma largura de caixa (nenhuma das duas tem padding). */
  .sec-panel{--wgap:14px}
  .widgets{display:grid;gap:var(--wgap);grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}
  @media (min-width:1900px){ .widgets{grid-template-columns:repeat(6,1fr)} }
  .w{cursor:pointer;padding:18px;border:1px solid var(--line);border-radius:18px;background:var(--glass);backdrop-filter:blur(18px);display:flex;flex-direction:column;gap:12px;min-height:200px;box-shadow:var(--shadow);transition:transform .25s,border-color .25s}
  .w:hover{transform:translateY(-3px);border-color:var(--line-strong)}
  .w .lbl{display:flex;align-items:center;justify-content:space-between;font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
  /* `.lbl-fim` é o rótulo da PONTA do card de links (ORDEM-018, adendo 1 §B): leva só a ação,
     com o mesmo corpo do `.lbl`, e não é `.lbl` porque os instrumentos clicam no único `.lbl`
     de cada card para abrir o modal. */
  .w .lbl-fim{display:flex;align-items:center;flex:none;font-size:11.5px}
  .w :is(.lbl,.lbl-fim) span{letter-spacing:0;text-transform:none;font-family:"IBM Plex Mono",monospace;color:var(--faint)}
  /* ORDEM-008, adendo 3 §B · a ação do cabeçalho dos cards de tarefas e de links.
     Os dois deixaram de ser `role="button" tabindex="0"` porque contêm controles próprios
     (`nested-interactive`, WCAG 2.0 nível A), e no lugar cada um ganhou um `<button>` de
     verdade no rótulo. **A aparência é a do `<span>` que já estava lá** — o "editar" do card
     de links era um span decorativo e continua com a mesma cor, a mesma fonte mono e o mesmo
     tamanho; o que muda é que agora ele é uma parada de tabulação e responde a `Enter` e
     `Espaço`. O sublinhado só aparece no ponteiro, para não pesar a linha em repouso; o anel
     de foco vem do `:focus-visible` global. */
  .w :is(.lbl,.lbl-fim) .lbl-dir{display:inline-flex;align-items:center;gap:10px}
  .w :is(.lbl,.lbl-fim) .lbl-acao{font:inherit;color:var(--faint);padding:0;line-height:1.25;border-bottom:1px solid transparent;transition:color .2s,border-color .2s}
  .w :is(.lbl,.lbl-fim) .lbl-acao:hover{color:var(--ink);border-bottom-color:var(--line-strong)}
  .big{font-family:"Sora",sans-serif;font-size:40px;font-weight:600;line-height:1;letter-spacing:-.03em;font-variant-numeric:tabular-nums}
  .big sup{font-size:16px;font-weight:500;color:var(--muted);vertical-align:top;margin-left:2px}
  .sub{color:var(--muted);font-size:13px}
  .rows{display:flex;flex-direction:column;gap:8px}
  .row{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:13.5px}
  .row .k{color:var(--muted)}
  .row .v{font-family:"IBM Plex Mono",monospace;font-variant-numeric:tabular-nums;font-size:13.5px}
  .delta{font-family:"IBM Plex Mono",monospace;font-size:11.5px;padding:2px 6px;border-radius:6px}
  .up{color:var(--ok-txt);background:color-mix(in srgb,var(--ok) 14%,transparent)}
  .dn{color:var(--crit-txt);background:color-mix(in srgb,var(--crit) 14%,transparent)}
  .flag{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;border-radius:10px;background:color-mix(in srgb,var(--crit) 14%,transparent);color:var(--crit-txt);font-weight:600;font-size:13px}
  .flag i{width:10px;height:10px;border-radius:2px;background:var(--crit)}
  .spark{width:100%;height:44px}
  .weather-top{display:flex;align-items:center;justify-content:space-between;gap:10px}
  .weather-top svg{width:52px;height:52px;color:var(--sun)}
  .meter{height:6px;border-radius:999px;background:var(--line);overflow:hidden}
  .meter i{display:block;height:100%;background:linear-gradient(90deg,var(--azul),var(--laranja));border-radius:999px}
  /* ORDEM-008, item 2: o rodapé do card deixa de ser empurrado para a base. Só aparece
     abaixo do modo sem-rolagem (lá `.more{display:none}`), e ali a página rola. */
  .more{font-size:11.5px;color:var(--faint);display:flex;justify-content:flex-end}

  /* aviso discreto quando a fonte de um bloco está fora do ar (E3) */
  .w .lbl .desatualizado{color:var(--warn-txt)}
  /* a cor da bandeira tarifária vem do dado, não do HTML */
  .flag[data-cor="ok"]{background:color-mix(in srgb,var(--ok) 14%,transparent);color:var(--ok-txt)}
  .flag[data-cor="ok"] i{background:var(--ok)}
  .flag[data-cor="warn"]{background:color-mix(in srgb,var(--warn) 14%,transparent);color:var(--warn-txt)}
  .flag[data-cor="warn"] i{background:var(--warn)}
  .flag[data-cor="crit"]{background:color-mix(in srgb,var(--crit) 14%,transparent);color:var(--crit-txt)}
  .flag[data-cor="crit"] i{background:var(--crit)}

  /* ---------- ORDEM-039 §3 · o resumo operacional dos portais ----------
     Cinco linhas num card de 229 px a 1536x864 (201 px de caixa útil, medidos). A grade da
     linha é `nome | tempos | disponibilidade`, com o nome encolhendo e as duas colunas de
     número no tamanho do conteúdo — é o contrário de `.row`, que é flex com
     `space-between` e daria três blocos soltos com vão variável entre eles.

     A ÚLTIMA QUEDA VAI NUMA SEGUNDA LINHA da própria linha (`grid-column:1/-1`), e não numa
     quarta coluna: "última queda: há 3 h" tem ~78 px e não sobra largura para ela em 1536.
     Como quase toda janela saudável não tem queda nenhuma, a altura extra só aparece quando
     há o que dizer — e é ela que faz a diferença entre um card que informa e um que esconde.

     O ponto de estado repete o desenho de `.status i` (o selo do card de portal) em vez de
     reusar a classe: `.status.vazio{display:none}` esconde o selo de quem está no ar, e aqui
     o ponto verde é justamente o que diz "no ar". Mesma paleta, mesmo tamanho, regra própria.
     A cor cumpre 1.4.11 (3:1, preenchimento) e **não é a única pista**: o `aria-label` do
     `role="img"` diz o estado por extenso, e as duas colunas de número dizem o resto. */
  /* `line-height:1.3` e os vãos curtos não são aperto gratuito: são os 10 px por card que
     fazem as cinco linhas caberem nos 213,2 px que a faixa dá a 1536x864 logado e nos 243,9 px
     de 1536x1000 (medidos nesta árvore, com a barra de links na página). O card do resumo é o
     único do painel com cinco linhas de dado; os outros têm duas. */
  .w-portais{gap:clamp(5px,.8vh,10px)}
  .rows-portais{gap:5px}
  .pr-linha{display:grid;grid-template-columns:minmax(0,1fr) auto auto;column-gap:8px;align-items:baseline;line-height:1.3}
  .pr-nome{display:flex;align-items:center;gap:6px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ink)}
  .pr-selo{width:7px;height:7px;flex:none;border-radius:50%;display:block;background:var(--faint)}
  .pr-selo-online{background:var(--ok)}
  .pr-selo-instavel{background:var(--warn)}
  .pr-selo-fora{background:var(--crit)}
  .pr-ms{color:var(--muted);white-space:nowrap}
  .pr-ms b{font-weight:600;color:var(--ink)}
  .pr-med{color:var(--faint)}
  .pr-disp{white-space:nowrap}
  /* Portal em construção ocupa as duas colunas de número com o motivo, e nenhum dígito:
     "100% de disponibilidade" num portal que ninguém sonda seria número inventado. */
  .pr-aviso{grid-column:2/-1;justify-self:end;font-size:.92em;color:var(--faint)}
  /* O SEGUNDO NÍVEL DA LINHA · a última queda de cada portal.
     **Nasce escondido**, e só aparece onde há largura e altura para ele — a mesma ideia do
     `.w .mini` (E6, item 6) e do `-webkit-line-clamp:4` dos cards de portal acima de 2200 px:
     mais espaço, mais texto; menos espaço, o número vale mais que a frase, e o detalhe
     continua a um clique no modal.

     OS DOIS NÚMEROS QUE ESCOLHERAM ESTA BORDA, medidos nesta árvore:
       · a 1536 de largura a faixa do painel dá ao card **213,2 px** (1536x864 logado) e
         **234 px** (1536x1000 logado), e as cinco linhas simples já custam 175 e 197 — as
         cinco linhas duplas custariam ~85 px a mais e o `geometria.mjs` reprovaria o corte;
       · a 1920x1080, 2560x1080 e 5120x1440 — as três resoluções que o `scripts/vazio.mjs`
         mede — o card tem 314, 314 e 321 px para **164 px** de conteúdo simples: 47,7% e 48,0%
         de vazio, contra o limite de 25% do PO. Com o segundo nível ele passa a pedir 300,3 e
         304,1 px e a usar a caixa que lhe deram.
     AS DUAS BORDAS SÃO AS MAIS BAIXAS EM QUE O CARD LOGADO NÃO CORTA, medidas uma a uma:
     1900x1080 é o piso, e **não** 1900x1000 — a 1920x1000 logado a faixa dá 257,6 px e as
     linhas duplas pedem 279,6; a 1920x1032, 278,3 contra 281,3; só a partir de ~1041 px de
     altura a conta vira, e 1080 é a borda redonda acima disso, com 13,7 px de folga. A
     largura de 1900 px é a mesma que a grade de seis colunas já usa: a 1700x1080 logado a
     folga cairia para 1,9 px, que é menos do que a diferença de renderização entre esta
     máquina e o runner do CI. */
  .pr-queda{grid-column:1/-1;display:none;font-family:"IBM Plex Mono",monospace;font-size:.84em;color:var(--faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  @media (min-width:1900px) and (min-height:1080px){ .pr-queda{display:block} }
  /* O rodapé é UMA linha, sempre, e nunca quebra: a altura do card entra na conta da faixa,
     e uma linha que às vezes vira duas é uma altura que às vezes corta. O que não couber sai
     por reticências, e o texto inteiro está no `title` e no modal. */
  .pr-rodape{font-family:"IBM Plex Mono",monospace;font-size:11px;color:var(--faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pr-rodape.desatualizado{color:var(--warn-txt)}
  /* Manchetes compartilham título, data e fonte entre o carrossel e o modal. */
  .nt-lista{display:flex;flex-direction:column;gap:10px;min-width:0;flex:none}
  .nt-item{display:flex;flex-direction:column;gap:2px;min-width:0;flex:none}
  .nt-titulo{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;min-height:2lh;font-size:13px;line-height:1.3;color:var(--ink);transition:color .2s}
  .nt-titulo:hover{color:var(--laranja)}
  .nt-meta{font-family:"IBM Plex Mono",monospace;font-size:10.5px;color:var(--faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* O que o card diz quando a resposta veio e não há manchete nenhuma, e quando a fonte não
     respondeu. A idade do dado vai no rótulo, pela `marcarEstado` da ORDEM-030; aqui é só o
     corpo, no mesmo tom do `SEM_RESPOSTA_DA_FONTE` dos outros cards. */
  .nt-vazio{font-size:13px;color:var(--muted)}

  /* No modal o ponto de estado vem antes da palavra, na coluna "Estado" — a mesma dupla
     cor + texto do card, com a palavra já visível em vez de só no `aria-label`. */
  .modal .pr-estado{font-family:"IBM Plex Sans",sans-serif}
  .modal .pr-estado .pr-selo{display:inline-block;margin-right:8px;vertical-align:middle}

  /* Aqui moravam as duas regras que desenhavam o convite de login dentro do card de tarefas
     do visitante (E6, item 6, mais o achado A da ORDEM-005). **Saíram** (ORDEM-008 §F):
     desde a ORDEM-007 o visitante não recebe card de tarefas nenhum — o caminho de login é
     o botão do topo —, então o ramo que gerava aquele `<li>` no `hub.js` ficou inalcançável
     e foi apagado junto. CSS de elemento que ninguém mais cria é peso morto que a próxima
     pessoa lê como intenção. */
  /* A lista vem logo depois do rótulo e rola por dentro quando passa da altura do card —
     barra fina, para não competir com o conteúdo. `min-height:0` é o que permite um filho de
     flex encolher abaixo do próprio conteúdo; sem ele o card cresceria e empurraria a página
     para a rolagem, que o layout não pode ter.

     ORDEM-008, item 2 (§B): era `flex:1`, e com isso a lista **tomava a altura que sobrava**
     — o campo "Nova tarefa…" ia para a base e ficavam 78 a 94 px de buraco no meio do card,
     medidos pelo `scripts/vazio.mjs`. Agora é `flex:0 1 auto`: cresce só até o conteúdo,
     encolhe (e rola) quando não cabe, e a sobra se junta embaixo do formulário. */
  .tasks{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px;flex:0 1 auto;min-height:0;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--line-strong) transparent}
  .tasks::-webkit-scrollbar{width:6px}
  .tasks::-webkit-scrollbar-thumb{background:var(--line-strong);border-radius:3px}
  .tasks::-webkit-scrollbar-track{background:transparent}
  .tasks li{display:flex;align-items:center;gap:10px;font-size:13.5px}
  .tasks input{accent-color:var(--laranja);width:16px;height:16px}
  .tasks li.done label{color:var(--faint);text-decoration:line-through}
  .tasks label{flex:1;cursor:pointer}
  .tasks .x{color:var(--faint);font-size:16px;line-height:1;padding:2px 4px;opacity:0;transition:opacity .2s}
  .tasks li:hover .x{opacity:1}
  .addtask{display:flex;gap:8px}
  .addtask[hidden]{display:none}
  /* Aviso de falha de gravação (incidente de 05/09/2026): o front não pode mais engolir
     erro em silêncio. Fica no rodapé do card, discreto mas legível — `--crit` é a mesma cor
     do indicador de portal fora do ar. */
  .aviso-falha{margin-top:8px;font-size:12px;line-height:1.35;color:var(--crit-txt)}
  .aviso-falha[hidden]{display:none}
  .addtask input{flex:1;min-width:0;background:none;border:0;border-bottom:1px solid var(--line-strong);padding:6px 0;color:var(--ink);font:inherit;font-size:13.5px;outline:0}
  .addtask input::placeholder{color:var(--faint)}

  /* ORDEM-008, item 2 (§B): era `flex:1` com `align-content:space-evenly`, e a grade
     espalhava as duas linhas de link pela altura do card — 58 a 62 px **entre** elas,
     medidos pelo `scripts/vazio.mjs`. Espaço distribuído em três pedaços continua sendo
     espaço vazio, e no meio do card incomoda mais que no rodapé. As linhas voltam a se
     encostar (o `gap` de 8 px é o único respiro entre elas) e a sobra se junta embaixo.
     Isto substitui a decisão do item 6 da E6 no ponto da distribuição; o resto do card
     (quatro colunas, selo, rótulo) não muda. */
  .links{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;align-content:start}
  .links a{min-width:0;overflow:hidden;white-space:nowrap;display:flex;flex-direction:column;align-items:center;gap:6px;padding:10px 4px;border-radius:12px;border:1px solid transparent;font-size:11px;color:var(--muted);transition:border-color .2s,background .2s}
  .links a:hover{border-color:var(--line-strong);background:var(--glass)}
  /* ORDEM-008, adendo 4 §B · o selo de duas letras. A cor do texto era `#fff` cravado, e
     no tema escuro o selo **sem cor própria** cai no `--azul` de lá (#4FA3E3, claro): branco
     sobre ele dá 2,73:1 e reprova a WCAG 2.1 AA. Não é mudança de paleta nenhuma — o par
     `--azul`/`--on-azul` existe exatamente para isto e estava sendo ignorado; com ele o mesmo
     selo dá 7,01:1.

     **O `#fff` não some, muda de lugar**, e a razão é medida: as cores próprias dos links
     (`config.js`, e as que a pessoa escolhe) são escuras e saturadas — Outlook #0F6CBD,
     Teams #5B5FC7, GitHub #3B4652 —, e sobre elas o branco dá de 5,4 a 9,6:1 enquanto o
     `--on-azul` do tema escuro (#061019) daria de 2,0 a 3,6:1. Trocar o texto no seletor
     inteiro fecharia um nó e abriria sete. Então o par viaja junto: quem tem cor própria
     traz `--ini-fg:#fff` do `selo()` em `hub.js`; quem não tem cai no par da paleta. */
  .links .ini{width:34px;height:34px;border-radius:10px;display:grid;place-items:center;font-family:"Sora",sans-serif;font-weight:600;font-size:12px;color:var(--ini-fg,var(--on-azul))}
  /* Selo com ícone: **mesma caixa** do selo de duas letras, para a grade não mexer conforme
     o link tem ou não imagem (condição do gerente).
     O fundo claro não é enfeite: os logos do GitHub e do Railway são pretos e sumiam no tema
     escuro. Um fundo previsível para todos evita depender da cor de cada marca — é o que
     lançador de aplicativo faz — e vale nos dois temas, para o selo não mudar de aparência
     quando o dia vira noite. */
  /* Especificidade acima de `.links .ini{background:var(--ini-bg)}`, que aparece depois no
     arquivo — sem isso o fundo colorido do selo venceria e o logo continuaria sumindo. */
  .links .ini.ini-img,.link-edit .ini.ini-img{background:var(--selo-img);box-shadow:inset 0 0 0 1px var(--selo-img-borda)}
  /* E6, item 8. O fundo claro existe porque os logos do GitHub e do Railway são pretos e
     sumiam no escuro — lançador de aplicativo faz o mesmo. Mas branco puro no tema escuro
     virava uma fileira de quadrados que chamava mais atenção que os próprios ícones. No
     escuro ele passa a um cinza claro menos opaco: continua separando o logo do fundo,
     sem gritar. A variável fica em um lugar só, para os dois selos (grade e editor) não
     divergirem — foi assim que a regra de especificidade acima nasceu. */
  .links .ini-img img{width:26px;height:26px;object-fit:contain;display:block}
  .link-edit .ini-img img{width:22px;height:22px;object-fit:contain;display:block}

  /* ---------- modal ---------- */
  .overlay{position:fixed;inset:0;z-index:20;background:var(--overlay);backdrop-filter:blur(8px);display:grid;place-items:center;padding:24px;opacity:0;pointer-events:none;transition:opacity .25s}
  .overlay.on{opacity:1;pointer-events:auto}
  .modal{width:min(880px,100%);max-height:min(86vh,900px);overflow:auto;border:1px solid var(--line-strong);border-radius:22px;background:var(--glass-strong);backdrop-filter:blur(24px);box-shadow:0 30px 80px rgba(0,0,0,.45);padding:26px 28px 28px;transform:translateY(14px) scale(.98);transition:transform .25s}
  .overlay.on .modal{transform:none}
  .modal header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:18px}
  .modal h3{font-size:22px;font-weight:600;letter-spacing:-.01em}
  .modal header p{margin:4px 0 0;color:var(--muted);font-size:13px}
  .modal .close{width:36px;height:36px;border-radius:999px;border:1px solid var(--line);display:grid;place-items:center;color:var(--muted);flex:none}
  /* E6, item 9. O PO: "os cards quando abertos são bem menos interessantes visualmente,
     bem menos grafismos e cores. Basicamente expande a informação."

     Cada modal passa a ter a cor do assunto dele, do mesmo jeito que os cards de portal já
     tinham (`--c` por classe, num lugar só). A cor vale para o rótulo das caixas, para as
     barras e para as linhas dos gráficos — não para fundo nem para tarja, que só fariam o
     modal parecer um aviso. Todas as cores já existem na paleta: nenhuma foi inventada
     aqui, porque cor nova é decisão de paleta, não de um modal. */
  .modal{--c:var(--azul)}
  .modal-clima{--c:var(--sun)}
  .modal-cambio{--c:var(--azul)}
  .modal-mercado{--c:var(--verde)}
  .modal-energia{--c:var(--laranja)}
  .modal-tarefas{--c:var(--roxo)}
  .modal-links{--c:var(--ouro)}
  .modal-portais{--c:var(--azul)}
  /* ORDEM-040 §4 · roxo é o único token da paleta que nenhum modal de DADO usa (azul em
     câmbio e portais, sol no clima, verde no mercado, laranja na energia): o card que traz
     texto de terceiro não se confunde com nenhum dos que trazem número medido. */
  .modal-noticias{--c:var(--roxo)}
  .modal-paleta{--c:var(--laranja)}

  /* A cor do assunto **em texto pequeno** não é a mesma coisa que a cor em barra.
     `--sun`, `--ouro` e `--verde` sobre o fundo claro do modal ficam entre 2,0:1 e 2,6:1 —
     abaixo dos 4,5:1 que o rótulo de 11 px precisa (item 15 manda conferir os dois temas,
     e é no claro que quebra). `--c-txt` puxa a cor do assunto na direção do texto do tema:
     no claro `--ink` é escuro e escurece; no escuro `--ink` é claro e clareia. Um cálculo
     só resolve os dois temas, e nenhuma cor nova entra na paleta — é mistura do que já
     existe, do mesmo jeito que `.portal:hover` e `.flag` já faziam.
     Medido depois, com os seis modais abertos nas cinco resoluções: pior caso 5,1:1
     (`--ouro`, tema claro) e 10:1 ou mais no escuro. */
  .modal{--c-txt:color-mix(in srgb,var(--c) 50%,var(--ink))}

  /* `align-items:stretch` é o que resolve o "muito espaço vazio" dos itens 10 e 13: sem
     ele, a caixa mais curta da linha ficava com a altura do conteúdo e a mais alta puxava
     a régua, deixando um vão. Com as caixas em coluna, o conteúdo pode ocupar a altura. */
  .modal .grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:14px;align-items:stretch}
  .modal .box{padding:14px 16px;border:1px solid var(--line);border-radius:14px;background:var(--glass);display:flex;flex-direction:column}
  .modal .box .lbl{font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--c-txt);margin-bottom:10px;font-weight:600}
  /* Esticar não basta: a caixa cresce e o conteúdo continua encostado no topo, que era
     exatamente a queixa do PO no clima e no setor elétrico. O conteúdo cresce junto e
     distribui a folga entre as linhas, em vez de acumular tudo embaixo. */
  .modal .box>.rows,.modal .box>.barh,.modal .box>.faixas-dia{flex:1;justify-content:space-evenly}

  /* Duas caixas lado a lado, ocupando a linha inteira.
     `auto-fit` sozinho não resolve: a régua da grade do modal é `minmax(200px,1fr)`, o que
     dá três colunas na largura de 880 px, e duas caixas deixavam a terceira vazia — o
     buraco à direita que o PO chamou de "muito espaço vazio". As colunas só ficam vazias
     de verdade quando **nenhum** item as ocupa, e as caixas `box-full` de cima ocupam
     todas, então `auto-fit` não colapsa nada. `.par` é uma grade própria de duas colunas
     (uma só abaixo de ~360 px de conteúdo, no telefone). */
  .modal .par{grid-column:1/-1;display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:14px;align-items:stretch}

  /* Barra horizontal comparativa: substitui coluna de número solto quando o que importa é
     "qual é maior", não o dígito exato — o dígito continua ao lado. */
  .barh{display:flex;flex-direction:column;gap:9px}
  .barh .l{display:grid;grid-template-columns:1fr auto;gap:8px;font-size:12.5px;align-items:baseline}
  .barh .l b{font-weight:500;font-family:"IBM Plex Mono",monospace;font-variant-numeric:tabular-nums}
  .barh .t{height:7px;border-radius:999px;background:var(--line);overflow:hidden;margin-top:4px}
  .barh .t i{display:block;height:100%;border-radius:999px;background:var(--c)}

  /* Variação com sinal (itens 11 e 12): a barra sai do meio, para a esquerda quando cai e
     para a direita quando sobe. Alta e baixa não podem ser a mesma cor — `--ok` e `--crit`
     são as que a paleta já usa para isso (bandeiras, selo de portal fora do ar). O sinal
     também vai no dígito, para quem não distingue as duas cores. */
  .barh.assinada .t{overflow:visible;position:relative}
  .barh.assinada .t::before{content:"";position:absolute;left:50%;top:-3px;bottom:-3px;width:1px;background:var(--line-strong)}
  .barh.assinada .t i{position:absolute;top:0}
  .barh.assinada .t i.sobe{left:50%;background:var(--ok)}
  .barh.assinada .t i.cai{right:50%;background:var(--crit)}
  /* Texto, logo `-txt` (adendo 5 §B). Aqui a diferença é maior do que parece: com `--warn`
     o mesmo desenho dava 4,40:1 sobre o card, **abaixo dos 4,5:1**, e nenhum instrumento
     via — `.barh` vive dentro do modal, e modal o `axe.mjs` não audita. Com `-txt` vai a
     7,00:1 (alta) e 7,37:1 (baixa). */
  .barh .l b.sobe{color:color-mix(in srgb,var(--ok-txt) 78%,var(--ink))}
  .barh .l b.cai{color:color-mix(in srgb,var(--crit-txt) 78%,var(--ink))}

  /* A carga do SIN é um número só. Centrado e com o mesmo `.big` dos cards, ele preenche
     a caixa sem enchimento inventado — era isso ou uma lista de duas linhas encostada no
     topo, que é a forma do espaço vazio que o PO apontou. (Item 13.) */
  .carga-sin{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;text-align:center;padding:6px 0}
  .carga-sin .sub{color:var(--muted);font-size:12.5px}

  /* Faixa mínima–máxima do dia: a barra mostra o intervalo, não um valor. Duas temperaturas
     numa linha de tabela não dizem que o dia é ameno ou de amplitude grande; a faixa diz. */
  .faixas-dia{display:flex;flex-direction:column;gap:10px}
  .faixas-dia .d{display:grid;grid-template-columns:auto 1fr auto;gap:10px;align-items:center;font-size:12.5px}
  .faixas-dia .dia{color:var(--muted);min-width:34px}
  .faixas-dia .t{position:relative;height:7px;border-radius:999px;background:var(--line)}
  .faixas-dia .t i{position:absolute;height:100%;border-radius:999px;background:linear-gradient(90deg,var(--azul),var(--c))}
  .faixas-dia .v{font-family:"IBM Plex Mono",monospace;font-variant-numeric:tabular-nums;color:var(--muted);min-width:62px;text-align:right}
  .modal table{width:100%;border-collapse:collapse;font-size:13px}
  .modal th{text-align:left;font-weight:500;color:var(--muted);font-size:11px;letter-spacing:.08em;text-transform:uppercase;padding:6px 8px;border-bottom:1px solid var(--line)}
  .modal td{padding:7px 8px;border-bottom:1px solid var(--line);font-family:"IBM Plex Mono",monospace;font-variant-numeric:tabular-nums}
  .modal td:first-child{font-family:"IBM Plex Sans",sans-serif}
  .modal .src{margin-top:16px;font-size:12px;color:var(--faint)}
  /* E6, item 6. O `.mini` é o mesmo desenho do modal dentro do card, e encolhe até um piso
     em vez de esticar o card. Em 390 px de largura o card já é curto — aí ele some, porque
     gráfico de 20 px de altura não informa nada e só rouba espaço do número.

     ORDEM-008, item 2 (§B): tinha `margin-top:auto`, que ancorava o mini-gráfico no rodapé
     e abria o buraco **no meio** do card — 32 px no clima, 72 a 93 px no setor elétrico,
     medidos pelo `scripts/vazio.mjs`. Foi essa a queixa literal do PO ("os gráficos de clima
     e bandeiras ancorados no rodapé deixam o vazio no meio do card"). O desenho passa a vir
     logo depois dos números e a sobra se junta embaixo. */
  .w .mini .bars{height:clamp(34px,7vh,64px)}
  /* ORDEM-008, item 3 · a versão de card das barras assinadas do modal. **Não é um desenho
     novo**: é o mesmo `.barh.assinada`, com as medidas do card — rótulo menor, barra mais
     fina, vãos mais curtos. O que muda é o tamanho, e só ele; cor, sinal e o traço do zero
     continuam vindo da regra base, num lugar só. */
  .w .mini .cap{font-size:9.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);margin-bottom:4px}
  .w .mini .barh{gap:4px}
  .w .mini .barh .l{font-size:11px;gap:6px}
  .w .mini .barh .l b{font-size:10.5px}
  .w .mini .barh .t{height:4px;margin-top:2px}
  .w .mini .flags i{height:14px}
  .w .mini .fl{font-size:9.5px}
  /* O segundo nível só aparece quando há altura para ele. Em 1536x864 o card do painel
     tem 239 px e o do clima estourava 52 px com o gráfico — medido. Abaixo de 1000 px de
     janela, o número vale mais que o desenho, e o desenho continua a um clique no modal.
     Mesma razão da regra de largura: gráfico espremido não informa, só ocupa.

     A borda era 950 até o adendo 3 §B da ORDEM-018, e de 951 a 999 px o VISITANTE cortava o
     card de mercado: 45 px a 1536×951, 28 a 1920×951, 17,8 a 1920×999, medidos, e o `main`
     igual. A partir de 1000 px a página do visitante tem folga para o gráfico; abaixo, não.
     Então a borda sobe para 999, para todos (logado, a regra da barra já o escondia ali).

     `max-height:999.98px`, e não `height < 1000px`: a sintaxe de intervalo exige Safari 16.4,
     e o `:has()` que a página já usa exige 15.4 (adendo 3 §C). O ,98 não deixa vão nem
     sobreposição com `min-height:1000px` numa altura fracionária de zoom. */
  @media (max-width:520px),(max-height:999.98px){ .w .mini{display:none} }
  .bars{display:flex;align-items:flex-end;gap:4px;height:90px}
  .bars i{flex:1;background:linear-gradient(180deg,var(--laranja),var(--azul));border-radius:3px 3px 0 0;opacity:.85}
  .bars i.now{opacity:1;outline:2px solid var(--laranja);outline-offset:1px}
  /* Só **dentro do modal** a barra vertical segue a cor do assunto (item 9). O mesmo
     desenho no card fica como o PO aprovou na PR 1: `.bars` é compartilhado entre card e
     modal desde o item 6, e mudar a regra base repintaria o card sem ordem para isso. */
  .modal .bars i{background:linear-gradient(180deg,var(--c),color-mix(in srgb,var(--c) 28%,transparent))}
  .modal .bars i.now{outline-color:var(--c-txt)}
  .flags{display:flex;gap:4px}
  .flags i{flex:1;height:22px;border-radius:4px}
  .fg{background:var(--ok)} .fy{background:var(--warn)} .fr{background:var(--crit)}
  .fl{display:flex;justify-content:space-between;font-size:10.5px;color:var(--faint);margin-top:4px;font-family:"IBM Plex Mono",monospace}

  footer{display:flex;flex-wrap:wrap;justify-content:space-between;gap:10px;color:var(--faint);font-size:12px;padding-top:8px;border-top:1px solid var(--line)}

  /* ---------- modo apresentação (E5.1) ----------
     Botão discreto no rodapé, do tamanho do texto ao lado: numa reunião ele não deve
     competir com nada. `kbd` lembra o atalho sem precisar de tooltip. */
  .btn-apresentacao{display:inline-flex;align-items:center;gap:6px;background:none;border:1px solid transparent;border-radius:999px;padding:3px 10px;color:var(--faint);font:inherit;font-size:12px;cursor:pointer;transition:color .2s,border-color .2s,background .2s}
  .btn-apresentacao:hover{color:var(--ink);border-color:var(--line-strong)}
  .btn-apresentacao kbd{font-family:"IBM Plex Mono",monospace;font-size:10px;border:1px solid var(--line-strong);border-radius:4px;padding:0 4px;line-height:1.5}
  .btn-apresentacao[aria-pressed="true"]{color:var(--on-azul);background:var(--azul);border-color:transparent}
  .btn-apresentacao[aria-pressed="true"] kbd{border-color:rgba(255,255,255,.5)}

  /* **Só o card de tarefas sai da tela** (decisão do PO, 05/09/2026, depois de avaliar o
     modo em produção): esconder quatro cards e esticar os dois restantes ficava ruim.
     Tarefa é o único conteúdo que não se projeta numa reunião com cliente; câmbio, mercado,
     links, clima e setor elétrico podem ficar. Com cinco cards a grade normal já serve, e
     por isso **não há regra especial de colunas aqui** — a versão anterior tinha uma, para
     dois cards, e ela saiu junto. `display:none` e não `visibility`: o grid tem de refluir,
     senão sobra um buraco onde o card estava. */
  [data-apresentacao="1"] .w[data-modal="tarefas"]{display:none}

  /* ---------- fit-to-viewport (sem rolagem no desktop/ultrawide) ----------
     Piso: >=1500 px de largura e >=860 px de altura. O mockup usava 720 px de altura, mas
     nessa altura o conteúdo não cabe: a linha do domínio dos cards de portal transbordava
     de 22 a 88 px, e em 1400x800 o card do Portal de Engenharia ainda jogava a linha do
     domínio 43 px para fora. A medição mostrou que a promessa só se sustenta de 1500x860
     para cima (relatório 007, seção 5). Abaixo disso a página rola e mostra tudo. */
  @media (min-width:1500px) and (min-height:860px){
    html,body{height:100%;overflow:hidden}
    .page{height:100vh;overflow:hidden;padding:14px clamp(18px,3vw,56px) 10px;gap:clamp(10px,1.7vh,26px)}
    .brand img{height:clamp(40px,5.4vh,56px)}
    .hero{padding-top:.4vh;gap:20px}
    .greet{font-size:clamp(24px,4.4vh,50px)}
    .date{margin-top:.6vh;font-size:clamp(13px,1.5vh,16px)}
    .search{margin-top:1.6vh;padding:4px 6px 4px 16px}
    .search input{padding:8px 0;font-size:15px}
    .flipclock{--h:clamp(60px,10.5vh,124px)}
    .flipclock .segundos{--h:clamp(37px,6.5vh,77px)}
    .clocklbl{font-size:11px}
    .sec{display:flex;flex-direction:column;min-height:0}
    .sec-portals{flex:1.12}
    .sec-panel{flex:1}
    /* ORDEM-018, item 2 · QUEM PAGA A ALTURA DA BARRA DE LINKS.
       A barra é uma faixa nova numa página que é `height:100vh` e **não tinha folga
       nenhuma**: medido no `main`, a 1920×1080 e a 2560×1080 o card de mercado precisa de
       exatamente os 314 px que a faixa lhe dava. Com a barra somando 70 px mais o vão de
       ~18 px, a repartição 1,12 : 1 tirava 36 px do painel e o `overflow:hidden` do card
       cortava conteúdo **em silêncio** — `mercado` perdia 36 px e `clima` 22.

       A repartição passa a 0,9 : 1 acima de 1000 px de altura, e isso NÃO é número
       escolhido: é o resultado de varrer 1,12 · 1,0 · 0,9 · 0,8 · 0,7 · 0,6 e medir
       `scrollHeight - clientHeight` de cada card em cada resolução. A 1920×1080 e a
       2560×1080, **0,9 é o único valor da varredura com corte zero** — o painel volta aos
       314 px e o card de portal cai de 281 para 280, um pixel. De 0,8 para baixo a conta
       inverte e são os cards de portal que passam a cortar (RFP e Engenharia, 21 px a 0,8).

       Abaixo de 1000 px de altura a repartição **fica como estava**, porque lá 0,9 piora:
       a 1600×900 leva o corte de zero para 21 px em dois cards de portal, e a 1536×864 leva
       Engenharia de 34 para 61 px. A banda dos portais é quem está apertada nessas alturas,
       e tirar dela é tirar de quem não tem.

       A **1536×864 logado** nenhuma repartição da varredura zerava o corte: sobravam **25 px**
       no Portal de Engenharia, a linha de ferramentas do único card com quatro, e o `main`
       não os tinha. Encurtar a descrição do card de portal compraria 18 deles, mas pegaria o
       VISITANTE, que não tem barra nem corte. **Fechado no adendo 1 §B, na barra**: ver
       "QUEM RECEBE O QUE A BARRA DEVOLVE", junto das regras dela, mais abaixo. */
    @media (min-height:1000px){ .sec-portals{flex:.9} }
    .sec-head{margin-bottom:clamp(6px,1vh,12px)}
    .sec-portals,.sec-panel{--wgap:clamp(8px,1.2vw,14px)}
    .portals,.widgets{flex:1;min-height:0;gap:var(--wgap)}
    /* DESVIO DELIBERADO em relação ao mockup, para cumprir o critério de aceite da E2
       ("layout sem rolagem em >=1400 px de largura e >=720 px de altura").
       O mockup usa auto-fit/minmax, que abaixo de ~1900 px rende 4 colunas de portal e 5
       de widget; com overflow:hidden do modo sem-rolagem, a segunda linha some cortada.
       Em 1536x864 (uma das quatro resoluções que o escopo manda testar) o próprio mockup
       corta o Portal de Ativos e metade do painel. Fixando as colunas, tudo cabe em uma
       linha (cards de 278 px, widgets de 229 px em 1536 px). Registrado no relatório 006. */
    /* E6, item 7, e ORDEM-008 item 1. `.portals{flex:1}` e `.widgets{flex:1}` davam a cada
       grade toda a altura da seção, e a linha única esticava para preencher — em 5120x1440 o
       card do painel ficava com o dobro da altura do seu conteúdo. `align-content` faz a
       linha tomar a altura do **conteúdo**; o valor diz onde fica a sobra.

       Era `center` nos portais (item 7, PR 1) e, acima de 1200 px de altura, também no painel
       (item 17(a), PR 3): a sobra ficava dividida em cima e embaixo. **Passa a ser `start`
       nas duas faixas**, por decisão do PO de 06/09/2026 (ORDEM-008 §2): a linha encosta no
       título da seção e o respiro inteiro fica no rodapé. É o mesmo princípio do item 2, um
       nível acima — espaço partido em dois pedaços é dois buracos; junto num lugar só é
       margem.

       Duas consequências medidas, e as duas são o que o item 4 pede: a regra agora vale em
       **toda** a faixa sem rolagem (era `min-height:1200px` só para o painel), então a 1080
       de altura o card do painel passa a ter a altura do conteúdo em vez de 320 px fixos; e
       onde não há sobra (1536x864, a resolução mais apertada do critério de aceite) nada
       muda, porque não há espaço para distribuir. */
    /* ORDEM-044 · DE CINCO PARA SEIS COLUNAS, E O QUE ISSO CUSTOU EM ALTURA.
       A largura do card cai de 278 para **229 px** a 1536, e de 318 para **256,3 px** de 1900
       a 2199 — a mesma largura que os cards do painel têm. Nenhuma coluna a mais: seis cards
       em cinco colunas abriria uma segunda linha que o `overflow:hidden` corta.

       **ORDEM-046 · QUEM PAGA A DIFERENÇA DEIXOU DE SER O PORTAL DE ENGENHARIA.** Ele saiu de
       "em construção" e trocou as quatro pílulas por uma só (`Motores`), então o card mais alto
       da fileira passou a ser o do RFP, que também tem quatro. A regra do corte da descrição
       **não mudou**, e a janela de duas linhas logo abaixo **continua onde estava**: ela é
       decisão de produto da ORDEM-044 e desfazê-la é decisão de produto também. Medido em
       14/10/2026, com a janela removida em memória, a 1920×1080 logado: `geometria.mjs` fica
       verde (1065 medidas, 0 falhas — a terceira linha **passa a caber**), e `vazio.mjs`
       **reprova duas vezes**, porque a fileira sobe de 241 para 261 px e Engenharia e CRM, que
       têm pouca pílula, vão a 28,4% e 29,4% de ar. Trocar a terceira linha por duas entradas
       novas na catraca é o que o gerente precisa decidir, e não o `front`.

       O parágrafo abaixo é o registro do que valia na ORDEM-044, e continua valendo como
       história do número: quatro pílulas num card estreito não cabem em duas fileiras.

       **Quem pagava a diferença era o Portal de Engenharia**, o único cujas quatro ferramentas
       não cabiam em duas fileiras quando o card encolhia. Medido nesta árvore, logado: a
       256,3 px as quatro pílulas ocupam **três** fileiras (93,8 px) onde a 318 px ocupavam
       duas (60,5 px) — **33,3 px a mais** num card que a 1920×1080 tinha **3,4 px** de folga.
       Sem devolver esses 33 px, `geometria.mjs` reprova **96 das 1065** medidas, com
       Engenharia cortando 34,16 px a 1920×1080 logado e arrastando o card de clima junto
       (12,31 px a 1920×860), porque a faixa dos portais cresce e o painel fica com o resto.

       **A ÚNICA COISA QUE MUDA PARA DEVOLVÊ-LOS É O CORTE DA DESCRIÇÃO**, logo abaixo, e as
       duas tentativas que não ficaram estão medidas para não serem tentadas de novo:

         · **dar o piso da faixa aos portais em toda a faixa sem rolagem** (tirar o
           `max-height:1079.98px` da regra do adendo 1) zera o corte dos portais e **passa o
           corte ao painel**: a 1920×1080 logado o mini corta 20,14 px em clima e 34,44 px em
           mercado. Escondendo o mini junto, `geometria.mjs` fica verde — e `axe.mjs`
           **reprova**: `#climaBarras` mora dentro do `.mini`, e sem ele a leitura ao apontar
           no card (ORDEM-043) deixa de existir a 1920×1080, que é onde ela é auditada. Régua
           verde apagando um recurso da rodada anterior.
         · **cortar a descrição em duas linhas em toda a faixa** fica geometricamente igual ao
           que ficou, e tira a terceira linha também de 1536×864 e 1536×1080, onde ela cabe.

       Por isso o corte da descrição desce **só na janela em que o card é estreito E a faixa
       não pode crescer**, e não em toda parte. */
    .portals{grid-template-columns:repeat(6,1fr);align-content:start}
    .widgets{grid-template-columns:repeat(6,1fr);align-content:start}
    /* Com cinco colunas em 1536 px o card fica com 278 px e a descrição do Portal de
       Engenharia (o único com quatro ferramentas) empurrava a linha do domínio 8 px para
       fora. Limitar a descrição a três linhas resolve. Em 1920 e 2560 px as descrições já
       ocupam três linhas, então esta regra não muda nada lá. */
    .portal p{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}
    /* E6, item 1: o corte em três linhas nasceu quando o rodapé de endereço ocupava a
       base do card. O rodapé saiu (item 3) e sobrou espaço — mas só onde o card é largo.
       Em 1536 px o card tem 278 px e o Portal de Engenharia, com quatro labels, gasta
       três linhas só nelas: a quarta linha de texto estourava a caixa em 9 px, medidos.
       Acima de 1700 px o card cresce e a quarta linha cabe. Mais largura, mais texto
       visível — em vez de um número fixo que serve mal aos dois casos.

       ORDEM-044 · A BORDA ERA 1700 E PASSA A 2200, E É A MESMA REGRA, NÃO OUTRA. O gatilho
       sempre foi a **largura do card**, escrita em largura de janela porque a grade tinha
       cinco colunas. Com seis ela deixou de valer: de 1900 a 2199 o card tem 256,3 px —
       *menos* que os 278 de 1536 com cinco colunas —, porque a `.page` está no teto de
       1720 px e a largura se divide por seis. O card só volta a crescer onde o teto da
       página sobe para 1960 (`min-width:2200px`, mais abaixo): ali ele vai a **296,3 px**,
       e 296 é o primeiro valor em que Engenharia volta a caber com quatro linhas — medido,
       a 1920×1080 logado a quarta linha estoura a caixa em **14,2 px**, e a 2560×1080 sobra.
       **1700 não é um número que envelheceu: é um número que descrevia 318 px de card.** */
    @media (min-width:2200px){ .portal p{-webkit-line-clamp:4} }
    /* A JANELA DE DUAS LINHAS (ORDEM-044), E POR QUE ELA É UMA JANELA E NÃO UM PISO.
       Ela é a interseção exata de duas condições que já existem no arquivo, e fora dela a
       descrição continua com as três linhas de sempre:

         · **1900 a 2199 px de largura** é onde o card é mais estreito do que em 1536 (256,3
           contra 278 px): a `.page` está no teto de 1720 px e a largura se divide por seis.
           A 2200 o teto sobe para 1960, o card vai a 296,3 px e a quarta linha volta.
         · **1080 px de altura ou mais** é onde a faixa dos portais **não** tem o piso do
           adendo 1 (`max-height:1079.98px`), e por isso não pode pedir a altura do próprio
           conteúdo: a repartição 0,9 lhe dá 309,9 px e o card de Engenharia pede 342.

       Abaixo de 1080 o piso existe, a faixa cresce, e as três linhas cabem — medido a
       1920×1000 logado, onde sobra 0,4 px. **É por isso que mais largura pode significar
       menos texto aqui, e não é descuido:** o que manda é a altura que a faixa consegue
       pedir, não a largura da janela. O texto inteiro continua no card do portal a partir de
       2200 px e na descrição do próprio portal; o que sai é a terceira linha, não o sentido
       da frase — as descrições são escritas com o assunto na primeira oração.

       Medido, a 1920×1080 logado: com três linhas Engenharia estoura a caixa em 14,2 px; com
       duas, `geometria.mjs` fecha em 1065 medidas e 0 falhas. */
    @media (min-width:1900px) and (max-width:2199.98px) and (min-height:1080px){ .portal p{-webkit-line-clamp:2} }
    .portal{min-height:0;padding:clamp(12px,1.8vh,20px) 18px;gap:clamp(8px,1.2vh,14px)}
    .portal .icon{width:clamp(34px,4.2vh,44px);height:clamp(34px,4.2vh,44px)}
    .portal h3{font-size:clamp(15px,1.9vh,18px)}
    .portal p{font-size:clamp(12px,1.35vh,13.5px);line-height:1.45}
    .tools a{font-size:11.5px;padding:4px 8px}
    .w{min-height:0;overflow:hidden;padding:clamp(12px,1.6vh,18px);gap:clamp(6px,1vh,12px)}
    .big{font-size:clamp(28px,3.8vh,40px)}
    .rows{gap:clamp(4px,.7vh,8px)}
    /* ORDEM-039 §3 · o resumo tem cinco linhas onde os outros cards têm duas: o vão
       acompanha o aperto da faixa, e o rodapé encolhe junto com o resto. */
    .rows-portais{gap:clamp(3px,.5vh,5px)}
    .pr-rodape{font-size:clamp(10px,1.15vh,11px)}
    .row,.row .v{font-size:clamp(12px,1.35vh,13.5px)}
    .spark{height:clamp(28px,4vh,44px)}
    .links a{padding:clamp(4px,.8vh,10px) 4px;gap:4px}
    .links .ini{width:clamp(28px,3.4vh,34px);height:clamp(28px,3.4vh,34px)}
    .tasks{gap:4px}
    .more{display:none}
    footer{font-size:11px;padding-top:4px}
  }
  @media (min-width:2200px){ .page{max-width:1960px} }

  /* ---------- E6, item 17 · o esticamento dos cards do painel ----------
     A ALTERNATIVA (a) foi escolhida pelo PO em 06/09/2026, ao vivo, olhando a tela; a (b)
     — alargar o conteúdo — continua recusada e existe só como captura
     (`scripts/capturas.mjs`, bloco do item 17).

     **A regra que morava aqui saiu, e não porque a decisão mudou.** Era
     `@media (min-width:1500px) and (min-height:1200px){ .widgets{align-content:center} }`, e
     ela fazia duas coisas ao mesmo tempo: a linha tomar a altura do conteúdo (que fica) e a
     sobra ser dividida em cima e embaixo (que o PO revogou na ORDEM-008 §2). O que fica foi
     dobrado no bloco sem-rolagem acima, como `align-content:start`, junto com a linha dos
     portais — as duas faixas seguem a mesma regra, e uma regra só é mais fácil de manter
     verdadeira que duas.

     O gatilho por altura também saiu, e é mudança de propósito (ORDEM-008, item 4): com
     `min-height:1200px` o painel continuava esticado a 1080 de altura, que é **a janela do
     PO** (2560×1080) e onde o critério dos 25% tem de fechar. Medido nesta rodada, a
     1920×1080 e a 2560×1080 o card do painel era de 320 px com 103 a 250 px de conteúdo.

     O que a regra antiga media continua registrado, porque é o número que justifica tudo
     isto (altura esticada → altura do conteúdo → sobra):

       1536× 864   241 → 206 →  35 px (17%)      1920×1080   320 → 300 →  20 px  (7%)
       2560×1080   320 → 300 →  20 px  (7%)      1920×1200   369 → 307 →  62 px (20%)
       2560×1440   471 → 307 → 164 px (53%)      5120×1440   471 → 307 → 164 px (53%)
       3840×1600   542 → 307 → 235 px (77%) */

  /* ---------- E6, ORDEM-007 item B · a faixa se recompõe com 4, 5 ou 6 cards ----------
     A faixa passou a ter três tamanhos: **4** para o visitante (clima, câmbio, mercado,
     setor elétrico), **5** no modo apresentação e **6** para quem entrou. Com
     `repeat(6,1fr)` os quatro do visitante ficavam encostados à esquerda e sobravam duas
     colunas vazias à direita — espaço de um lado só, que foi a queixa do PO.

     A regra: **a largura do card não muda**. `--colw` é exatamente a largura que a linha de
     seis dá — `(100% - 5 vãos) / 6` — e as três variantes só mudam **quantas** colunas
     existem. `justify-content:center` põe a linha no meio e divide a sobra nos dois lados.
     Com seis cards a conta rende o mesmo que `repeat(6,1fr)`, então a tela de quem está
     logado é a mesma de antes, pixel a pixel.

     **Alargar o card foi recusado pelo PO** (alternativa (b) do item 17): card mais largo
     não faz o conteúdo crescer junto e reabre o vão entre o texto e a base — a queixa que
     originou a E6.

     O número de cards vem do `data-cards` que o `hub.js` escreve contando o que está
     desenhado, e não do estado da sessão: no modo apresentação o card de tarefas sai com
     `display:none`, e elemento assim não é item de grade. Contar a página é o único jeito
     de as duas contas não divergirem.

     A lista de mídia tem duas entradas porque a grade de seis colunas nasce em dois lugares:
     no bloco sem-rolagem (a partir de 1500×860) e na regra de 1900 px de largura, que vale
     quando a janela é larga e baixa demais para o modo sem-rolagem. Abaixo disso a página
     rola e a grade é `auto-fit`, que já se acomoda sozinha. */
  @media (min-width:1500px) and (min-height:860px),(min-width:1900px){
    .sec-panel{--colw:calc((100% - 5 * var(--wgap)) / 6)}
    .widgets{justify-content:center}
    .widgets[data-cards="4"]{grid-template-columns:repeat(4,var(--colw))}
    .widgets[data-cards="5"]{grid-template-columns:repeat(5,var(--colw))}
    .widgets[data-cards="6"]{grid-template-columns:repeat(6,var(--colw))}

    /* ---------- ORDEM-040 §4 · a SÉTIMA coluna, e por que ela é a única que muda a largura
       A regra acima diz que "a largura do card não muda": `--colw` é a largura que a linha de
       SEIS dá, e as variantes de 4 e 5 só mudam quantas colunas existem. Com o card de
       notícias o estado LOGADO passa a ter sete cards, e sete cards de `--colw` não cabem —
       `7 × --colw + 6 vãos` passa de `100%` por construção. Não há escolha a fazer aqui: ou a
       coluna encolhe, ou o sétimo card quebra para uma segunda linha que o `overflow:hidden`
       do modo sem-rolagem corta em silêncio (é o que o `hub.css` fazia antes desta regra, e o
       que o item 57 do `STATUS.md` mediu na reconstrução do `capturas.mjs`).

       **Quem encolhe é só quem entrou.** Para o visitante a linha de seis fica CHEIA, com a
       largura da PR #41 sem um pixel de diferença — 296,3 px a 2560 e a 5120, 256,3 a 1920,
       229 a 1536 (medidos nesta árvore). Logado, a coluna vai para 252, 217,7 e 194,3.

       O VÃO INTERNO DO CARD ACOMPANHA, e o 1,08 px que ele devolve não é enfeite: a 1920×1080
       logado, e **só ali**, o rótulo "MERCADO · B3 · atraso de 30 min" deixa de caber numa
       linha a 217,7 px e passa a ocupar duas, +17,2 px. A faixa dá 328 px e o card de mercado
       passa a pedir 330,2 — 2 px de corte, que o `geometria.mjs` reprova. Medido ponto a
       ponto de 1040 a 1120 px de altura: **1080 é a única altura que corta**, e três vãos de
       `.9vh` em vez de `1vh` devolvem 3,24 px. O `padding` do card faria o mesmo (medido
       também); o vão foi o escolhido por mexer no espaço ENTRE os blocos do card, e não na
       moldura que o PO aprovou. */
    .widgets[data-cards="7"]{grid-template-columns:repeat(7,calc((100% - 6 * var(--wgap)) / 7))}
    /* O RÓTULO DO CARD É UMA LINHA, SEMPRE — e é esta regra, não a largura, que paga a
       sétima coluna. Medido nesta árvore, logado, com os oito links de referência na barra:
       a 217,7 px o rótulo "MERCADO · B3 · atraso de 30 min" passa a ocupar duas linhas
       (+17,2 px) e o card pede 328 px numa faixa de 314 — **14 px de corte**; a 194,3 px é o
       "CLIMA · CAMPINAS · agora" que quebra, e o corte é de 13 px a 1536×1000. A faixa não
       tem esses 14 px para dar: quem os gastou foi a barra de links da ORDEM-018.

       A saída é a do `.pr-rodape` do card de portais, palavra por palavra: **uma linha
       sempre, e o que não couber sai por reticências**, com o texto inteiro no `title`
       (`marcarEstado`, no `hub.js`). O que se perde é o detalhe do rótulo do mercado
       ("atraso de 30 min", que está no modal); o que **não** se perde é a idade da ORDEM-030
       — "há 3 h" tem 8 caracteres e cabe com folga em qualquer das três larguras. Um rótulo
       de duas linhas custaria uma manchete inteira do card de notícias, todo dia, em troca
       de nada.

       Vale só com sete cards: com seis o rótulo cabe e nada aqui se aplica. */
    .widgets[data-cards="7"] .w{padding-inline:clamp(10px,1.1vh,14px)}
    .widgets[data-cards="7"] .w :is(.lbl,.lbl-fim) > span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

    /* ---------- ORDEM-018, item 1 · o cabeçalho acompanha a linha de cards ----------
       O DEFEITO, medido antes de consertar (11/09/2026, ver o relatório da rodada): entre
       logado e deslogado **nada muda** na largura do contêiner, no `max-width`, na margem
       nem no padding — `.sec-panel`, `.sec-head` e `.widgets` medem os MESMOS 1848 px a
       2560, 1608 a 1920 e 1443,8 a 1536. O que muda é **uma coisa só**:
       `grid-template-columns` passa de `repeat(6,--colw)` para `repeat(4,--colw)`, e o
       `justify-content:center` da regra acima divide a sobra nos dois lados. A linha de
       cards encolhe e **centra**; o cabeçalho continua ocupando a faixa inteira, com o
       título colado na borda esquerda e o "clique num card…" colado na direita.

       O deslocamento é exatamente meia sobra, `(6 - N) / 2 × (--colw + --wgap)`, e foi esse
       o número medido nos dois lados, em cada resolução, com 4 cards:

         5120×1440 e 2560×1440 e 2560×1080 → 310,3 px      1920×1080 → 270,3 px
         1536×864 → 243,0 px                               390×844 → 0 (a grade não centra)

       A CORREÇÃO: o cabeçalho passa a ter **a largura da linha de cards** e a centrar com
       ela — `N` colunas mais `N-1` vãos —, e não um recuo fixo. É a hipótese do PO ("a
       posição deles precisa variar junto com a posição dos cards") escrita como a mesma
       conta que governa a grade, e não como um segundo número que poderia divergir dela.
       Por isso `--colw` e `--wgap` subiram para `.sec-panel`: **uma conta só, dois usos.**

       `:has()` porque o `data-cards` está na grade e o cabeçalho é irmão dela. Manter o
       atributo onde está é de propósito: `scripts/capturas.mjs` reconstrói a alternativa do
       item 17 lendo `.widgets[data-cards]`, e mover o atributo quebraria o instrumento em
       silêncio (ele pararia alto, mas por outro motivo). Com 6 cards não há regra: a linha
       já ocupa a faixa inteira e o cabeçalho também.

       Vale **só dentro deste bloco de mídia**, que é o único onde a grade centra. Abaixo de
       1500×860 (e de 1900 de largura) a grade é `auto-fit` e preenche a faixa toda nos dois
       estados — o desvio medido lá é 0, e regra nenhuma tem o que corrigir. */
    .sec-panel:has(.widgets[data-cards="4"]) .sec-head{width:calc(4 * var(--colw) + 3 * var(--wgap));margin-inline:auto}
    .sec-panel:has(.widgets[data-cards="5"]) .sec-head{width:calc(5 * var(--colw) + 4 * var(--wgap));margin-inline:auto}
  }

  /* ---------- ORDEM-018, item 2 · a barra horizontal de links rápidos ----------
     O PO pediu o card de links "como uma barra horizontal entre os cards dos portais e o
     painel do dia". O elemento é o MESMO `.w[data-modal="links"]` de antes (ver o comentário
     do `index.html`); o que muda é onde ele mora e como se arruma por dentro.

     TRÊS DECISÕES QUE A ORDEM MANDA PROPOR, E NÃO ESCOLHER EM SILÊNCIO:

     1. **Os cards que sobram NÃO alargam.** `--colw` continua sendo `(100% - 5 vãos) / 6`,
        então clima, câmbio, mercado, setor elétrico e tarefas têm exatamente a largura que o
        PO aprovou na PR #41 — 296 px a 2560, 256 a 1920, 229 a 1536 —, e a linha de cinco
        fica centrada com meia coluna de ar de cada lado (o cabeçalho acompanha, item 1).
        A alternativa é dividir por 5 e deixar os cinco preencherem a faixa: o card ganharia
        ~21% de largura **sem o conteúdo crescer junto**, que é literalmente a alternativa (b)
        do item 17 que o PO recusou, e que a régua do `scripts/vazio.mjs` mede — mais largura
        com o mesmo conteúdo é mais ar dentro do card, e a catraca dos 25% é o portão disso.
        Está nas capturas `barra-links-alternativa-colunas-*` para ele ver e decidir.

     2. **Quando os oito não cabem em linha, eles QUEBRAM — não rolam e não encolhem.**
        `auto-fit` com piso de 132 px: acima disso os oito ocupam uma linha só; abaixo, a
        grade quebra em duas, três ou quatro fileiras sozinha. Rolagem horizontal foi
        recusada por esconder conteúdo sem aviso (e sem parada de tabulação visível);
        encolher abaixo do piso corta o rótulo, e rótulo cortado num link é o mesmo que
        rótulo ausente. Medido: a linha única se mantém até 820 px de largura de janela.
        A alternativa rolante está na captura `barra-links-alternativa-rolagem-390x844-*`.

     3. **O "editar" vai para a ponta direita da barra** (adendo 1 §B: o `front` recomendou,
        o gerente concordou). Mudou de lugar no DOM, depois dos links, e não por `order`: a
        tabulação segue o documento, e com `order` o foco pularia do título para a ponta e
        voltaria ao primeiro ícone. Na primeira volta ele ficava colado no título, e essa é
        agora a alternativa descartada.

     O card fica com `flex-direction:row`: o cabeçalho vira uma coluna estreita à esquerda e
     os links tomam o resto. É isso que faz a barra ser BAIXA — cada link passa de
     ícone-sobre-rótulo para ícone-ao-lado-do-rótulo, e a altura da faixa cai para a de uma
     linha de selo em vez de duas. Sem isso a "barra" teria a altura de um card e não seria
     barra nenhuma. */
  .sec-links .w[data-modal="links"]{flex-direction:row;align-items:center;gap:16px;min-height:0;padding:10px 16px}
  /* O `translateY(-3px)` de `.w:hover` é gesto de card: numa faixa que atravessa a tela
     inteira ele vira a página inteira balançando. Fica só a borda acendendo. */
  .sec-links .w[data-modal="links"]:hover{transform:none}
  .sec-links .lbl{flex:none;flex-direction:column;align-items:flex-start;gap:2px;max-width:150px}
  .sec-links .lbl-dir{margin:0}
  .sec-links .links{flex:1;min-width:0;grid-template-columns:repeat(auto-fit,minmax(132px,1fr));gap:6px}
  .sec-links .links a{flex-direction:row;justify-content:center;gap:8px;padding:6px 8px;text-align:left}
  .sec-links .links .ini{flex:none}
  /* O clique no corpo continua abrindo o editor, como no card — `ligarCardDoPainel` é o
     mesmo e ignora cliques em `a`, `button`, `input`, `label` e `form`. Não é mudança de
     comportamento, é o comportamento que o card já tinha, agora numa caixa mais larga. */

  /* A barra encolhe onde a altura é curta (ORDEM-018, item 2, e adendo 1 §B). Não é gosto:
     entre 860 e 1000 px de altura a página não tem folga nenhuma e cada pixel da barra sai do
     conteúdo de um card. A barra passa de 70 px para **30** (selo de 22 px, sem respiro em
     volta do link, 2 px de borda a borda) e o vão da página em volta dela fecha 4 px de cada
     lado. Medido a 1536×864, logado, e é o que a barra devolve à página: 48,6 px de barra
     mais 14,7 de vão viraram 30 mais 10,7 — **22,6 px**.

     O que foi medido e NÃO serve, para ninguém propor de novo:
       · ícones sem rótulo: **0 px**. O rótulo fica AO LADO do selo, e a altura do link é a
         do selo; tirar o texto estreita a barra, não a abaixa;
       · o "editar" na ponta: 0,6 px. Tira a segunda linha do título, mas a altura da barra
         já era a do link, não a do título.

     O que a barra devolve não chega, sozinho, aos portais — e isso decide o bloco seguinte.

     As faixas desta seção são `max-height:NNN.98px`, e não a sintaxe de intervalo, pela razão
     de compatibilidade escrita na regra do `.mini`, mais acima. */
  @media (min-width:1500px) and (max-height:999.98px){
    .sec-links .w[data-modal="links"]{padding:2px 14px;gap:12px}
    .sec-links .links a{padding:0 6px}
    .sec-links .links .ini{width:22px;height:22px}
    .sec-links .links .ini-img img{width:17px;height:17px}
  }
  /* QUEM RECEBE O QUE A BARRA DEVOLVE (adendo 1 §B, corte zero a 1536×864 logado).
     A repartição 1,12 : 1 dá aos portais só 53% de cada pixel liberado: com a barra de 30 px
     e sem esta regra o Portal de Engenharia ainda corta **11 px** (medido). E o que falta
     não é proporção, é piso: a 1536×864 o card de Engenharia precisa de 264,7 px e a faixa
     dos portais, com título, de 292,8.

     Então a faixa dos portais **deixa de encolher abaixo do próprio conteúdo** —
     `min-height:auto`, o piso natural de item flex, que o bloco sem-rolagem tinha desligado
     com `.sec{min-height:0}` — e o painel fica com o resto. Não é número escolhido: o piso é
     o conteúdo de cada resolução, e onde a repartição já dá mais que o conteúdo ele não faz
     nada. A 1536×864 o painel fica com 241,3 px e o card mais exigente dele (clima) precisa
     de 234 — **7,4 px de margem**, medidos.

     **Só com a barra na página.** `:has()` casa com a seção da barra sem `hidden`, e o
     visitante não tem barra: para ele esta regra não existe, e a impressão digital da página
     do visitante (retângulo de todo elemento fora do relógio) sai idêntica antes e depois. */
  @media (min-width:1500px) and (min-height:860px) and (max-height:999.98px){
    .sec-links{margin-block:-4px}
  }
  /* A BORDA DE 1000 PX (adendo 2 §A). Estas faixas eram `max-height:1000px` e a repartição
     0,9 é `min-height:1000px`: a exatamente 1000 px as duas valiam, e o mercado cortava 2 px.
     Passaram a `height < 1000px` e, no adendo 3 §C, a `max-height:999.98px`, que dá o mesmo
     sem exigir Safari 16.4: não toca a outra nem deixa vão entre elas.

     **Só separar as faixas não zerava nada**, e a borda era a ponta visível de uma faixa
     inteira. Medido logado a 1920 e a 2560 de largura, antes desta mudança:
       999 → 36 px (mercado)   1000 → 2 px   1001 → 26 px   960 → 43 px   1040 → 14 px
       1080 → 1 px. Zero só abaixo de 951 e a partir de ~1090.
     A causa é o `.mini`: ele aparece a partir de 951 px (regra do E6 item 6, mais acima) e
     pede ~22 px a 951 que a página com a barra não tem. Com a barra compacta, o mini e o piso
     dos portais, faltam ainda 2 px a 1000; com a barra cheia, 49 px a 1001 e 1 px a 1080.

     Então, **com a barra na página e abaixo de 1080 px**, vale para o mini a razão que já
     o esconde abaixo de 950 (1000 desde o adendo 3, para todos) — "o número vale mais que
     o desenho, e o desenho continua a um clique no modal" — e os portais guardam o piso do bloco anterior. O limite é 1080 e não
     outro porque 1920×1080 e 2560×1080 são resoluções do aceite com captura aprovada: ali
     nada muda. Visitante: nenhuma destas regras existe para ele.

     **Abaixo de 1900 de largura a faixa vai até 1129** (adendo 3, varredura a 1536). Com quatro
     colunas de portal em vez de cinco, o mesmo mini cortava logado de 1080 a 1126 px a 1500,
     1536 e 1600 de largura: mercado 17,5 px e Portal de Engenharia 14,6 a 1080, caindo a 1 px
     em 1126 (medido; a 1700, 1800 e 1899 já era zero). Nenhuma resolução do aceite cai ali. */
  @media (min-width:1500px) and (min-height:860px) and (max-height:1079.98px),
         (min-width:1500px) and (max-width:1899.98px) and (min-height:860px) and (max-height:1129.98px){
    .page:has(> #secLinks:not([hidden])) > .sec-portals{min-height:auto}
    .page:has(> #secLinks:not([hidden])) .w .mini{display:none}
  }

  @media (max-width:820px){
    .sec-links .w[data-modal="links"]{flex-direction:column;align-items:stretch;gap:10px}
    .sec-links .lbl{max-width:none;flex-direction:row;align-items:center;justify-content:space-between}
    .sec-links .lbl-fim{align-self:flex-end}
    .hero{grid-template-columns:1fr;align-items:start}
    .clockwrap{align-items:flex-start}
    .flipclock{--h:clamp(56px,14vw,72px)}
    .flipclock .segundos{--h:clamp(35px,8.7vw,45px)}
    .topbar .chip{display:none}
    .brand img{height:36px}
    .seg button span{display:none}
  }
  @media (prefers-reduced-motion: reduce){ .portal,.w,.overlay,.modal{transition:none} }

  /* ---------- cores dos cards de portal ----------
     No mockup isto era style="--c:..." em cada card. Vira classe para o HTML ficar sem
     atributo style e a CSP poder recusar 'unsafe-inline'. */
  .portal-rfp{--c:var(--azul)}
  .portal-engenharia{--c:var(--laranja)}
  .portal-propostas{--c:var(--verde)}
  .portal-leads{--c:var(--roxo)}
  .portal-ativos{--c:var(--ouro)}
  .portal-crm{--c:var(--magenta)}

  /* cor de cada link rápido: o JS define --ini-bg a partir de js/config.js (CSSOM,
     que a CSP não bloqueia), em vez de style="background:..." no HTML */
  .links .ini{background:var(--ini-bg,var(--azul))}

  /* variantes que no mockup eram style= soltos */
  .big-ibov{font-size:30px}
  .big-ibov sup{font-size:13px}
  .box-full{grid-column:1/-1}
  /* Item 11. A linha de 30 pregões subia e descia sem dizer de quanto para quanto: era um
     traço azul cravado, sem referência de escala. Agora ela segue a cor do modal, ganha
     área sob a curva (para a subida ter peso visual) e duas guias tracejadas com o mínimo
     e o máximo do período **escritos ao lado** — o desenho responde "andou muito?", o
     dígito responde "de quanto para quanto". Os rótulos são HTML, não `<text>` no SVG:
     o `preserveAspectRatio="none"` que estica a curva esticaria a letra junto. */
  .chart-wrap{position:relative}
  .chart-30d{display:block;width:100%;height:120px;color:var(--c)}
  .chart-30d .area{fill:currentColor;opacity:.13;stroke:none}
  .chart-30d .linha{fill:none;stroke:currentColor;stroke-width:2}
  .chart-30d .guia{stroke:var(--line-strong);stroke-width:1;stroke-dasharray:4 5}
  .chart-wrap .ref{position:absolute;right:0;font-size:11px;font-family:"IBM Plex Mono",monospace;font-variant-numeric:tabular-nums;color:var(--muted);background:var(--glass-strong);border-radius:5px;padding:0 5px;pointer-events:none}
  .chart-wrap .ref.alta{top:0}
  .chart-wrap .ref.baixa{bottom:0}
  /* No modal a lista também rola por dentro: com muitas tarefas, o modal passaria da altura
     da tela e a página inteira ganharia rolagem. */
  .tasks-modal{font-size:15px;gap:10px;max-height:60vh}
  /* E6, item 14. Tarefas e links ficaram de fora do tratamento dos quatro modais de dados e
     pareciam de outro produto: nenhuma cor, nenhuma caixa, só uma lista solta na folha.
     Passam a usar a mesma caixa e o mesmo espaçamento dos outros — a cor entra no rótulo,
     na marca do checkbox e no foco, nunca em fundo. **A função não muda**: mesma lista,
     mesmo formulário, mesmas setas, mesmas rotas, mesmo teclado. */
  .modal-tarefas .tasks input{accent-color:var(--c)}
  .modal-tarefas .tasks li.done label{color:var(--faint)}

  /* ---------- editor de links no modal (E5.3) ----------
     Opção A: lista vertical com setas ↑↓ e ×, mais um formulário curto embaixo. O card não
     muda; toda a edição vive aqui. Rola por dentro pelo mesmo motivo da lista de tarefas —
     com muitos links, o modal passaria da altura da tela. */
  /* A caixa do editor passou a ser uma `.box` como as outras (item 14): mesma borda, mesmo
     raio, mesmo fundo e mesmo padding dos quatro modais de dados. Antes era um bloco solto
     encostado no topo da folha. */
  .editor-links{margin-bottom:14px;padding:14px 16px;border:1px solid var(--line);border-radius:14px;background:var(--glass)}
  .editor-links .lbl{font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--c-txt);margin-bottom:10px;font-weight:600}
  .editor-lista{list-style:none;margin:0 0 12px;padding:0;display:flex;flex-direction:column;gap:8px;max-height:46vh;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--line-strong) transparent}
  .editor-lista::-webkit-scrollbar{width:6px}
  .editor-lista::-webkit-scrollbar-thumb{background:var(--line-strong);border-radius:3px}
  /* `cursor:grab` é a única marca do arrastar em repouso (item 16). Nada de alça nova na
     linha: o repouso do editor é a imagem que o PO está prestes a aprovar na PR 2, e um
     elemento a mais ali mudaria o que ele viu. O gesto se anuncia pelo cursor e se explica
     no momento em que acontece, pelas duas pistas abaixo. */
  .link-edit{display:flex;align-items:center;gap:10px;position:relative;cursor:grab}
  /* A linha que saiu, esmaecida: sem isso não se sabe **o que** está sendo arrastado quando
     o cursor já está longe dela. */
  .link-edit.arrastando{opacity:.4;cursor:grabbing}
  /* E **onde vai cair**: um traço na cor do modal, no vão entre as linhas. Pseudo-elemento
     posicionado, e não borda nem `box-shadow`: borda empurraria a lista 2 px a cada
     passagem do cursor, e a linha inteira piscaria de lugar. */
  .link-edit.alvo-antes::before,
  .link-edit.alvo-depois::after{content:"";position:absolute;left:0;right:0;height:2px;border-radius:2px;background:var(--c)}
  .link-edit.alvo-antes::before{top:-5px}
  .link-edit.alvo-depois::after{bottom:-5px}
  /* Mesmo par do selo do card (adendo 4 §B): o `selo()` é o mesmo nos dois lugares, e uma
     regra que valesse só num deles seria a cor repetida envelhecendo separada. Nenhum
     instrumento veria esta: o editor vive dentro do modal, e modal o `axe.mjs` não audita. */
  .link-edit .ini{width:30px;height:30px;flex:none;border-radius:9px;display:grid;place-items:center;font-family:"Sora",sans-serif;font-weight:600;font-size:11px;color:var(--ini-fg,var(--on-azul));background:var(--ini-bg,var(--azul))}
  .link-edit-txt{flex:1;min-width:0;display:flex;flex-direction:column;line-height:1.25}
  .link-edit-txt strong{font-weight:600;font-size:13.5px}
  .link-edit-txt span{font-family:"IBM Plex Mono",monospace;font-size:11px;color:var(--faint);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .link-edit-acoes{display:flex;gap:4px;flex:none}
  /* Os botões ficam sempre visíveis (não só no hover): num tablet não existe hover — e ali
     o arrastar do HTML também não funciona, então as setas são o **único** caminho para
     reordenar. Vale o mesmo para quem navega por teclado. */
  .link-edit-acoes button{width:28px;height:28px;border:1px solid var(--line);border-radius:8px;background:var(--glass);color:var(--ink);font-size:13px;line-height:1;cursor:pointer;transition:border-color .2s,background .2s}
  .link-edit-acoes button:hover:not(:disabled){border-color:var(--line-strong);background:var(--glass-strong)}
  .link-edit-acoes button:disabled{opacity:.35;cursor:default}
  /* O ⟳ fica um pouco menor que as setas: é ação secundária, e a linha já tem quatro botões. */
  .link-edit-acoes button:nth-of-type(3){font-size:12px}
  .link-edit-acoes button:focus-visible{outline:2px solid var(--azul);outline-offset:2px}
  .editor-add{display:flex;gap:8px;flex-wrap:wrap}
  .editor-add input{flex:1;min-width:140px;background:none;border:0;border-bottom:1px solid var(--line-strong);padding:6px 0;color:var(--ink);font:inherit;font-size:13.5px;outline:0}
  .editor-add input::placeholder{color:var(--faint)}
  .editor-add input:focus-visible{border-bottom-color:var(--azul)}
  .editor-nota{margin:8px 0 0;font-size:12px;color:var(--crit-txt)}
  .editor-links[hidden]{display:none}

  /* ---------- ORDEM-039 §4 · a paleta de comandos ----------
     A paleta é um MODAL (ver o `hub.js`), e por isso herda o véu, o raio, o vidro e o
     `focus-visible` de todo o resto. O que muda aqui é só a forma: mais estreita que os
     modais de dado — ela é uma lista de escolhas, e uma linha de 880 px deixa o rótulo de um
     lado e a nota do outro, com um deserto no meio — e sem as caixas `.box`.

     A opção corrente é marcada por `aria-selected`, e não por `:hover` nem por uma classe: é
     o MESMO atributo que o leitor de tela anuncia, então a marca que se vê e a que se ouve
     não podem divergir. Passar o mouse por cima não muda a opção corrente (o `hub.js` nem
     escuta `mouseover`), porque isso roubaria o lugar de quem está navegando pelas setas.

     `color-mix` com a cor do assunto, e não uma cor nova: a paleta é `--laranja`, e o fundo
     da opção corrente é 16% dela sobre o que houver atrás. */
  .modal-paleta{width:min(620px,100%)}
  .paleta{display:flex;flex-direction:column;gap:12px}
  .paleta-campo{width:100%;background:none;border:0;border-bottom:1px solid var(--line-strong);padding:8px 0;color:var(--ink);font:inherit;font-size:16px;outline:0}
  .paleta-campo::placeholder{color:var(--faint)}
  .paleta-campo:focus-visible{border-bottom-color:var(--c)}
  .paleta-lista{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px;max-height:min(52vh,420px);overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--line-strong) transparent}
  .paleta-lista::-webkit-scrollbar{width:6px}
  .paleta-lista::-webkit-scrollbar-thumb{background:var(--line-strong);border-radius:3px}
  .paleta-opcao{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 10px;border-radius:10px;cursor:pointer;font-size:14px}
  .paleta-opcao[aria-selected="true"]{background:color-mix(in srgb,var(--c) 16%,transparent)}
  .paleta-opcao[aria-disabled="true"]{cursor:default;color:var(--faint)}
  .paleta-rotulo{display:flex;align-items:center;gap:8px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .paleta-nota{flex:none;font-family:"IBM Plex Mono",monospace;font-size:11.5px;color:var(--faint)}
  .paleta-vazio{justify-content:flex-start;font-family:"IBM Plex Mono",monospace;font-size:12.5px}


  /* Carrossel: uma manchete legível, com controles sempre disponíveis. */
  .w-noticias .nt-destaque{flex:1;justify-content:center;min-height:0}
  .w-noticias .nt-titulo{font-family:"Sora",sans-serif;font-size:clamp(14px,1.6vh,18px);line-height:1.45;-webkit-line-clamp:5;min-height:0}
  .w-noticias .nt-item{gap:10px}
  .nt-controles{display:flex;align-items:center;gap:5px;flex:none}
  .nt-controles[hidden],.nt-controles button[hidden]{display:none}
  .nt-posicao{margin-right:auto;font-family:"IBM Plex Mono",monospace;font-size:11px;color:var(--muted)}
  .nt-controles button{min-width:28px;min-height:28px;padding:3px 7px;border:1px solid var(--line);border-radius:8px;background:var(--glass);color:var(--ink);font:inherit;font-size:11px;cursor:pointer}
  .nt-controles button:hover{background:var(--glass-strong);border-color:var(--line-strong)}
  .nt-controles button:focus-visible{outline:2px solid var(--azul);outline-offset:2px}
  @media (min-width:1500px) and (min-height:860px) and (max-height:999.98px){
    .w-noticias .nt-titulo{-webkit-line-clamp:4;font-size:14px;line-height:1.35}
    .w-noticias .nt-item{gap:5px}
  }

  .nt-lista-modal .nt-titulo{display:block;min-height:0;-webkit-line-clamp:unset}

  /* ---------- ORDEM-043 · a leitura ao apontar, um desenho só para todos os gráficos ------
     O balão é um `<output>` no `<body>` (região viva `polite`), posicionado pelo CSSOM em
     coordenadas de janela — nunca por `style=`, que a CSP `style-src 'self'` bloquearia em
     silêncio. Vazio ele some por `:empty`, e é assim que ele fica quando não há leitura:
     `display:none` teria de voltar no mesmo quadro em que o texto muda, e região viva que
     aparece junto com o próprio texto não anuncia de forma confiável.

     `touch-action:pan-y` no gráfico é o que divide o gesto no tablet: arrastar de lado lê a
     série, arrastar para cima continua rolando a página. Sem ele o navegador engoliria o
     arrasto horizontal como rolagem e a leitura nunca sairia do primeiro ponto. */
  .leitor{touch-action:pan-y}
  .leitura{position:fixed;left:0;top:0;z-index:30;pointer-events:none;padding:4px 8px;border:1px solid var(--line-strong);border-radius:8px;background:var(--glass-strong);backdrop-filter:blur(10px);color:var(--ink);font-family:"IBM Plex Mono",monospace;font-size:12px;font-variant-numeric:tabular-nums;white-space:nowrap;box-shadow:0 8px 22px rgba(0,0,0,.28)}
  .leitura:empty{opacity:0}
  /* O ponto apontado, nos três desenhos. `outline` e não `border`: borda mudaria a caixa e
     empurraria as barras vizinhas — o `geometria.mjs` reprovaria um corte que a leitura teria
     inventado. */
  .bars i.lendo{opacity:1;outline:2px solid var(--ink);outline-offset:1px}
  .flags i.lendo{outline:2px solid var(--ink);outline-offset:2px}
  .marca-guia{stroke:var(--line-strong);stroke-width:1;opacity:0}
  .marca-leitura{fill:var(--ink);opacity:0}
  .com-leitura .marca-guia,.com-leitura .marca-leitura{opacity:1}
  /* O gráfico que recebe foco é o `.box` do modal (no card não há `.box`, e o motivo é
     `nested-interactive`: ver `ligarLeitura` no hub.js). Foco sem contorno visível seria
     teclado sem pista de onde se está. */
  .modal .box[tabindex]:focus-visible{outline:2px solid var(--c-txt);outline-offset:2px}
