/* ============================================================================
   BebéVida People — design system
   Espelho dos tokens do site novo (bebevida_new_website:
   apps/web/src/app/(public)/globals.css) adaptado a app interna autenticada.
   Tipografia self-hosted (wwwroot/fonts): Fraunces (display) + Instrument Sans
   (corpo) + JetBrains Mono (etiquetas/datas/códigos).
   ========================================================================== */

/* ---------- Fonts (variáveis, latin + latin-ext) ---------- */

@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/fraunces-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/fraunces-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/instrument-sans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/instrument-sans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url('../fonts/jetbrains-mono-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url('../fonts/jetbrains-mono-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------- Tokens (herdados do site) ---------- */

:root {
  --ocean: #015e82;
  --ocean-dark: #013f58;
  --ocean-darker: #0a1821;
  --cyan: #16becf;
  --cyan-soft: #5cc3ce;
  --cyan-deep: #0e7480;
  --cream: #faf8f1;
  --sand: #f7f5e7;
  --paper: #ffffff;
  --ink: #0e152f;
  --muted: #5b6270;
  --line: #e6e3d9;
  --gold: #caa85a;
  --gold-deep: #8a6d2a;
  /* Ausências (Task 9). Fora da família das FÉRIAS (--ocean) e da do aniversário/feriado
     (--gold): uma ausência não é um direito gozado nem uma data do calendário — é
     "indisponível por outra razão". Roxo dessaturado, para não competir com o âmbar do
     limite de cobertura (--status-warning), que é o único alarme desta app.
     Contrastes calculados (WCAG 2.x): branco sobre --plum 5,91:1 — é o par que a
     `.cal-ausencia` usa —, e --plum-deep sobre branco 9,67:1. Os dois passam o AA de texto
     (4,5:1) com folga e o de componentes (3:1) largamente.
     ⚠️ --plum e --ocean estão PERTO em luminância (1,22:1 entre eles): é a FORMA — as riscas
     claras a 135° — que os separa, e não a cor. Vale nas DUAS vistas que os põem lado a lado, a
     `.mapa-ausencia` (mapa da equipa, células de 22px) e a `.ano-ausencia` (faixa anual, ~14px,
     mesmas riscas com passo mais apertado). É a mesma regra D8 que já obriga o pendente às
     riscas e o aniversário ao círculo. */
  --plum: #6b5b95;
  --plum-deep: #4a3d6b;

  --status-success: #186c46;
  --status-warning: #6e5620;
  --status-neutral: #51586a;

  --font-sans: 'Instrument Sans', -apple-system, system-ui, sans-serif;
  --font-serif: 'Fraunces', Georgia, serif;
  --font-mono: 'JetBrains Mono', ui-monospace, monospace;

  --radius-sm: 6px;
  --radius-md: 12px;
  --radius-lg: 20px;
  --radius-pill: 999px;

  --shadow-xs: 0 1px 2px rgba(14, 21, 47, 0.06);
  --shadow-sm: 0 4px 10px -4px rgba(14, 21, 47, 0.12);
  --shadow-md: 0 12px 30px -18px rgba(1, 94, 130, 0.35);
  /* Focus ring duplo (paper interno + cyan externo) — visível sobre qualquer
     fundo, claro ou ocean-darker. WCAG 2.4.7 / 1.4.11. */
  --shadow-ring: 0 0 0 2px var(--paper), 0 0 0 5px rgba(22, 190, 207, 0.85);

  --transition-fast: 0.15s ease;
  --transition-base: 0.2s ease;

  --sidebar-w: 248px;
  --sidebar-w-calha: 68px;
  --conteudo-max: 1080px;
}

/* ---------- Base ---------- */

* { box-sizing: border-box; }

html { overflow-x: clip; }

body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
  font-family: var(--font-serif);
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.12;
  margin: 0;
  text-wrap: balance;
}

p { text-wrap: pretty; }

img { max-width: 100%; display: block; }

a { color: var(--ocean); text-decoration: none; }
a:hover { text-decoration: underline; }

:focus-visible {
  outline: none;
  box-shadow: var(--shadow-ring);
  border-radius: 4px;
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---------- Shell: sidebar + conteúdo ---------- */

.shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.sidebar {
  background: var(--ocean-darker);
  color: #e8eaf0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 24px;
  padding: 20px;
}

.sidebar-brand { display: inline-block; line-height: 0; }
.sidebar-brand img { height: 30px; width: auto; }

/* ⚠️ Estes espaçamentos foram APERTADOS na ronda pós-agosto (18→12, 6→4, 9→7, 44/14→40/10,
   e o gap da grelha desktop 16→12) por uma medição, não por gosto: num portátil de 1432×734 o
   menu completo do RhAdmin (3 grupos, 11 entradas) pedia 600px numa faixa de 537 — 63px de scroll
   para ver o «Parâmetros». Quem guarda o total é o
   NavegacaoCalhaTests.O_menu_completo_cabe_sem_rolar_num_ecra_de_734_de_altura; quem alargar um
   destes valores tem de voltar a caber lá.

   ⚠️⚠️ SEGUNDO APERTO — Task 13 do módulo de DESPESAS (2026-08-18), pelo MESMO método e com o mesmo
   teste a mandar. O módulo acrescenta duas entradas ao menu («As minhas despesas», de todos, e
   «Conferência de despesas», só de quem passa na ConferirDespesas), e o RhAdmin passou de 11 para
   13. Medido em Chromium a 1432×734, ANTES do aperto:

       #nav-principal  scrollHeight = 603   clientHeight = 545   →  transbordava 58px
       .nav-link (caixa) = 35,69px  ·  gap das listas = 2px  ·  custo por entrada ≈ 37,7px
       grupos = 206 / 168 / 193 px  ·  margens entre grupos ≈ 36px

   Reconstituído: com 11 entradas o scrollHeight era ≈ 528px — o desenho já só tinha ≈ 17px de folga.
   Ou seja, não foi o módulo que gastou o orçamento; foi o orçamento que já estava no fim.

   O aperto são DOIS valores, escolhidos como o mínimo que fecha os 58px com folga real — e vivem
   nas regras `.sidebar-desktop …` mais abaixo, NÃO nas regras base (ver o aviso a seguir):
     · `.nav-link` padding vertical 7px → 5px   →  2px × 2 lados × 13 entradas ≈ 52px
     · `.nav-grupo` margin-bottom   12px → 8px  →  4px × 3 grupos            ≈ 12px

   Medido DEPOIS, em Chromium, a 1432×734:
       altura do `.nav-link`  35,69px → 31,69px
       fundo do último filho = 530,94px numa faixa visível de 545px  →  14,06px

   ⚠️ Desses 14,06px, 8px são a `margin-bottom` do ÚLTIMO grupo — que fica DENTRO da caixa mas não é
   conteúdo a mostrar. A folga aproveitável são portanto ≈6px, e é esse o número a ter em conta:
   não cabe nem meio píxel de padding a mais em cada lado das 13 entradas.

   ⚠️⚠️ E a folga mede-se assim — pelo fundo do último filho contra o fundo da caixa visível — e NÃO
   pelo `scrollHeight`: essa propriedade devolve o MAIOR entre o conteúdo e o `clientHeight`, por
   isso satura em 545 assim que o conteúdo cabe e passa a dizer «folga zero» seja qual for a folga.
   Custou um terceiro aperto desnecessário (o `margin` do `.nav-grupo-titulo`, revertido) antes de
   se dar por isso. O `scrollHeight` serve para «rola ou não rola», que é a pergunta do teste; não
   serve para «quanto sobra».

   ⚠️ O que NÃO se pode perder de vista ao mexer nisto outra vez: o alvo de clique do `.nav-link` na
   sidebar desce de 35,69px para 31,69px. Continua acima do mínimo AA de 24px (WCAG 2.2, 2.5.8), que
   é o chão a respeitar — abaixo disso o aperto deixa de ser espaçamento e passa a ser
   acessibilidade.

   ⚠️⚠️⚠️ E O APERTO É SÓ DA SIDEBAR — review r1, Importante 2. O `_NavPartial` é renderizado DUAS
   vezes por página: na `.sidebar-desktop` e na topbar de telemóvel (o `<details>`). Apertado na
   regra BASE, o aperto vazava para o telemóvel — que não tem problema nenhum de altura (o menu abre
   por cima do conteúdo e rola à vontade) e onde o alvo de 31,69px é uma perda pura: num ecrã tátil o
   dedo tem menos precisão do que o rato, e é aí que os 44px recomendados fazem falta. Um problema de
   um portátil de 734px não se paga com o polegar de quem anda no autocarro. As regras base ficam nos
   7px/12px de sempre e as duas mais abaixo, prefixadas por `.sidebar-desktop`, é que apertam. */
.nav-grupo { margin: 0 0 12px; }

/* O aperto do segundo aperto (ver acima), preso ao sítio que tem o problema. */
.sidebar-desktop .nav-grupo { margin-bottom: 8px; }

.nav-grupo-titulo {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 1px;
  text-transform: uppercase;
  /* O #6b7686 que aqui esteve dava 3,91:1 sobre a sidebar (--ocean-darker, #0a1821) — falha o AA
     (4,5:1) a 10px, e falhava nos TRÊS títulos. Um título de grupo é a etiqueta que diz de quem é
     o bloco: ou é legível para todos, ou não é para ninguém. #c5cad4 = 10,96:1, o mesmo dos links.
     Medido em píxeis, em Chromium, título a título: 10,96 / 10,91 / 10,96 com esta cor, contra
     3,91 / 3,76 / 3,91 com a antiga (o 3,76 do «Equipa» é o antialiasing de um título curto, não
     outra cor). Guarda: MapaEquipaTests.Os_titulos_dos_tres_grupos_leem_se_com_o_contraste_minimo. */
  color: #c5cad4;
  /* ⚠️ Ficou nos 4px, e isso é uma decisão MEDIDA, não uma coisa por fazer: no segundo aperto do
     menu (Task 13, 2026-08-18) cheguei a baixá-lo para 2px, por ler no `scrollHeight` uma folga de
     zero. A leitura é que estava errada — o `scrollHeight` devolve o MAIOR entre o conteúdo e o
     `clientHeight`, portanto satura assim que o conteúdo cabe e deixa de dizer quanto sobra. Medida
     a sério (fundo do último filho contra o fundo da caixa visível), a folga com os dois valores da
     `.nav-grupo`/`.nav-link` já era de ≈14px, e este terceiro aperto era espaçamento gasto sem
     necessidade. Ver a medição completa na `.nav-grupo`. */
  margin: 0 0 4px;
  padding: 0 12px;
}

.nav-links { display: flex; flex-direction: column; gap: 2px; }

/* ── Links com ícone ── */
/* ⚠️ Só o display/alinhamento (display, align-items, gap, position) vem do delta — as cores e o
   padding já cá estavam e ficam como estavam (docs/frontend-2026-08-delta.css, secção 1).
   ⚠️⚠️ Os 7px verticais são os do TELEMÓVEL (e de qualquer sítio que não seja a barra lateral do
   desktop): um alvo de 35,69px, que num ecrã tátil é o que se quer. Quem aperta é a regra
   `.sidebar-desktop .nav-link` logo a seguir, e só ela — ver o comentário grande da `.nav-grupo`. */
.nav-link {
  display: flex;
  align-items: center;
  gap: 10px;
  position: relative;
  color: #c5cad4;
  text-decoration: none;
  padding: 7px 12px;
  border-radius: var(--radius-sm);
  font-size: 14px;
  transition: background-color var(--transition-fast), color var(--transition-fast);
}
/* O aperto do segundo aperto (Task 13, ver o comentário grande da `.nav-grupo`), preso ao ÚNICO
   sítio que tem o problema de altura. O telemóvel fica nos 7px/35,69px da regra base. */
.sidebar-desktop .nav-link { padding-top: 5px; padding-bottom: 5px; }
.nav-link:hover { background: rgba(255, 255, 255, 0.06); color: #fff; text-decoration: none; }
.nav-link.ativo { background: var(--ocean); color: #fff; }
.nav-link.ativo:hover { background: var(--ocean-dark); }

.nav-icone {
  flex: 0 0 18px;
  width: 18px;
  height: 18px;
  opacity: 0.85;
}
.nav-link.ativo .nav-icone { opacity: 1; }
.nav-rotulo {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* O contador de «Aprovações»/«Validações» no menu. Só é emitido quando > 0 — com zero não há
   `nav-badge` nenhum, é um irmão do texto dentro do `<a>`, nunca um atributo condicional, e há
   testes que o afirmam via `MenuHtml.BadgeDe` (não byte a byte — o ícone entra antes do texto).
   O par cyan sobre ocean-darker é o mesmo contraste dos destaques da sidebar. */
.nav-badge {
  display: inline-block;
  min-width: 1.5em;
  padding: 0.1em 0.45em;
  border-radius: var(--radius-pill);
  /* Invisível no tema normal; em forced-colors (alto contraste do Windows) o fundo é forçado a
     Canvas e o badge ficava um número solto ao lado do texto, sem forma nenhuma — a borda é
     forçada com ele e devolve-lhe o contorno. É o que a família `.badge` deste ficheiro já faz. */
  border: 1px solid transparent;
  background: var(--cyan);
  color: var(--ocean-darker);
  font-family: var(--font-mono);
  /* Em px como o resto do bloco do menu: era a única regra daqui em rem, e a 32px de fonte do
     browser o badge crescia 1,65× sozinho, dentro de um link que não crescia. */
  font-size: 11px;
  font-weight: 700;
  line-height: 1.4;
  text-align: center;
  vertical-align: 0.1em;
}

/* ---------- Sidebar colapsável: calha de 68px só com ícones (Tarefa 3) ---------- */

/* ⚠️ (ronda 1, Crítico 2) O estado vive no <html>, não no `.shell`. O `.shell` nasce SEM
   `data-nav` nenhum no markup — só o script inline do <head> escreve `html[data-nav]`, ANTES da
   primeira pintura, e o nav.js mantém a MESMA fonte depois. A primeira versão só cobria a
   largura (`--sidebar-w`) e deixava as restantes ~10 regras (marca, rótulos, padding, badge,
   título de grupo) presas a `.shell[data-nav="calha"]`, que só o nav.js escrevia, no FIM do
   <body> — um arranque lento (pedido extra, cache fria, IIS frio) pintava a calha a 68px com o
   CONTEÚDO TODO EXPANDIDO lá dentro (marca deitada, rótulos, nome do utilizador), esmagado pelo
   `overflow-x: clip`. Pior do que o salto 248→68 que esta medida existe para evitar. */
html[data-nav="calha"] .shell { --sidebar-w: var(--sidebar-w-calha); }

/* ⚠️ (ronda 1, Importante 3) TODAS as regras "Estado calha" abaixo estão presas a
   `.sidebar-desktop`, e não só a `.shell[data-nav="calha"]` / `html[data-nav="calha"]`. O
   `_NavPartial` e o `_LoginPartial` são renderizados DUAS vezes — uma na `.sidebar-desktop`
   (desktop) e outra dentro de `.topbar-nav` (o <details> da topbar, mobile) — e as duas cópias
   partilham as mesmas classes (`.nav-link`, `.nav-grupo-titulo`, `.nav-badge`, `.user-nome`…).
   Sem este âmbito extra, uma preferência `calha` guardada no browser esmagava também o menu da
   topbar num ecrã estreito — nome e email do utilizador desapareciam, e os títulos de grupo
   viravam traços de 1px. Como a `.sidebar-desktop` já é `display: none` abaixo
   dos 900px (regra antiga, mais abaixo neste ficheiro), este âmbito também torna DESNECESSÁRIA
   qualquer lista de `revert` na media query estreita: as regras da calha deixam de poder tocar
   em nada fora da barra do desktop, em vez de "tocar em tudo e depois desfazer duas coisas". */
.sidebar-topo {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.nav-interruptor {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: var(--radius-sm);
  color: #c5cad4;
  cursor: pointer;
  transition: background-color var(--transition-fast), color var(--transition-fast);
}
.nav-interruptor:hover { background: rgba(255, 255, 255, 0.08); color: #fff; }
.nav-interruptor:focus-visible { box-shadow: var(--shadow-ring); outline: none; }
.nav-interruptor svg { width: 16px; height: 16px; }
/* A seta aponta para onde a barra VAI, não para onde está. Só existe um interruptor na página
   (vive na `.sidebar-desktop`), por isso não precisa do âmbito extra. */
html[data-nav="calha"] .nav-interruptor svg { transform: scaleX(-1); }

/* Sem JavaScript o interruptor não aparece — a barra fica expandida e inteira.
   O script tira o `hidden` no arranque. */
.nav-interruptor[hidden] { display: none; }

/* ── Estado calha (âmbito: só a `.sidebar-desktop` — ver a nota grande acima) ── */
html[data-nav="calha"] .sidebar-desktop { padding: 24px 10px; }

/* ⚠️ O logótipo é uma marca DEITADA (~150px de largura). Em 48px de espaço útil
   ficava esmagado por cima do interruptor — apanhado na renderização. Na calha
   entra a marca curta (o mesmo símbolo do favicon) e o interruptor desce para
   debaixo dela. */
.marca-curta { display: none; }
html[data-nav="calha"] .sidebar-desktop .sidebar-topo { flex-direction: column; gap: 12px; }
html[data-nav="calha"] .sidebar-desktop .marca-larga { display: none; }
html[data-nav="calha"] .sidebar-desktop .marca-curta { display: block; height: 26px; width: auto; }
html[data-nav="calha"] .sidebar-desktop .user-nome,
html[data-nav="calha"] .sidebar-desktop .user-email { display: none; }

/* ⚠️⚠️ (ronda 1, Crítico 1) NÃO é `display: none`. O `<span class="nav-rotulo">` é o ÚNICO
   texto dentro do `<a>` — o `<svg>` é `aria-hidden`, e não há `aria-label`/`title` em lado
   nenhum. Conteúdo em `display: none` fica FORA do cálculo do nome acessível: um `display: none`
   aqui deixava os quinze links da calha anónimos para um leitor de ecrã (e o link das
   «Aprovações», com o `.nav-badge` continuando visível, ficava com o número sozinho por nome). A
   técnica `.sr-only` (copiada do `site.css`, que já a usa noutro sítio) mantém o texto na árvore
   de acessibilidade, só o recorta visualmente — uma só fonte de verdade (o rótulo que já lá
   está), em vez de duplicar o nome num `aria-label` paralelo que diverge com o tempo. A `.nav-dica`
   NÃO substitui isto: é `role="presentation"`, não tem `aria-describedby` nenhum a ligá-la ao
   link, e só aparece ao hover/foco — é um canal visual, não o nome acessível permanente do link. */
html[data-nav="calha"] .sidebar-desktop .nav-rotulo {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

html[data-nav="calha"] .sidebar-desktop .nav-link {
  justify-content: center;
  padding: 10px 0;
  gap: 0;
}

/* O título do grupo passa a ser um traço: o bloco continua a ler-se como bloco
   sem ocupar duas linhas de texto ilegível a 10px. */
html[data-nav="calha"] .sidebar-desktop .nav-grupo-titulo {
  font-size: 0;
  padding: 0;
  margin: 0 8px 8px;
  height: 1px;
  background: rgba(255, 255, 255, 0.14);
}

/* O badge das Aprovações/Validações não cabe ao lado do ícone: passa a ponto
   no canto, e o número continua a ser lido por quem usa leitor de ecrã. */
html[data-nav="calha"] .sidebar-desktop .nav-badge {
  position: absolute;
  top: 4px;
  right: 10px;
  min-width: 15px;
  padding: 0 3px;
  font-size: 9px;
  line-height: 15px;
}

/* ⚠️⚠️ O tooltip da calha é `position: fixed` E VIVE NO <body>, não dentro do
   link. A primeira versão era um `::after` com `left: calc(100% + 8px)` — e a
   `.sidebar` era, na altura, um contentor de scroll (`overflow-y: auto`, para
   menus longos em ecrã baixo; desde a A5 quem rola é o `#nav-principal`, mas o
   raciocínio vale igual — o link continua dentro de um contentor que rola).
   Um filho que sai pela direita de um contentor de scroll não fica
   por cima do conteúdo: FAZ O CONTENTOR GANHAR SCROLL HORIZONTAL. Era a barra de
   deslocamento que aparecia no fundo da calha, e o tooltip vinha cortado.
   O `overflow-x: clip` mata a barra; o tooltip sai do contentor para o body e
   é o JavaScript que o coloca à altura do ícone.
   ⚠️ (ronda 1, Crítico 1-bis) Este `overflow-x: clip` era o que o teste
   `A_calha_nao_ganha_barra_de_deslocamento_horizontal` media — a dica é filha do <body>, nunca da
   `.sidebar-desktop`, e nem hover nem foco correm naquele teste, por isso o `position: fixed` da
   `.nav-dica` não era o que ali se afirmava. **Já não é verdade desde a A5**: a barra deixou de ser
   contentor de scroll e a asserção que carrega a prova mede o `#nav-principal`. O `clip` fica na
   mesma, e por uma razão que continua de pé — é ele que impede um filho a sair pela direita de
   voltar a abrir a barra de deslocamento se um dia a `.sidebar-desktop` recuperar overflow.
   Quem guarda que a dica é mesmo `position: fixed` e vive fora da barra é o
   `A_dica_da_calha_aparece_ao_foco_do_teclado_e_fora_da_barra` (medido por mutação — ver o
   task-3-report.md). */
.sidebar-desktop { overflow-x: clip; }

.nav-dica {
  position: fixed;
  z-index: 60;
  padding: 6px 10px;
  background: var(--ink);
  color: #fff;
  border-radius: var(--radius-sm);
  font-family: var(--font-sans);
  font-size: 12px;
  white-space: nowrap;
  box-shadow: var(--shadow-sm);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--transition-fast);
}
.nav-dica.visivel { opacity: 1; }

/* Em ecrã estreito o menu é o <details> da topbar — a calha não existe lá. Só resta esconder o
   interruptor (defesa a mais: já vive dentro da `.sidebar-desktop`, que é `display: none` aqui
   por regra mais abaixo neste ficheiro). Não há `revert` nenhum a fazer: o âmbito
   `.sidebar-desktop` das regras "Estado calha" acima já impede qualquer uma delas de tocar na
   topbar, com preferência guardada ou sem ela (ver a nota grande do Importante 3). */
@media (max-width: 899.98px) {
  .nav-interruptor { display: none; }
}

.user-box {
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  padding-top: 14px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.user-nome { font-weight: 600; font-size: 14px; color: #fff; }
.user-email { font-size: 12px; color: #c5cad4; word-break: break-all; }
.user-sair {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 6px;
  padding: 7px 12px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: var(--radius-sm);
  color: #fff;
  font-size: 13px;
  text-align: center;
  transition: background-color var(--transition-fast);
}
.user-sair svg { width: 16px; height: 16px; flex: 0 0 auto; }
.user-sair:hover { background: rgba(255, 255, 255, 0.08); text-decoration: none; }

/* Topbar mobile — <details> sem JS: o summary é a barra (logo + «Menu»);
   aberto, mostra a navegação escura por baixo. Escondida em desktop. */
.topbar { background: var(--ocean-darker); }
.topbar > summary {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  cursor: pointer;
}
.topbar > summary::-webkit-details-marker { display: none; }
.topbar > summary img { height: 26px; width: auto; }
.topbar-toggle {
  color: #e8eaf0;
  font-size: 12px;
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: 0.8px;
  padding: 6px 10px;
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: var(--radius-sm);
}
.topbar[open] .topbar-toggle { background: rgba(255, 255, 255, 0.08); }
.topbar-nav { padding: 4px 16px 18px; }

.principal {
  flex: 1;
  min-width: 0;
  padding: 24px 20px 48px;
}

.conteudo {
  max-width: var(--conteudo-max);
  animation: entrada 0.35s ease both;
}

@keyframes entrada {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}

/* Desktop: sidebar fixa à esquerda, topbar desaparece. */
@media (min-width: 900px) {
  .shell { flex-direction: row; align-items: flex-start; }
  .sidebar {
    width: var(--sidebar-w);
    flex-shrink: 0;
    position: sticky;
    top: 0;
    height: 100vh;
    padding: 24px 20px;
  }
  .topbar, .sidebar-mobile { display: none; }
  .principal { padding: 40px 48px 64px; }

  /* A barra em três faixas (A5): topo fixo · menus a rolar · rodapé fixo. Aqui esteve um
     `overflow-y: auto` na `.sidebar` acima — era a barra INTEIRA o contentor de scroll, e num ecrã
     baixo a marca e o «Sair» saíam do ecrã com os menus. O scroll mudou de dono: passou para a
     faixa do meio, e as outras duas ficam onde estão porque a grelha lhes dá altura própria. */
  .sidebar-desktop {
    display: grid;
    /* ⚠️ O `0` do `minmax(0, 1fr)` — e não o `1fr` — é o que importa: uma faixa cujo mínimo é o
       próprio conteúdo nunca encolhe, e transborda em vez de rolar. Medido por mutação (task-5):
       trocar por `min-content` deixa a faixa sem altura limitada, o `scrollHeight` iguala o
       `clientHeight` e nada rola. Este `0` e o `min-height: 0` do `#nav-principal` lá em baixo
       dizem a MESMA coisa por dois lados (pista e item): cada um sozinho basta — medido também —
       e ficam os dois de propósito, para que mexer num não parta a barra em silêncio. */
    grid-template-rows: auto minmax(0, 1fr) auto;
    /* ⚠️ A coluna explícita não é decoração. A `.sidebar` traz `justify-content: space-between`
       (do tempo em que isto era flex, e continua a ser abaixo dos 900px): numa grelha essa palavra
       impede as pistas AUTOMÁTICAS de esticar, e a coluna encolhia para o max-content — os menus
       deixavam de ocupar a largura da barra (medido: 196,9px em vez de 208px). Declarada, a pista
       deixa de ser automática. Guarda: `A_faixa_do_meio_e_que_scrolla_e_o_topo_e_o_rodape_ficam`. */
    grid-template-columns: minmax(0, 1fr);
    /* 12px (era 16): parte do aperto medido da ronda pós-agosto — ver a nota na .nav-grupo. */
    gap: 12px;
  }
  /* ⚠️ O `overflow-x: clip` viaja com o `overflow-y` — é a mesma armadilha da nota grande da
     `.nav-dica` acima: um contentor que rola na vertical ganha barra HORIZONTAL assim que algo lá
     dentro passa da borda direita. A regra da `.sidebar-desktop` fica onde está — continua a
     recortar o que transborde do topo ou do rodapé — mas quem o
     `A_calha_nao_ganha_barra_de_deslocamento_horizontal` mede é ESTA: sem `overflow-y`, a barra
     deixou de ser contentor de scroll e o `scrollWidth` dela é 0 por construção; o excesso fica
     contido na caixa de scroll onde acontece e nunca chega lá acima.
     O `min-height: 0` diz do lado do item o que o `minmax(0, 1fr)` diz do lado da pista — ver a
     nota lá em cima: são redundantes de propósito, não por engano. */
  #nav-principal { overflow-y: auto; overflow-x: clip; min-height: 0; }
}

/* Mobile: a sidebar desktop esconde-se; o menu vem do <details> da topbar. */
@media (max-width: 899.98px) {
  .sidebar-desktop { display: none; }
  .sidebar-mobile { padding-top: 8px; }
}

/* ---------- Cabeçalho de página ---------- */

.cabecalho { margin: 0 0 24px; }

.eyebrow {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--cyan-deep);
  margin: 0 0 6px;
}

.cabecalho h1 { font-size: 30px; color: var(--ink); }

.lead {
  font-size: 15px;
  color: var(--muted);
  margin: 8px 0 0;
  max-width: 640px;
}

/* Controlos segmentados (filtros de listas), lado a lado quando há espaço. */
.filtros-lista { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start; }
.segmentos { display: inline-flex; flex-wrap: wrap; gap: 2px; margin: 0 0 16px;
             padding: 2px; border: 1px solid var(--line); border-radius: 10px;
             background: var(--sand); }
.segmento { padding: 6px 14px; border-radius: 8px; font-size: 13px; color: var(--muted);
            text-decoration: none; white-space: nowrap; }
.segmento:hover { color: var(--ocean); }
.segmento-ativo { background: var(--paper); color: var(--ocean); font-weight: 600;
                  box-shadow: var(--shadow-xs); }

/* ---------- Cards ---------- */

.card {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 22px 24px;
  box-shadow: var(--shadow-xs);
  margin: 0 0 16px;
}

.card-titulo {
  font-family: var(--font-serif);
  font-size: 19px;
  color: var(--ocean);
  margin: 0 0 14px;
}

.card-suave { background: var(--sand); border-color: var(--line); }

/* Hero do dashboard — gradiente cream→sand como na área de cliente do site. */
.hero {
  background: linear-gradient(135deg, var(--cream), var(--sand));
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 26px 28px;
  margin: 0 0 16px;
}
.hero h1 { font-size: 30px; }

/* Grelha 2 colunas (main + lateral) em ecrãs largos. */
.colunas { display: grid; grid-template-columns: 1fr; gap: 16px; align-items: start; }
@media (min-width: 960px) {
  .colunas { grid-template-columns: 2fr 1fr; }
}

.lateral-titulo {
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--ocean);
  margin: 0 0 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}

/* Aniversários (dashboard). Os dias do mês corrente que já passaram continuam à vista, esbatidos:
   "o dia 3 foi da Ana" é informação útil, e escondê-los deixava o cartão vazio na segunda metade
   do mês. */
.aniv-mes { font-family: var(--font-mono); font-size: 11px; text-transform: uppercase;
            letter-spacing: 0.8px; color: var(--muted); margin: 14px 0 4px; }
/* O primeiro `.aniv-mes` do cartão não precisa da margem de separação de cima — vem logo a seguir
   ao `.lateral-titulo`, que já tem a sua própria. NÃO é `.aniv-mes:first-of-type`: essa
   pseudo-classe é por TAG entre todos os irmãos, e o primeiro `<p>` do cartão é sempre o
   `.lateral-titulo` (nunca um `.aniv-mes`) — a regra nunca correspondia a elemento nenhum. */
.lateral-titulo + .aniv-mes { margin-top: 0; }
.aniv-passado { opacity: 0.55; }

/* Ações rápidas (dashboard) */
/* a mesma respiração dos .card — sem isto o bloco colava ao cartão seguinte (PR1-B) */
.acoes { display: grid; grid-template-columns: 1fr; gap: 10px; margin: 0 0 16px; }
@media (min-width: 640px) { .acoes { grid-template-columns: 1fr 1fr; } }

.acao {
  display: flex; gap: 12px; align-items: flex-start;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: 16px 18px;
  color: inherit;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.acao:hover {
  border-color: var(--cyan-soft);
  box-shadow: 0 2px 8px rgba(22, 190, 207, 0.12);
  text-decoration: none;
}
.acao-icone {
  display: flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; flex: 0 0 36px;
  border-radius: 10px; background: var(--sand); color: var(--ocean);
  /* Mesma razão do `.nav-badge` (linha 326): em forced-colors (alto contraste do Windows) o
     fundo é forçado a Canvas e o tile perdia a forma, ficando o ícone solto sem contorno — a
     borda é preservada e devolve o contorno. */
  border: 1px solid transparent;
}
.acao-icone svg { width: 20px; height: 20px; }
.acao-texto { min-width: 0; }
.titulo-icone, .lateral-icone {
  display: inline-block; vertical-align: -0.15em; margin-right: 8px; color: var(--ocean);
}
.titulo-icone { width: 18px; height: 18px; }
.lateral-icone { width: 16px; height: 16px; }
.acao-titulo {
  font-family: var(--font-serif);
  font-size: 17px;
  font-weight: 600;
  color: var(--ocean);
  margin: 0 0 2px;
}
.acao-desc { font-size: 13px; color: var(--muted); margin: 0; }

/* ---------- Régua de dias (assinatura) ----------
   O saldo anual como fila de segmentos — eco visual dos racks de
   criopreservação. Cada segmento = 1 dia; meio-dia = segmento cortado. */

.regua { display: flex; flex-wrap: wrap; gap: 4px; margin: 12px 0 8px; }

.seg {
  width: 15px;
  height: 24px;
  border-radius: 4px;
  border: 1px solid var(--line);
  background: var(--paper);
}
.seg-gozado { background: var(--ocean); border-color: var(--ocean); }
.seg-pendente { background: var(--sand); border-color: var(--gold-deep); }
.seg-transitado { background: var(--cyan-soft); border-color: var(--cyan-deep); }
/* Meio-dia: segmento a meia largura, seja qual for o estado (gozado/pendente/livre). */
.seg-metade { width: 7px; }
.seg-aniversario { background: var(--gold); border-color: var(--gold-deep); }

.regua-legenda {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
}
.regua-legenda .seg {
  width: 11px; height: 14px;
  display: inline-block;
  vertical-align: -2px;
  margin-right: 5px;
}

.saldo-numero {
  font-family: var(--font-serif);
  font-size: 34px;
  font-weight: 600;
  color: var(--ocean);
  line-height: 1;
}
.saldo-rotulo { font-size: 13px; color: var(--muted); }

/* ── Saldo repartido (decisão B2) ─────────────────────────────────────────────
   As cinco parcelas — transitados · direito · gozados · pendentes · disponíveis
   — são o rodapé do mapa de férias em papel, e a razão de existirem é a pergunta
   de janeiro: "quantos me sobraram do ano passado?". Só respondem a isso se se
   lerem DE UMA VEZ, lado a lado; empilhadas, são cinco frases soltas e o total
   volta a ser a única coisa que se vê.

   ⚠️ Sem breakpoint escolhido à mão, e é deliberado. A largura disponível NÃO
   cresce com a janela: aos 900px entra a sidebar (248px) e o cartão fica mais
   ESTREITO do que estava aos 899px. Um `@media` fixo teria de escolher entre
   partir aos 900 ou nunca chegar a cinco colunas — medido, não suposto. O
   `auto-fit` pergunta ao espaço que há, e por isso acerta dos dois lados dessa
   descontinuidade: cinco colunas quando cabem, menos quando não cabem, uma só
   em ecrã de telemóvel.

   ⚠️ O `min(140px, 100%)` e não `140px`: num contentor mais estreito do que a
   largura mínima da coluna, o `minmax(140px, 1fr)` transbordaria em vez de
   encolher — é a armadilha clássica do auto-fit. O `min-width: 0` na parcela é
   a outra metade da mesma rede (um item de grelha tem `min-width: auto`, que é
   min-content, e um rótulo longo esticaria a coluna para fora do cartão).

   ⚠️⚠️ AS LINHAS SÃO DAS PARCELAS, NÃO DO CONTENTOR — e isto foi um defeito real
   e medido, não uma preferência de escrita. A primeira versão desenhava-as com o
   `gap` de 1px a deixar ver um `background: var(--line)` no CONTENTOR. Funciona
   enquanto a grelha estiver cheia; com cinco parcelas em 3 ou 4 colunas — ou
   seja, em toda a banda dos 900 aos ~1099px — as pistas VAZIAS da última linha
   passavam a mostrar esse fundo: uma laje cinzenta ao lado da última parcela,
   medida em 168px a 900px, 425px a 960px e 473px a 1024px, quase metade do
   cartão. Acima de 1100px nunca se viu, porque aí o `auto-fit` colapsa as pistas
   inteiramente vazias e não sobra nenhuma — que é precisamente o que fazia o
   defeito ser invisível a quem só olhasse para o ecrã grande.
   Agora cada parcela traz a SUA linha (um `box-shadow` de 1px, que preenche o
   `gap` sem entrar no layout) e o contentor não tem fundo nenhum para mostrar:
   uma pista vazia fica exatamente com a cor que teria se não existisse.
   ⚠️ Um `@media` a remendar a banda seria a correção errada — o problema não é a
   largura, é a pista vazia, que aparece em qualquer largura onde o número de
   colunas não divida cinco. */
.saldo-repartido {
  display: grid;
  /* ⚠️ O piso é 120px e não 140: a 360px de viewport o conteúdo do cartão mede ~272px, e com 140
     o auto-fit só conseguia UMA coluna — as cinco parcelas empilhavam-se a toda a largura e o
     «Disponíveis» (a resposta que quase toda a gente vem buscar) caía um ecrã inteiro abaixo.
     Com 120, cabem duas (2×120+1 ≤ 272) — medido em browser (MobileUiTests). Em desktop nada
     muda: o auto-fit continua a dar as cinco lado a lado quando cabem. */
  grid-template-columns: repeat(auto-fit, minmax(min(120px, 100%), 1fr));
  gap: 1px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.saldo-parcela {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 12px 14px;
  background: var(--paper);
  box-shadow: 0 0 0 1px var(--line);
  min-width: 0;
}
/* O número de uma parcela normal: a mesma família serifada do `.saldo-numero`,
   em ponto menor. É a hierarquia que diz "isto é uma parcela, aquilo é o
   resultado" sem precisar de outra cor. */
.saldo-valor {
  font-family: var(--font-serif);
  font-size: 22px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.15;
}
/* O disponível fica em `--sand` — o mesmo fundo do `.card-suave`, já na paleta.
   ⚠️ Contraste MEDIDO em browser, e não estimado: o `PaginaFeriasTests` imprime-o
   a cada corrida, pelo computado E pelos píxeis do screenshot. `--ocean` sobre
   `--sand` = 6,55:1 (mínimo 3,0 — o número tem 34px, é texto grande) e `--muted`
   sobre `--sand` = 5,60:1 (mínimo 4,5). Mudar qualquer um destes dois tokens
   volta a ser medido no teste seguinte, não confiado a esta linha. */
.saldo-parcela-destaque { background: var(--sand); }

/* ---------- Tabelas ---------- */

.tabela-scroll { overflow-x: auto; }

.tabela {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
.tabela th {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--muted);
  text-align: left;
  padding: 8px 12px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.tabela td {
  padding: 10px 12px;
  border-bottom: 1px solid #f0eee5;
  vertical-align: middle;
}
.tabela tbody tr:last-child td { border-bottom: none; }
.tabela tbody tr { transition: background-color var(--transition-fast); }
.tabela tbody tr:hover { background: var(--cream); }

.mono { font-family: var(--font-mono); font-size: 13px; }

/* ── Cabeçalhos que ordenam: qual é a coluna ativa, e para que lado ──
   Os `<th>` da lista de funcionários são links que recarregam a página com `?ordem=&dir=`. O
   `aria-sort` já diz a um leitor de ecrã por onde a tabela está ordenada; isto é a metade que
   FALTAVA — sem ela, clicar num cabeçalho devolvia uma página visualmente idêntica e ninguém
   percebia se tinha acontecido alguma coisa.
   ⚠️ O triângulo é `content: ""` com bordas, e não uma seta em texto (`content: "↑"`): conteúdo
   textual num pseudo-elemento é anunciado por alguns leitores de ecrã, e ficaria a repetir o que o
   `aria-sort` já diz. Vazio, nunca é lido.
   ⚠️ Só a coluna ATIVA cresce (uns 13px), o que importa numa tabela que já está no limite de
   largura — ver `TabelaFuncionariosTests`. */
.tabela th[aria-sort]:not([aria-sort="none"]) a { color: var(--ink); font-weight: 700; }
.tabela th[aria-sort]:not([aria-sort="none"]) a::after {
  content: "";
  display: inline-block;
  margin-left: 5px;
  border: 4px solid transparent;
}
.tabela th[aria-sort="ascending"] a::after { border-bottom-color: currentColor; margin-bottom: 4px; }
.tabela th[aria-sort="descending"] a::after { border-top-color: currentColor; margin-top: 4px; }

/* ── Coluna «Estado» da lista de funcionários: um ícone, não um badge ──
   O badge ocupava a largura de «Inativo» em todas as linhas; com oito colunas de dados na
   mesma tabela, essa largura passou a ser cara. O ícone diz o mesmo em 16px.
   ⚠️ O CANAL É A FORMA (✓ contra ✗), a cor é REFORÇO — a mesma regra D8 que já obriga o
   pendente às riscas e o aniversário ao círculo. O <svg> é `aria-hidden` e o estado vai num
   `.sr-only` ao lado: sem esse texto a coluna fica anónima num leitor de ecrã.
   ⚠️ Não há `--status-danger` nesta paleta e NÃO se inventou um: o único alarme da app é o
   `--status-warning` (limite de cobertura), e «inativo» não é um alarme — é um facto. Leva o
   `--status-neutral`, exatamente o tom do `.badge-recusado` que esta coluna substitui. */
.estado-icone { width: 16px; height: 16px; display: block; }
.estado-sim { color: var(--status-success); }
.estado-nao { color: var(--status-neutral); }
/* `width: 1%` + `nowrap` = "a coluna mais estreita que couber", no algoritmo de tabela. */
.col-estado { width: 1%; white-space: nowrap; }

/* ── A lista de pedidos em ecrã estreito: cartões, não uma tabela cortada ──
   Abaixo de 640px a tabela dos pedidos não cabe, e o .tabela-scroll escondia precisamente as
   colunas que respondem à pergunta de quem abre a página no telemóvel — o ESTADO e os botões —
   atrás de um deslize horizontal sem indício nenhum (medido em MobileUiTests: Cancelar a 573px
   num viewport de 360). Em vez de deslizar, cada linha vira um cartão empilhado: tipo, datas,
   total, estado e ações, tudo à vista.
   ⚠️ 640px e não o breakpoint do shell (900): entre 640 e 899 não há sidebar e a tabela CABE —
   virar cartões aí era desperdiçar uma tabela perfeitamente legível.
   ⚠️ O cabeçalho `display: none` é seguro porque cada valor ou é autoexplicativo (badges, datas,
   botões) ou traz o seu rótulo no `data-rotulo` — desenhado pelo ::before, no mesmo tom mono dos
   `th` que substitui. */
@media (max-width: 639.98px) {
  .tabela-pedidos thead { display: none; }
  .tabela-pedidos, .tabela-pedidos tbody,
  .tabela-pedidos tr, .tabela-pedidos td { display: block; }
  .tabela-pedidos tr {
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    padding: 10px 14px;
    margin: 0 0 10px;
  }
  .tabela-pedidos tbody tr:hover { background: none; }
  .tabela-pedidos td { border: none; padding: 3px 0; }
  .tabela-pedidos td[data-rotulo]::before {
    content: attr(data-rotulo);
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.6px;
    text-transform: uppercase;
    color: var(--muted);
    margin-right: 8px;
  }
}

/* ── O histórico da lista de pedidos: um <details> por ano anterior (Task 11, PR 3a) ──
   A lista mostra este ano e o seguinte à vista; cada ano anterior fica numa gaveta com a
   contagem no rótulo. O tom é o mesmo da `.ano-lista-mes` (mono, discreto, com o triângulo
   escrito à mão em vez do marcador nativo, que é diferente em cada browser): é o mesmo gesto
   — «abre isto se quiseres» — e duas gramáticas na mesma página liam-se como dois controlos
   diferentes. */
.pedidos-ano > summary {
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--muted);
  padding: 10px 0;
  border-top: 1px solid var(--line);
  list-style: none;
}
.pedidos-ano > summary::-webkit-details-marker { display: none; }
.pedidos-ano > summary::before { content: "\25B8\00a0"; }
.pedidos-ano[open] > summary::before { content: "\25BE\00a0"; }
.pedidos-ano > summary:hover { color: var(--ink); }
.pedidos-ano > summary:focus-visible { outline: none; box-shadow: var(--shadow-ring); }
/* Ar por baixo da tabela aberta, para a gaveta seguinte não colar à última linha desta. */
.pedidos-ano[open] > .tabela-scroll { margin: 0 0 14px; }

/* ---------- Badges de estado ---------- */

.badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  border: 1px solid;
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
}
.badge-aprovado { background: rgba(24, 108, 70, 0.1); color: var(--status-success); border-color: rgba(24, 108, 70, 0.35); }
.badge-pendente { background: var(--sand); color: var(--status-warning); border-color: rgba(110, 86, 32, 0.35); }
.badge-recusado { background: rgba(81, 88, 106, 0.08); color: var(--status-neutral); border-color: rgba(81, 88, 106, 0.3); }
.badge-ferias { background: rgba(22, 190, 207, 0.12); color: var(--ocean-dark); border-color: var(--cyan-soft); }
.badge-aniversario { background: rgba(202, 168, 90, 0.15); color: var(--gold-deep); border-color: var(--gold); }

/* ---------- Alertas / avisos ---------- */

.alerta {
  border-radius: var(--radius-md);
  padding: 12px 16px;
  font-size: 14px;
  margin: 0 0 12px;
  border: 1px solid;
}
.alerta-aviso { background: var(--sand); color: var(--status-warning); border-color: rgba(110, 86, 32, 0.3); }
.alerta-ok { background: rgba(22, 190, 207, 0.1); color: var(--ocean-dark); border-color: var(--cyan-soft); }
.alerta-erro { background: rgba(110, 86, 32, 0.06); color: var(--status-warning); border-color: var(--status-warning); }

/* validation-summary do ASP.NET: some quando não há erros */
.validation-summary-valid { display: none; }
.alerta-erro ul { margin: 0; padding-left: 18px; }

.texto-erro { color: var(--status-warning); font-size: 13px; }
.texto-erro:empty { display: none; }

/* ---------- Estado vazio ---------- */

.vazio {
  text-align: center;
  padding: 32px 20px;
  color: var(--muted);
}
.vazio p { margin: 0 0 4px; }
.vazio .vazio-titulo {
  font-family: var(--font-serif);
  font-size: 17px;
  color: var(--ink);
}

/* ---------- Formulários ---------- */

.campo { margin: 0 0 16px; }

.campo label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  margin: 0 0 4px;
}

.campo-ajuda { font-size: 12px; color: var(--muted); margin: 3px 0 0; }

/* ⚠️ O `time` entrou com as horas da ausência (Consulta médica). É por ENUMERAÇÃO de `type` e não
   um `.campo input` genérico, de propósito: um seletor genérico apanharia também os `checkbox` e
   `radio` do resto da app e dava-lhes 380px de largura. */
.campo input[type="text"],
.campo input[type="date"],
.campo input[type="time"],
.campo input[type="number"],
.campo input[type="email"],
.campo select,
.campo textarea {
  width: 100%;
  max-width: 380px;
  font: inherit;
  font-size: 14px;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 9px 12px;
  transition: border-color var(--transition-fast);
}
.campo textarea { max-width: 560px; min-height: 84px; resize: vertical; }
.campo input:hover, .campo select:hover, .campo textarea:hover { border-color: var(--cyan-soft); }
.campo input:focus-visible, .campo select:focus-visible, .campo textarea:focus-visible {
  border-color: var(--cyan-soft);
  box-shadow: var(--shadow-ring);
}

.campo-inline { display: flex; align-items: center; gap: 8px; }
.campo-inline label { margin: 0; }

input[type="checkbox"] { accent-color: var(--ocean); width: 16px; height: 16px; }

.form-linha { display: flex; flex-wrap: wrap; gap: 16px; }
.form-linha .campo { flex: 1 1 180px; margin-bottom: 0; }

/* ⚠️⚠️ APANHADO EM BROWSER (Ausências, Task 6), e é a armadilha genérica do atributo `hidden`.
   O `[hidden] { display: none }` vive na folha do BROWSER, e QUALQUER `display` de uma folha de
   AUTOR ganha-lhe — não é questão de especificidade, é de origem da regra. Ou seja: um
   `<div class="form-linha" hidden>` fica À VISTA, porque o `display: flex` da linha acima o
   desmascara. Medido: o bloco das horas da página de ausências aparecia com «Doença» escolhida, com
   a suite C# inteira verde (ela só vê a STRING "hidden" no markup, nunca o que o browser desenha).
   A regra é geral de propósito — é a que qualquer reset tem — para o próximo `hidden` desta app não
   voltar a cair no mesmo sítio; o `!important` existe porque o que ela tem de vencer são regras de
   autor, como a de cima. Guardada por `PaginaAusenciasTests` (BrowserTests). */
[hidden] { display: none !important; }

/* ⚠️ O flex-wrap não é opcional: nas Aprovações a linha é «nota (min 200px) + Aprovar + Recusar
   (+ Pedir parecer)» e, sem wrap, a 360px o Recusar saía FORA do cartão — medido em browser
   (MobileUiTests). Uma fila que não cabe parte para a linha de baixo, não para fora da caixa. */
.form-acoes { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 20px; }

/* As observações de quem pediu, no cartão de aprovação. Citação e não campo: a barra à esquerda
   diz "isto é a voz da pessoa", sem precisar de rótulo nenhum. */
.obs-pedido {
  font-size: 14px;
  color: var(--muted);
  margin: 12px 0 0;
  padding-left: 12px;
  border-left: 3px solid var(--line);
  max-width: 640px;
}

/* A frase que explica porque é que uma linha da lista de pedidos não tem (todos) os botões.
   Discreta de propósito — é uma explicação, não um erro: um aviso a vermelho dizia que algo correu
   mal quando o que aconteceu foi só o tempo passar. O max-width impede-a de esticar a coluna das
   ações e desalinhar a tabela toda. */
.motivo-sem-accao {
  font-size: 12px;
  color: var(--muted);
  margin: 6px 0 0;
  max-width: 34ch;
  line-height: 1.4;
}

/* ---------- Botões ---------- */

.btn {
  display: inline-block;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  border-radius: 8px;
  padding: 9px 18px;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background-color var(--transition-fast), border-color var(--transition-fast);
  text-decoration: none;
}
.btn:hover { text-decoration: none; }

.btn-primario { background: var(--ocean); color: #fff; }
.btn-primario:hover { background: var(--ocean-dark); }

.btn-fantasma { background: transparent; color: var(--ink); border-color: var(--line); }
.btn-fantasma:hover { border-color: var(--cyan-soft); background: var(--paper); }

.btn-aniversario { background: transparent; color: var(--gold-deep); border-color: var(--gold); }
.btn-aniversario:hover { background: rgba(202, 168, 90, 0.12); }

.btn-pequeno { padding: 6px 12px; font-size: 13px; }

.btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* ---------- Rodapé ---------- */

.rodape {
  max-width: var(--conteudo-max);
  margin-top: 40px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  font-size: 12px;
  color: var(--muted);
  display: flex;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
.rodape a { color: var(--muted); }

/* ---------- A forma comum das legendas (A6) ---------- */

/* Uniformiza FORMA, nunca CONTEÚDO: a escala fala de turnos, o mapa de férias, a faixa anual de
   estados do ano, o plano publicado de manchas da bancada. Cada sistema mantém as suas classes de
   cor e a sua lista de entradas — o que passa a ser igual é a pastilha, o tamanho da amostra, o
   espaçamento e a tipografia.
   São SETE os sítios que a usam: `_CalendarioMes` (`.cal-legenda`), `_FaixaAnual` (`.ano-legenda`),
   `Ferias/MapaEquipa` (`.mapa-legenda`), `Escala/Index` vista «Mês» e `Escala/Index` vista «A minha»
   (as duas com `.legenda-linha` própria — PR 2, VC4), `Escala/Editar` (`.legenda-linha`) e
   `Escala/Gerir` (`.plano-legenda`).
   ⚠️ A régua do saldo (`.regua-legenda`, em `Pages/Index.cshtml`) NÃO entra: é a legenda de uma
   barra de PROPORÇÃO, não de um calendário, e continua com a sua tipografia mono em versaletes. Até
   hoje partilhava esta classe com a legenda do `_CalendarioMes`, que É de calendário — foi essa
   colisão que fez com que se contassem cinco sistemas onde havia seis, e é por isso que a do
   calendário passa a ter nome próprio (`.cal-legenda`).
   ⚠️ Este bloco vem ANTES dos sete, e é regra e não arrumação: `.legenda .amostra` e, por exemplo,
   `.mapa-legenda .mapa-aniversario` empatam em especificidade (0,2,0), e quem tem forma PRÓPRIA (o
   círculo do aniversário, as riscas da ausência) tem de ganhar à forma comum. Ordem do ficheiro é
   o que os separa. */
.legenda { display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: center;
           margin: 12px 0 0; padding: 0; list-style: none;
           font-size: 12px; color: var(--muted); }
.legenda > li, .legenda > span { display: inline-flex; align-items: center; gap: 6px; }
/* A amostra ABSTRATA de cor — um quadrado que não é célula nenhuma, só o nome de uma cor. É o que o
   calendário (`.cal-chip`), o mapa (`.mapa-amostra`) e a faixa anual (`.ano-amostra`) desenham.
   ⚠️ As legendas da escala e a do plano publicado NÃO levam esta classe, de propósito: as suas
   amostras são a CÉLULA REAL da grelha (`.escala-turno-hora`, `.editor-celula`, `.plano-cel`), com o
   texto lá dentro e a classe partilhada com a bancada. Encolhê-las a 14px fazia a legenda mentir
   sobre o que está na grelha — que é exatamente o que essas três legendas existem para não fazer. */
.legenda .amostra { width: 14px; height: 14px; border-radius: 3px; flex: 0 0 auto; }

/* ---------- Calendário de marcação ---------- */

.cal-cabecalho {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.cal-cabecalho h2 { text-transform: capitalize; }

.cal-grelha {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 4px;
}

.cal-dow {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--muted);
  text-align: center;
  padding-bottom: 4px;
}

.cal-dia {
  font: inherit;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  min-height: 56px;
  padding: 6px 8px;
  background: var(--paper);
  /* ⚠️ A cor TEM de sair daqui explicitamente, mesmo parecendo redundante com o `body`. Estes dias
     são <button> e a maioria sai `disabled` (fim de semana, feriado, dia passado, dia que já é
     meu, aniversário) — e a folha do próprio browser tem `button:disabled { color:
     rgba(16,16,16,0.3) }`, que GANHA a um valor herdado por muito específico que ele seja (uma
     regra do agente de utilizador só perde para uma declaração de autor, e herdar não é declarar).
     Sem esta linha, um dia passado renderizava o número E o marcador ::after (currentColor) a 30%
     de preto — medido em browser: #B7B7B7 sobre branco, 2,01:1. Que é precisamente o efeito que o
     bloco do dia passado, mais abaixo, diz por extenso ter recusado ao não usar `opacity`.
     Os estados que vêm a seguir (.cal-fds, .cal-feriado, .cal-sel, .cal-pendente, .cal-aprovado,
     .cal-aniversario) declaram a sua própria cor e continuam a ganhar a esta — são posteriores. */
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 8px;
  cursor: pointer;
  transition: border-color var(--transition-fast), background-color var(--transition-fast);
}
.cal-dia:hover:not(:disabled) { border-color: var(--cyan-soft); }
.cal-dia:disabled { cursor: default; }

.cal-celula { position: relative; min-width: 0; min-height: 56px; }
.cal-celula > .cal-dia { width: 100%; height: 100%; }
.cal-ausentes { position: absolute; right: 4px; bottom: 4px; z-index: 2; }
.cal-ausentes > summary {
  list-style-position: inside; cursor: pointer; padding: 1px 4px;
  border-radius: var(--radius-sm); background: var(--paper); color: var(--ocean-dark);
  font-family: var(--font-mono); font-size: 9px; line-height: 1.35;
}
.cal-ausentes[open] { z-index: 5; }
.cal-ausentes > ul {
  position: fixed; left: 50%; right: auto;
  bottom: max(8px, env(safe-area-inset-bottom));
  transform: translateX(-50%);
  width: max-content; max-width: min(520px, calc(100vw - 16px));
  max-height: calc(100dvh - max(8px, env(safe-area-inset-top)) - max(8px, env(safe-area-inset-bottom)));
  overflow-y: auto; overscroll-behavior: contain; box-sizing: border-box;
  margin: 0; padding: 7px 9px 7px 24px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--paper); color: var(--ink); box-shadow: var(--shadow-sm);
  font-family: var(--font-sans); font-size: 12px; text-align: left;
}
.cal-ausente-tratamento { display: block; font-weight: 600; }
.cal-ausente-oficial { display: block; color: var(--muted); }
/* A animation `entrada` usa transform e, com fill-mode `both`, faria qualquer tray fixed ficar
   preso à geometria de `.conteudo`, mesmo depois de a animação terminar. Retira-se só o fill
   enquanto há um tray aberto; o nome/timeline da animação não muda nem reinicia ao fechar. */
.conteudo:has(.cal-ausentes[open]) { animation-fill-mode: none; }
@media (max-width: 899.98px) {
  /* Em sete colunas, nenhuma ancoragem left/right consegue manter uma lista larga dentro do
     viewport nas colunas centrais e nas duas extremidades ao mesmo tempo. No telemóvel o tray
     ocupa a largura disponível; as safe areas cobrem também ecrãs com recorte. A altura e o scroll
     vivem na regra base porque uma lista longa também pode exceder um viewport desktop baixo. */
  .cal-ausentes > ul {
    position: fixed;
    left: max(8px, env(safe-area-inset-left));
    right: max(8px, env(safe-area-inset-right));
    bottom: max(8px, env(safe-area-inset-bottom));
    transform: none;
    width: auto;
    max-width: none;
    box-sizing: border-box;
    max-height: calc(100dvh - max(8px, env(safe-area-inset-top)) - max(8px, env(safe-area-inset-bottom)));
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}

.cal-num { font-weight: 600; font-size: 14px; }
.cal-tag { font-family: var(--font-mono); font-size: 10px; color: var(--muted); }

/* ── Calendário: três canais independentes ───────────────────────────────────
   O fundo diz "é meu"; a superfície apagada diz "o dia não está em jogo"; a
   barra inferior diz "a equipa está apertada". Foi a sobreposição destes três
   que o modelo antigo não conseguia — um dia meu E cheio só mostrava um deles.
   Nada aqui depende só da cor: o feriado tem nome, o dia sem lugar tem rótulo,
   o meio dia tem forma.
   Cores derivadas de token via color-mix() em vez de hex soltos — mantém a
   ligação ao token (muda o token, muda a cor aqui também) e evita valores
   anónimos a meio do ficheiro (ronda de correção 1, Achado 3).             */

/* ── 1. O dia serve para férias? ── */
.cal-fora     { opacity: 0.25; }                                  /* transbordo do mês */
.cal-fds      { background: var(--cream); border-color: transparent;
                color: var(--muted); font-weight: 400; opacity: 0.6; }
.cal-feriado  { background: var(--sand); border-color: var(--gold-deep); color: var(--ink); }
.cal-feriado .cal-tag { color: var(--ink); font-size: 9px; }
/* "Já aconteceu" é um canal próprio, não um estado do canal 2 — um dia de
   férias APROVADO no passado tem as duas classes ao mesmo tempo, e é
   precisamente aí que a diferença mais importa (só o futuro é editável).
   Não pinta fundo: dessatura por cima de qualquer estado, em vez de apagar.
   NÃO usar opacity aqui — opacity mistura o TEXTO com o fundo também, e num
   dia aprovado (texto branco sobre ocean) isso derrubava o contraste para
   ~2,7:1 (pior do que o problema original — ronda de correção 1 errou nisto).
   saturate() sozinho não mexe no branco (permanece branco) — só dessatura o
   fundo; contrastes medidos no design-system.md.
   O marcador de FORMA vive num ::after, não numa borda (ronda de correção 3):
   uma borda/sub-propriedade de borda pode ser apagada por qualquer regra que
   defina `border-color` a transparent (`.cal-fds`) ou que use a abreviatura
   `border` completa (`.cal-sel`) — nesse dia deixa de se ver, sem erro
   nenhum, só uma regressão silenciosa. Um `::after` é uma caixa à parte que
   NENHUMA regra deste bloco toca, por isso compõe mesmo com QUALQUER
   combinação, incluindo `.cal-fds` e `.cal-sel`. Usa currentColor para
   herdar a cor de texto de cada estado — o mesmo par que já tem contraste
   verificado (ver design-system.md), por isso o marcador nunca fica menos
   legível do que o texto ao lado dele. */
.cal-passado  { filter: saturate(0.6); font-weight: 400; position: relative; }
/* ⚠️ O `bottom` TEM de deixar o marcador acima da barra do canal 3 (`.cal-ocupado` /
   `.cal-cheio`, um `box-shadow: inset 0 -4px 0` na MESMA aresta). Estava a 3px, e a 3px o
   tracejado caía DENTRO da barra: medido em browser (suite BrowserTests, teste
   `O_marcador_do_dia_passado_continua_visivel_por_baixo_da_barra_do_dia_cheio`), num dia passado
   E cheio o marcador renderizava #4B412A sobre #655636 — contraste 1,41:1, ou seja, invisível.
   Ficava a dizer "já passou" só nos dias em que a equipa tinha folga.
   Os 6px são a conta: a barra ocupa 4px a contar da aresta interior (mais 2px de borda no
   `.cal-cheio`), por isso o marcador só está a salvo a partir dos 4px — 6px deixa margem para o
   antialiasing. Se a barra engrossar, este número sobe com ela. */
.cal-passado::after {
  content: "";
  position: absolute;
  left: 6px; right: 6px; bottom: 6px;
  border-bottom: 1.5px dashed currentColor;
  pointer-events: none;
}

/* ── 2. É meu, e em que estado? — a intensidade da tinta é o grau de certeza ── */
/* Página de EDITAR: um dia que já pertence ao pedido que se está a editar. Ao contrário de
   .cal-pendente/.cal-aprovado, este dia é CLICÁVEL (nunca sai com `disabled`) — é literalmente o
   que se veio aqui mexer. Esta regra só dá o CONTEXTO ("isto já era teu"); quem manda no aspeto é
   a seleção, que o selecao-dias.js põe por cima.
   ⚠️ VEM ANTES do .cal-sel, e isso é a regra e não arrumação. Estava DEPOIS, com a mesma
   especificidade (uma classe), por isso o seu `border-color` GANHAVA ao `border` abreviado do
   .cal-sel: um dia em edição selecionado ficava com a borda tracejada da seleção pintada com a cor
   do contexto — exatamente o contrário do que este comentário promete. A cascata resolve-o de
   graça; um `:not(.cal-sel)` resolvia também, mas escondia a razão. */
.cal-editando { border-color: color-mix(in srgb, var(--ocean) 45%, var(--paper)); }
.cal-sel      { background: color-mix(in srgb, var(--ocean) 10%, transparent);
                border: 2px dashed var(--ocean);
                color: var(--ocean); font-weight: 700; }           /* a escolher */
/* ⚠️ Os 34% são os MESMOS da `.ano-pendente` e da `.mapa-pendente`, e é isso que aqui se corrigiu
   (A6): «por decidir» estava a 16% no calendário e a 34% na faixa anual e no mapa — o mesmo conceito
   com dois tons, e quem visse as duas vistas no mesmo ecrã via duas coisas. O próprio calendário já
   se contradizia: o meio-dia (`.cal-meio.cal-pendente`, aqui em baixo) sempre desenhou 34%.
   ⚠️ Só o `background` mudou. O `border-color` e o `color` são desta regra e não das outras duas
   porque a célula do calendário é grande e LEVA TEXTO — e o texto continua a passar: --ocean-dark
   sobre 34% de --ocean em papel dá 6,42:1 (era 8,78:1 a 16%), acima do 4,5:1 exigido. */
.cal-pendente { background: color-mix(in srgb, var(--ocean) 34%, var(--paper));
                border-color: color-mix(in srgb, var(--ocean) 34%, var(--paper));
                color: var(--ocean-dark); }
.cal-aprovado { background: var(--ocean); border-color: var(--ocean); color: #fff; }
.cal-aprovado .cal-tag { color: rgba(255, 255, 255, 0.85); }
.cal-aniversario { background: var(--gold); border-color: var(--gold-deep); color: var(--ink); }
/* A ausência JÁ REGISTADA do próprio (Task 9). Sai sempre `disabled` — como o aniversário, não há
   nada para marcar nem para desmarcar aqui —, por isso não precisa (nem deve) parecer clicável.
   O tom é o --plum, deliberadamente fora da família das férias: quem olha para o mês tem de
   distinguir "gozei/vou gozar" de "faltei". */
.cal-ausencia { background: var(--plum); border-color: var(--plum-deep); color: #fff; }
.cal-ausencia .cal-tag { color: rgba(255, 255, 255, 0.85); }

/* Meio dia: a diagonal é a FORMA que diz "metade" — não depende de se ver a cor. */
.cal-meio.cal-sel      { background: linear-gradient(135deg, color-mix(in srgb, var(--ocean) 28%, transparent) 50%, transparent 50%); }
.cal-meio.cal-pendente { background: linear-gradient(135deg, color-mix(in srgb, var(--ocean) 34%, var(--paper)) 50%, var(--paper) 50%); }
.cal-meio.cal-aprovado { background: linear-gradient(135deg, var(--ocean) 50%, var(--paper) 50%);
                         color: var(--ocean-dark); }

/* ── 3. A equipa aguenta? — barra inferior, sobrepõe-se a QUALQUER estado ── */
.cal-ocupado  { box-shadow: inset 0 -4px 0 color-mix(in srgb, var(--status-warning) 45%, transparent); }
.cal-cheio    { border-color: var(--status-warning); border-width: 2px;
                box-shadow: inset 0 -4px 0 var(--status-warning); }
.cal-cheio .cal-tag { color: var(--status-warning); font-weight: 600; }
.cal-aprovado.cal-cheio .cal-tag { color: rgba(255, 255, 255, 0.95); }

/* A legenda do calendário do mês (`_CalendarioMes.cshtml`), agora com nome próprio: até à A6
   chamava-se `.regua-legenda` — a classe da régua do saldo do painel inicial —, e vestir a roupa de
   outro deu-lhe uma tipografia mono em versaletes de 11px que nenhuma outra legenda tem. Passa a
   `.legenda cal-legenda`: a forma vem toda da `.legenda` (ver a secção acima), por isso não sobra
   regra nenhuma para escrever aqui — só o nome, que é o que dá a esta legenda um sítio onde crescer
   sem voltar a pedir emprestado.
   ⚠️ A `.regua-legenda` continua a existir e a servir SÓ a régua do saldo. Não a reaproveitar. */

/* Os chips da legenda do calendário. Tamanho, cantos e alinhamento vêm da `.legenda .amostra`; o que
   é mesmo seu é o contorno, e não é decoração: o chip do «Fim de semana» é --cream (#faf8f1) sobre
   --paper (#ffffff) — sem uma linha à volta não há chip nenhum para ver.
   ⚠️ A abreviatura `border` vem DEPOIS do `.cal-fds` (que põe `border-color: transparent` na célula
   do calendário) e é por isso que ganha. As duas empatam em especificidade; muda-se a ordem e o
   chip do fim de semana desaparece. */
.cal-chip { border: 1px solid var(--line); }

/* O rótulo do ANO da lista (revisão final do PR 3c) — o título do card («O meu ano») deixou de
   levar o ano: a lista pode ser doutro ano que não o do saldo (Mes aceita anoAtual-1..+2, e
   marcar em novembro/dezembro férias do ano seguinte é uso normal). Mesmo tom discreto da
   `.ano-lista-mes` — mono, cor --muted — para ler-se como parte da mesma peça, e não como um
   segundo título a competir com o `.card-titulo`. */
.ano-lista-ano {
  margin: 14px 0 0;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 400;
  color: var(--muted);
}
.ano-lista-ano + .ano-lista-cabeca { margin-top: 4px; }

/* ── O cabeçalho dos dias 1–31 (ronda pós-agosto) ──
   A mesma grelha de 3 colunas da .ano-lista-linha e a mesma .ano-lista-barra lá dentro: as pistas
   TÊM de bater certo com as das linhas, senão os números não apontam para dia nenhum — é o que o
   AnoEmListaTests mede pelo alinhamento do 15. O padding horizontal é o da linha (4px), pela
   mesma razão. */
.ano-lista-cabeca {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) 52px;
  align-items: end;
  gap: 8px;
  margin: 14px 0 0;
  padding: 0 4px;
}
.ano-lista-cabeca + .ano-lista { margin-top: 2px; }
.ano-cabeca-dia {
  font-family: var(--font-mono);
  font-size: 9px;
  line-height: 12px;
  color: var(--muted);
  text-align: center;
  font-variant-numeric: tabular-nums;
}
/* Abaixo disto cada posição tem <11px e um «31» a 9px mono já não cabe na sua coluna — os números
   sobrepunham-se e apontavam para o dia errado, que é pior do que não os ter. */
@media (max-width: 599.98px) {
  .ano-lista-cabeca { display: none; }
}

/* ── O ano em lista (PR 3c, F2/F3): 12 linhas fluidas, sem scroll horizontal. A fatia não
   tem largura mínima — 31 × minmax(0,1fr) encolhe até onde for preciso, e é isso que mata
   o .ano-scroll. As cores são as mesmas classes da legenda (ano-aprovado…), intocadas. ── */
.ano-lista { display: flex; flex-direction: column; gap: 4px; margin-top: 14px; }
.ano-lista-linha {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) 52px;
  align-items: center;
  gap: 8px;
  padding: 2px 4px;
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: inherit;
}
.ano-lista-linha:hover { background: var(--cream); }
.ano-lista-linha:focus-visible { box-shadow: var(--shadow-ring); outline: none; }
.ano-lista-mes { font-family: var(--font-mono); font-size: 12px; color: var(--muted); text-align: right; }
.ano-lista-barra { display: grid; grid-template-columns: repeat(31, minmax(0, 1fr)); gap: 1px; height: 12px; }
/* O fundo BASE delimita um dia real sem marcação nenhuma (ronda pós-agosto: sem ele, um dia útil
   vazio era um buraco transparente entre o sábado e a mancha seguinte, e a barra lia-se como
   manchas soltas em vez de 31 dias). --sand e não --cream: o hover da linha pinta cream, e uma
   base cream desaparecia debaixo do rato. As classes `ano-*` a seguir têm a MESMA especificidade
   (0,1,0) e ganham por virem DEPOIS no ficheiro — a ordem aqui é regra, não arrumação. O
   `ano-vazio` devolve a transparência aos lugares que não existem (posições 29–31 dos meses
   curtos): sem essa exceção, fevereiro parecia ter 31 dias.
   Prova: AnoEmListaTests.Um_dia_util_sem_nada_tem_fundo_e_um_lugar_inexistente_nao. */
.ano-fatia { border-radius: 1px; background: var(--sand); }
.ano-fatia.ano-vazio { background: transparent; }
.ano-lista-contagem { font-family: var(--font-mono); font-size: 11px; color: var(--muted); text-align: right; white-space: nowrap; }
/* ── As cores de estado, PARTILHADAS pela lista e pela legenda ──
   A fatia (`.ano-fatia`) não tem borda nenhuma — só background — por isso as classes de
   cor abaixo bastam-se a si próprias, sem precisar de escopo nenhum contra uma regra de
   borda genérica (a `.ano-grelha > div` que a antiga grelha tinha morreu com ela). */
.ano-fds { background: var(--line); }
.ano-feriado { background: color-mix(in srgb, var(--gold-deep) 45%, transparent); }
.ano-aprovado { background: var(--ocean); }
.ano-pendente { background: color-mix(in srgb, var(--ocean) 34%, var(--paper)); }
/* Ausência: cor NOVA (--plum) mais FORMA própria, a mesma solução da `.mapa-ausencia` — riscas
   claras a 135°. Sem elas a célula distinguia-se da `.ano-aprovado` (--ocean) só pelo tom, e os
   dois estão a 1,22:1 de luminância um do outro: para quem não separa roxo de azul, a faixa anual
   ficava a dizer «férias aprovadas» num dia de doença. É a regra D8, a mesma que já obriga o
   pendente às riscas no mapa e o aniversário ao círculo.
   ⚠️ O passo é MAIS APERTADO do que o do mapa (2px/3,5px contra 3px/5px), e a razão é DENSIDADE, não
   salvamento. Aqui esteve escrito que «com o passo do mapa cabia pouco mais de uma risca e a forma
   deixava de se ler como padrão» — é falso, e foi medido em Chromium a 4x na ronda 1 da A6 (ver o
   `Os_padroes_das_amostras_do_mapa_leem_se_como_padrao`, que conta as riscas nos píxeis pintados):

     amostra de 14px, passo do mapa (3/5px) ........ 4,4 riscas   ← o que o mapa desenha hoje
     amostra de 14px, passo da faixa (2/3,5px) ..... 6,0 riscas   ← o que esta regra desenha  (sonda)
     amostra de 12px, passo da faixa ............... 5,1 riscas   ← esta regra até à A6        (sonda)
     amostra de 22px, passo do mapa ................ 6,3 riscas   ← o mapa até à A6            (sonda)

   ⚠️ Só a PRIMEIRA linha é medição da página a sério, e é a que aquele teste repete a cada corrida.
   As outras três estão marcadas «(sonda)»: duas já não existem em sítio nenhum (só se medem
   injetando um elemento à mão) e a terceira não tem prova a repeti-la. Dão escala, não são factos
   verificados — e uma marca destas em falta foi exatamente o defeito da ronda 2.

   Ou seja: o passo do mapa a 14px lê-se (4,4 riscas), só que mais folgado. O passo apertado existe
   para a faixa manter, num quadrado pequeno, a mesma densidade que o mapa tinha no seu quadrado
   grande — e não porque o outro passo fosse ilegível. Mesmo ângulo e mesma cor de risca, para as
   duas vistas falarem o mesmo dialeto; só a densidade acompanha o tamanho.
   ⚠️ Esta frase estava a condenar, trezentas linhas abaixo, o `.mapa-ausencia` que a A6 encolheu de
   22px para 14px sem lhe tocar no passo. Quem mexer num destes dois números tem de correr aquele
   teste: é ele, e não este comentário, que agora guarda a relação entre o tamanho e o passo.
   As células da faixa não têm texto (ver a nota do `tabindex` lá em cima), por isso a risca não
   pisa contraste de leitura nenhum — o que ela acrescenta é o canal não cromático. */
.ano-ausencia {
  background-color: var(--plum);
  background-image: repeating-linear-gradient(135deg, transparent 0, transparent 2px,
                    color-mix(in srgb, var(--paper) 60%, transparent) 2px,
                    color-mix(in srgb, var(--paper) 60%, transparent) 3.5px);
}
.ano-aniversario { background: var(--gold); }

/* ── Legenda ── A forma (linha, espaçamento, tipografia, lado da amostra) vem toda da `.legenda`
   partilhada — ver a secção «A forma comum das legendas (A6)». Aqui fica só o que é desta: o
   contorno da amostra, que a faixa precisa e o mapa não: as suas cores mais claras — `.ano-fds` em
   --line (#e6e3d9) e `.ano-feriado` a 45% de transparente — não se separam do --paper sem ele. */
.ano-amostra { border: 1px solid var(--line); }

/* ── Mapa mensal da equipa ──
   As cinco cores reutilizam a paleta da faixa anual, já testada em contraste. As formas — riscas
   no pendente, círculo no aniversário e marca textual no limite — dão o canal não cromático D8.
   A célula inerte não significa presença nem ausência: significa que a pessoa não estava empregada. */
.mapa-equipa { border-collapse: separate; border-spacing: 1px; font-size: 12px; }
.mapa-scroll { contain: paint; }
.mapa-equipa th, .mapa-equipa td { padding: 0; }
.mapa-equipa .mapa-nome { text-align: left; white-space: nowrap; padding-right: 12px;
                          position: sticky; left: 0; background: var(--paper); z-index: 1; }
.mapa-identidade { position: relative; display: inline-block; cursor: help; }
.mapa-nome-completo {
  display: none; position: absolute; top: calc(100% + 4px); left: 0; z-index: 3;
  padding: 4px 7px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--paper); color: var(--ink); font-family: var(--font-sans);
  font-size: 12px; font-weight: 500; letter-spacing: 0; text-transform: none;
  box-shadow: var(--shadow-sm);
}
.mapa-identidade:hover .mapa-nome-completo,
.mapa-identidade:focus .mapa-nome-completo { display: block; }
.mapa-equipa tbody th.mapa-nome:hover,
.mapa-equipa tbody th.mapa-nome:focus-within { z-index: 4; }
.mapa-equipa tbody tr:last-child .mapa-nome-completo {
  top: auto; bottom: calc(100% + 4px);
}
/* Linha de grupo (equipa) na «Por pessoa» — MP9: a tabela real não tinha esta noção; é uma linha
   `<tr class="mapa-grupo-linha">` a atravessar toda a tabela, em serifa, para separar visualmente
   as equipas escolhidas. Grep de colisão: `mapa-grupo-linha` — 0 ocorrências.
   ⚠️ Se esta linha calhar em último lugar (acontece: uma equipa escolhida SEM ninguém tem na mesma
   a sua linha de grupo), o dano NÃO é nela — ela não tem `.mapa-nome-completo` lá dentro para o
   seletor apanhar. É na linha ANTERIOR: a última linha de pessoa deixa de ser `:last-child` e
   perde o `bottom: calc(100% + 4px)` do `.mapa-equipa tbody tr:last-child .mapa-nome-completo`
   acima, que existe para o tooltip do nome completo abrir para CIMA e não ser cortado pelo
   contentor de scroll. É por isso que o `MapaEquipaTests:518`, que mede esse tooltip, tem de
   continuar a abrir o mapa com UMA equipa só — está escrito no teste que declara a consequência
   (`Uma_equipa_sem_ninguem_no_mes_tem_na_mesma_a_sua_linha_de_grupo`). */
.mapa-grupo-linha td {
  font-family: var(--font-serif);
  font-size: 14px;
  color: var(--ocean);
  background: var(--sand);
  padding: 8px 12px;
  border-bottom: 1px solid var(--line);
}
/* ⚠️ A CAUSA: as três linhas (dia / contagem / «!») só existiam nas colunas em
   excesso, e com `vertical-align: bottom` isso empurrava ESSES dias para cima —
   os números do mês ficavam em duas alturas diferentes. Agora todas as colunas
   reservam exatamente as mesmas três faixas; o «!» dá lugar a uma barra. */
.mapa-equipa thead th {
  vertical-align: top;
  min-width: 24px;
  padding: 0 0 5px;
}
.mapa-equipa thead th > .mapa-cabeca {
  display: grid;
  grid-template-rows: 14px 16px 3px;
  align-items: center;
  justify-items: center;
  gap: 2px;
}
.mapa-dia { display: block; font-size: 10px; line-height: 14px; color: var(--muted); }
.mapa-conta { display: block; font-size: 12px; line-height: 16px; }
.mapa-barra { display: block; width: 14px; height: 3px; border-radius: 2px; background: transparent; }
.mapa-equipa th.mapa-col-cheia .mapa-barra { background: var(--status-warning); }
.mapa-equipa th.mapa-col-cheia .mapa-conta { color: var(--status-warning); font-weight: 700; }
/* Fim de semana marcado TAMBÉM no cabeçalho: sem isso a contagem de um sábado lê-se como se
   fosse um dia de trabalho. */
.mapa-equipa th.mapa-col-fds { background: rgba(14, 21, 47, 0.035); }
/* ⚠️ Regra morta por agora: nenhuma coluna recebe `.mapa-col-feriado`. `ColunaMapa` (a linha
   do cabeçalho) não tem escritório — só a CÉLULA de cada pessoa sabe se um dia é feriado dela,
   porque o calendário é por escritório e uma coluna mistura pessoas de escritórios diferentes.
   Marcar a coluna inteira exigiria inventar um facto (ex.: "feriado nacional") que
   `MapaEquipaService` hoje não expõe a este nível. Fica pronta para quando essa decisão for
   tomada — ver Tarefa 12, ronda de correção 1. */
.mapa-equipa th.mapa-col-feriado .mapa-dia { color: var(--gold-deep); font-weight: 700; }
/* Uma régua de cada 5 dias, para não se contar coluna a coluna. */
.mapa-equipa th.mapa-col-marco { box-shadow: inset 1px 0 0 var(--line); }
.mapa-equipa td.mapa-cel { display: table-cell; }
.mapa-cel { width: 22px; height: 22px; border-radius: 2px; background: var(--paper); }
.mapa-aprovado { background: var(--ocean); }
.mapa-pendente {
  background-color: color-mix(in srgb, var(--ocean) 34%, var(--paper));
  background-image: repeating-linear-gradient(45deg, transparent 0, transparent 3px,
                    color-mix(in srgb, var(--ocean) 34%, transparent) 3px,
                    color-mix(in srgb, var(--ocean) 34%, transparent) 5px);
}
/* Ausência: cor NOVA (--plum) mais forma própria — riscas claras a 135°, ao contrário das do
   pendente (escuras, a 45°). Sem a forma, a célula ficaria a distinguir-se do "aprovado" só pelo
   tom, que é exatamente o que o canal não cromático da D8 existe para evitar. */
.mapa-ausencia {
  background-color: var(--plum);
  background-image: repeating-linear-gradient(135deg, transparent 0, transparent 3px,
                    color-mix(in srgb, var(--paper) 60%, transparent) 3px,
                    color-mix(in srgb, var(--paper) 60%, transparent) 5px);
}
.mapa-aniversario { background: var(--gold); border-radius: 50%; }
.mapa-feriado {
  background-color: color-mix(in srgb, var(--gold-deep) 45%, transparent);
  background-image: repeating-linear-gradient(0deg, transparent 0, transparent 3px,
                    color-mix(in srgb, var(--paper) 65%, transparent) 3px,
                    color-mix(in srgb, var(--paper) 65%, transparent) 5px);
}
.mapa-fds {
  background-color: var(--line);
  background-image: radial-gradient(circle at center, var(--muted) 1px, transparent 1.5px);
}
.mapa-inerte { background: transparent; box-shadow: inset 0 0 0 1px var(--line); opacity: .45; }
/* A forma da legenda (linha, espaçamento, tipografia, lado da amostra) vem toda da `.legenda`
   partilhada — ver a secção «A forma comum das legendas (A6)». A amostra era de 22px, o lado da
   célula do mapa; passou aos 14px comuns às três legendas de amostra abstrata. O que fica aqui é o
   que é mesmo do mapa: o círculo do aniversário.
   ⚠️ Os PADRÕES (`.mapa-ausencia` a 135°, `.mapa-pendente` a 45°, `.mapa-feriado` a 0°) atravessaram
   os 22px→14px com o passo intacto, e isso foi medido e não presumido: a 14px continuam a dar 4,4 /
   4,3 / 3,0 riscas claras dentro da amostra (Chromium a 4x, ronda 1 da A6). Quem mexer no lado da
   amostra OU no passo tem de correr o `Os_padroes_das_amostras_do_mapa_leem_se_como_padrao`, que é
   quem guarda a relação entre os dois — nenhuma prova o fazia quando a amostra encolheu.
   ⚠️ Este `border-radius` empata em especificidade com o `.legenda .amostra` (0,2,0) e só ganha por
   vir DEPOIS no ficheiro — ver o aviso na secção da `.legenda`. A forma redonda é o canal não
   cromático do aniversário, não é decoração.
   ⚠️ A `.mapa-amostra` continua a existir como classe e é nome LOAD-BEARING: é por ela que o
   `@media print` lá em baixo escreve a letra de cada estado dentro da amostra. */
.mapa-legenda .mapa-aniversario { border-radius: 50%; }
.mapa-filtros { align-items: flex-end; }
.mapa-meses { display: flex; justify-content: space-between; gap: 16px; margin: 16px 0; }

/* ── PR 3 (mapa da equipa): chips de equipas e de estado ──
   Grep de colisão corrido no ficheiro INTEIRO antes de escrever, composto ou não: `mapa-chips`,
   `mapa-chip`, `mapa-chip-remover`, `mapa-chip-juntar-wrap`, `mapa-chip-juntar`, `mapa-chip-lista`,
   `mapa-chip-opcao`, `mapa-chip-vazio`, `mapa-chip-estado`, `mapa-chip-estado-ativo` — 0 ocorrências
   de cada. ⚠️ Prefixo `mapa-chip-`, e não `mapa-equipa-`: `.mapa-equipa` já existe (é a `<table>` da
   «Por pessoa») e um chip chamado `.mapa-equipa-remover` teria colidido em leitura, ainda que não
   em especificidade.
   Os chips de equipa e o botão «Remover» são `<a>` (navegação por `?ambito=`, sem JS) — não
   `<button>` como no mockup simulado —, daí `text-decoration: none` em vez de `border: none` e a
   ausência de `aria-pressed` (um `<a>` não pode usar esse atributo; ver `.mapa-chip-estado`, que
   também é `<a>` e resolve pelo `.sr-only`). */
.mapa-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.mapa-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 6px 6px 12px;
  background: var(--sand);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  font-size: 13px;
  color: var(--ink);
}
.mapa-chip-remover {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  color: var(--muted);
  text-decoration: none;
  line-height: 1;
}
.mapa-chip-remover:hover, .mapa-chip-remover:focus-visible {
  background: rgba(14, 21, 47, 0.08);
  color: var(--ink);
}
.mapa-chip-remover svg { width: 10px; height: 10px; }
/* P1 (passagem de CSS, 2026-08-21): faltava o par do `.mapa-chip-estado[aria-disabled="true"]` —
   sem ele o `×` da última equipa (markup em MapaEquipa.cshtml:121, `role="link" aria-disabled=
   "true"`, sem `href`) ficava visualmente IGUAL a um remover ativo e continuava a reagir ao
   `:hover`. Mesmo idioma do par que já existe: opacidade + `not-allowed`, e o `:hover`/`:focus-
   visible` de cima deixa de se aplicar (o seletor mais específico ganha). */
.mapa-chip-remover[aria-disabled="true"] { opacity: 0.6; cursor: not-allowed; }
.mapa-chip-remover[aria-disabled="true"]:hover, .mapa-chip-remover[aria-disabled="true"]:focus-visible {
  background: transparent;
  color: var(--muted);
}

/* `+ Equipa`: `<details>`/`<summary>` — o `<summary>` já é um botão nativo (MP12), por isso não leva
   `border`/`background` próprios além dos que o desenho pede. */
.mapa-chip-juntar-wrap { position: relative; display: inline-flex; }
.mapa-chip-juntar {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  list-style: none;
  padding: 6px 12px;
  border-radius: var(--radius-pill);
  border: 1px dashed var(--line);
  background: transparent;
  color: var(--muted);
  font-size: 13px;
  cursor: pointer;
}
.mapa-chip-juntar::-webkit-details-marker { display: none; }
.mapa-chip-juntar:hover { border-color: var(--cyan-soft); color: var(--ocean); }
.mapa-chip-lista {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 20;
  min-width: 200px;
  max-width: min(260px, 80vw);
  padding: 6px;
  margin: 0;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.mapa-chip-opcao {
  display: block;
  width: 100%;
  text-align: left;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  color: var(--ink);
  text-decoration: none;
}
.mapa-chip-opcao:hover, .mapa-chip-opcao:focus-visible { background: var(--sand); color: var(--ocean); }
.mapa-chip-vazio { padding: 7px 10px; font-size: 12px; color: var(--muted); margin: 0; }

/* Estado ligado/desligado (MP6): fundo + PESO (dois canais; a cor nunca é o único) mais o
   `.sr-only` que diz o estado por palavras — um `<a>` não pode usar `aria-pressed`. */
.mapa-chip-estado {
  display: inline-block;
  font-size: 13px;
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  text-decoration: none;
  transition: background-color var(--transition-fast), color var(--transition-fast);
}
.mapa-chip-estado:hover { border-color: var(--cyan-soft); }
.mapa-chip-estado-ativo { background: var(--sand); color: var(--ink); font-weight: 600; }
.mapa-chip-estado[aria-disabled="true"] { opacity: 0.6; cursor: not-allowed; }

/* ── Vista «Por dia» do mapa da equipa (PR 3d, M3/M7 → PR 3, direção E) — calendário mensal
   INERTE, sem <button> nenhum (o único elemento clicável é o `+N` que abre o painel, MP5). A
   grelha passou de 7 colunas iguais a 5 (seg-sex) + 2 finas de 34px (sáb/dom) na direção E — deixou
   de ser fluida sem scroll: ganhou `min-width: 820px` e vive dentro de `.mapa-dia-scroll` (ver mais
   abaixo). As marcas de fim de semana e de excesso reusam os tokens já validados da vista «Por
   pessoa» (`--cream`/fds, `--status-warning`/excesso) — é a mesma informação, só noutro eixo de
   leitura.
   ⚠️ O seletor é `section.mapa-dia`, e não `.mapa-dia` a seco: a vista «Por pessoa» já tem um
   `.mapa-dia` (linha ~1512) no número do dia do CABEÇALHO da coluna — `<span class="mapa-dia">`,
   `display: block; font-size: 10px`. Um `.mapa-dia` a seco aqui, mais abaixo no ficheiro,
   ganhava a esse por ordem de cascata (mesma especificidade) e desfazia o número da coluna da
   grelha antiga. `section.mapa-dia` só apanha o `<section>` desta vista nova (o elemento
   raiz do `_MapaPorDia.cshtml`, que existe — e não um `<div>` — porque o `aria-label` só é
   exposto pela árvore de acessibilidade num elemento com role implícito, e um `<div>` não
   tem nenhum). */
/* ⚠️ Achado do inventário (Task 1): a spec dizia que o contentor de scroll «já existia» —
   enganava-se, `.mapa-dia-scroll` não tinha ocorrência nenhuma no repo. Sem ele, o `min-width:
   820px` do `section.mapa-dia` abaixo faz deslizar a PÁGINA, não a grelha — a mesma armadilha já
   paga na tabela «Por pessoa» (`.tabela-scroll`, que dá `overflow-x: auto` ao `.mapa-scroll`
   dela). Aqui o markup (Task 7) é `<div class="mapa-dia-scroll mapa-scroll">`, sem `.tabela-scroll`
   — por isso o `overflow-x` tem de nascer nesta classe própria, e não herdar do `.mapa-scroll`
   partilhado, que só dá `contain: paint` (linha ~1600). Grep de colisão: `mapa-dia-scroll` — 0
   ocorrências. */
.mapa-dia-scroll { overflow-x: auto; }
section.mapa-dia {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr)) 34px 34px; /* era repeat(7, minmax(0, 1fr)) */
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  overflow: hidden;
  /* ⚠️ AQUI ESTAVA `container-type: inline-size`, e foi APAGADO na vaga C — depois de medido, que
     é o que a vaga B (só CSS, sem Playwright) não podia fazer e deixou dito. A `@container
     (max-width: 620px)` que o lia já tinha sido apagada por inalcançável (ver o comentário junto à
     `.mapa-dia-fds-numero`), e nenhum outro `@container` da folha aponta a este contentor — mas
     apagá-lo não era óbvio, porque `container-type: inline-size` IMPLICA
     `contain: layout style inline-size` e podia estar a segurar o encaixe da grelha.
     MEDIÇÃO (Playwright, Chromium, cenário de 2 equipas, a 390 / 768 / 1400px): com e sem a linha,
     TUDO o que se mede é idêntico ao centésimo — caixa da grelha (820×638,45 / 820×638,45 /
     1006×622,95), `scrollWidth`/`scrollHeight` da grelha e do `.mapa-dia-scroll`, largura do
     contentor, dimensões da página, os retângulos das 42 células uma a uma, o `min-height` e o
     `padding` da célula e o `font-size` do cabeçalho. A ÚNICA diferença entre os dois retratos era
     o valor computado da própria propriedade. (O `contain` computado dá `none` nos dois casos: a
     conteção implícita não aparece nessa propriedade.)
     ⚠️⚠️ A primeira versão desta sonda acusou «diferente» nas três larguras — um desvio de ~0,95px
     no `y` — e era FALSO: o CONTROLO (injetar o MESMO valor, `inline-size` outra vez) dava
     exatamente o mesmo desvio. A página assenta um pouco entre duas leituras seguidas, e o `y`
     absoluto anda sozinho. O retrato passou a ser RELATIVO à grelha e o controlo a bater certo.
     Quem quiser mesmo a célula compacta no telemóvel tem de repor o `container-type` NOUTRO
     elemento (o `.mapa-dia-scroll`, que acompanha a largura do ecrã) — é decisão de desenho. */
  /* MEDIDO (Playwright, Chromium headless — ver MP11): 5 colunas úteis a ~140px + 2×34px + gaps.
     Os nomes completos e o rótulo «COM 6/10 · excesso» precisam de mais espaço por coluna do que a
     vista antiga (fluida, sem min-width) dava — a 390px isso voltava a quebrar palavra a palavra.
     É o `.mapa-dia-scroll` acima que absorve o excesso, exatamente como o `.tabela-scroll` já faz
     na tabela «Por pessoa». */
  min-width: 820px;
  /* ⚠️ Ronda final da PR 3d (minor 5): a classe `.mapa-dia` é PARTILHADA com o span do cabeçalho
     da grelha antiga (linha ~1512, `<span class="mapa-dia">`, font-size 10px/line-height 14px/
     color muted) — sem estas três linhas, editar essa regra legada muda esta secção INTEIRA em
     silêncio, por herança, até o par tratamento/oficial dos nomes lá dentro (era exatamente esse
     o defeito: o tratamento herdava `--muted` da regra legada e ficava indistinguível do
     oficial). font-size/line-height ficam neutros (o valor do `body`, que é o que cada descendente
     já sobrepõe com o seu próprio tamanho); a cor volta a `--ink`, a normal — só quem quer
     `--muted` (o oficial, a contagem) o pede explicitamente. */
  font-size: 15px;
  line-height: 1.55;
  color: var(--ink);
}
.mapa-dia-dow {
  padding: 8px 6px;
  background: var(--sand);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--muted);
  text-align: center;
}
/* ⚠️ Fidelidade ao mockup aprovado (`mapa-equipa.html`, `.pde-cel`): o `gap` tinha divergido para
   3px sem justificação escrita nenhuma — o mockup usa 5px. `.mapa-dia-celula` é PARTILHADA pelos
   três tipos de célula (dia útil, `.mapa-dia-fds`, `.mapa-dia-vazia`): confirmado antes de mexer
   que a `.mapa-dia-fds` (linha ~1906) já reescreve o seu próprio `gap: 6px` (o do mockup,
   `.pde-fds`) — por isso subir este `gap` só muda o espaço vertical DENTRO da célula de dia útil
   (entre `.mapa-dia-topo` e cada bloco `.mapa-dia-equipa`, e entre equipas quando há mais de uma);
   a `.mapa-dia-vazia` não tem filhos, não é afetada. */
.mapa-dia-celula {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-height: 74px;
  padding: 6px 7px 7px;
  background: var(--paper);
  font-size: 11px;
}
.mapa-dia-vazia { background: var(--cream); }
/* P8 (passagem de CSS, 2026-08-21): a `.mapa-dia-fds` só trazia o fundo — o mockup
   (`mapa-equipa.html`, `.pde-fds`) centra a coluna comprimida (`align-items: center; padding:
   8px 4px; gap: 6px`) e sem isto o número de 34px ficava encostado à esquerda, herdado da
   `.mapa-dia-celula` (que é `flex-direction: column` sem `align-items` próprio). Único
   consumidor confirmado por grep (`_MapaPorDia.cshtml:107`): a célula de fim de semana da
   grelha «Por dia» — nada mais lê esta classe, por isso não há segundo efeito a temer. */
.mapa-dia-fds {
  background: color-mix(in srgb, var(--cream) 80%, var(--paper));
  align-items: center;
  padding: 8px 4px;
  gap: 6px;
}
/* Tinta de aviso das novas células agrupadas por equipa (direção E). ⚠️ Dentro da grelha nunca se
   usa `rgba()`: a `.mapa-dia-fds`/`.mapa-dia-vazia` acima já mostram porquê — a
   `.mapa-legenda`/grelha preenche o `gap: 1px` com `var(--line)`, e um `background` (atalho, como
   os dois de cima) apaga o `--paper` da célula por baixo; um `rgba()` aqui compunha sobre o
   CINZENTO da grelha, não sobre o papel — o mesmo acidente medido no PR 2 (`.escala-mes-dia.feriado`,
   `#e2dbc8` em vez de `#f8f4ea`). `color-mix(…, var(--paper))` fica opaco e sai da paleta. Grep de
   colisão: `mapa-dia-limite`, `mapa-dia-excesso` — 0 ocorrências de cada. */
.mapa-dia-limite { background: color-mix(in srgb, var(--status-warning) 7%, var(--paper)); }
.mapa-dia-excesso { background: color-mix(in srgb, var(--status-warning) 14%, var(--paper)); }
.mapa-dia-numero {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
/* «Hoje»: mesma construção do `.escala-mes-dia.hoje` (anel interior a `--cyan-deep`) — dois canais,
   o anel E a cor do número, nenhum dos dois é `rgba()`. Grep de colisão: `mapa-dia-hoje` — 0
   ocorrências. */
.mapa-dia-hoje { box-shadow: inset 0 0 0 2px var(--cyan-deep); }
.mapa-dia-hoje .mapa-dia-numero { color: var(--cyan-deep); }
/* P4 (passagem de CSS, 2026-08-21): `.mapa-dia-contagem`, `.mapa-dia-cheia .mapa-dia-contagem` e
   `.mapa-dia-regra` apagadas — grep antes de cada uma, em markup/CSS/JS/testes C#, confirmou o
   único consumidor a sobrar em `MapaPorDiaTests.cs:413/416/419` (browser), que a Task 10 reescreve
   a seguir; substituídas por `.mapa-dia-equipa-nome`/`.mapa-dia-equipa-nome strong` (linhas
   abaixo). */
/* ── Célula agrupada por equipa (direção E) ── Um bloco `.mapa-dia-equipa` por equipa ativa COM
   alguém a assinalar nesse dia; `.mapa-dia-topo` embrulha o número + o triângulo de aviso.
   Grep de colisão corrido no ficheiro INTEIRO, composto ou não: `mapa-dia-topo`, `mapa-dia-tri`,
   `mapa-dia-equipa`, `mapa-dia-equipa-nome`, `mapa-dia-mais`, `mapa-dia-fds-numero` — 0 ocorrências
   de cada. */
.mapa-dia-topo { display: flex; align-items: flex-start; justify-content: space-between; gap: 4px; }
.mapa-dia-tri { width: 13px; height: 13px; flex: 0 0 13px; color: var(--status-warning); }
.mapa-dia-equipa { margin: 0; }
.mapa-dia-equipa-nome {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 2px;
  overflow-wrap: break-word;
}
.mapa-dia-equipa-nome strong { color: var(--status-warning); font-weight: 700; }
/* O «+N · ver o dia» que abre o painel (MP5): é o ÚNICO elemento clicável desta grelha — uma célula
   sem excesso não é clicável (decisão declarada na spec). `font: inherit` primeiro e
   `font-family`/`font-size` depois, como o resto dos botões desta folha que imitam texto corrido. */
.mapa-dia-mais {
  display: block;
  font: inherit;
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--cyan-deep);
  margin: 1px 0 0;
  padding: 0;
  border: 0;
  background: transparent;
  text-align: left;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.mapa-dia-mais:hover, .mapa-dia-mais:focus-visible { color: var(--ocean); }

/* As marcas de motivo (MP3): o MESMO vocabulário visual das células de 22px da «Por pessoa»
   (`.mapa-aprovado`/`.mapa-ausencia`/`.mapa-aniversario`), a 9px para caber antes de um nome —
   sólido / listrado / círculo, forma e padrão, não só cor (D8). Só 3 motivos aqui (`Ferias`,
   `Falta`, `Aniversario`; sem `PorDecidir` — MP4, «Por decidir» não desenha na «Por dia») mais o
   feriado, que não é um `MotivoMapa`.
   ⚠️ `border: 1px solid transparent`: um fundo sem borda desaparece em `forced-colors` (alto
   contraste do Windows) — o padrão já pago no `.nav-badge` (linha ~334) e no tile do PR 1. */
.mapa-marca {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 2px;
  flex: 0 0 9px;
  vertical-align: -1px;
  margin-right: 4px;
  border: 1px solid transparent;
}
.mapa-marca-ferias { background: var(--ocean); }
.mapa-marca-falta {
  background-color: var(--plum);
  background-image: repeating-linear-gradient(135deg, transparent 0 2px,
                    color-mix(in srgb, var(--paper) 60%, transparent) 2px 4px);
}
.mapa-marca-aniversario { background: var(--gold); border-radius: 50%; }
.mapa-marca-feriado {
  background-color: color-mix(in srgb, var(--gold-deep) 45%, transparent);
  background-image: repeating-linear-gradient(0deg, transparent 0 2px,
                    color-mix(in srgb, var(--paper) 65%, transparent) 2px 4px);
}
/* A legenda da vista «Por dia» (C2). A FORMA vem toda da `.legenda` partilhada (A6) — linha,
   espaçamento, tipografia, lado da amostra —, e por isso a única regra que aqui sobra é esta: as
   amostras desta legenda são as MARCAS REAIS da grelha, e a `.mapa-marca` traz um `margin-right:
   4px` que existe para separar a marca do NOME dentro da célula. Numa legenda esse papel é do
   `gap: 6px` da `.legenda > li`, e os dois somados davam 10px — a única das sete legendas com um
   espaço diferente das outras.
   Grep de colisão no ficheiro inteiro, composto ou não: `mapa-dia-legenda` — 0 ocorrências. */
.mapa-dia-legenda .mapa-marca { margin-right: 0; }

/* ⚠️ Ronda pós-agosto (pedido do Bruno): era um <details> com summary «nomes» e o par
   tratamento+oficial lá dentro; o disclosure morreu (os nomes estão SEMPRE à vista) e o oficial
   saiu (cada linha é só o tratamento — a porta única do Funcionario.Tratamento). O `.sr-only` do
   detalhe de privacidade fica, no mesmo canal de sempre.
   ⚠️⚠️ O `margin: auto 0 0` de «encostar ao fundo da célula» (herdado dessa ronda) ficou falso
   nesta direção E: o `<ul>` deixou de ser filho direto do flex `.mapa-dia-celula` e passou a viver
   dentro do `<div class="mapa-dia-equipa">` (bloco normal, sem `display: flex` próprio) — um
   `margin-top: auto` fora de um item flex/grid resolve para 0 em fluxo normal, não empurra nada.
   Fica `margin: 0`, o valor que já se estava a obter na prática.
   ⚠️⚠️⚠️ Herança do minor 2 da ronda do 3d, que continua a valer: o `<li>` vive dentro do
   `overflow: hidden` do `section.mapa-dia`, numa coluna que já não encolhe com o viewport desde o
   `min-width: 820px` da grelha (mede ~140px a qualquer largura de ecrã — é o `.mapa-dia-scroll`
   que absorve o resto) — sem `overflow-wrap` um nome longo cortava-se em silêncio ou sobrepunha-se
   à célula vizinha. E com o details fora, o pior caso passou a ser o TRATAMENTO de quem não tem
   NomeAbreviado (cai no nome completo); o crescimento é VERTICAL (mais linhas), nunca horizontal —
   medido no `Um_nome_colado_nao_transborda_a_celula_a_390px` (o teste que media isto a 360px foi
   renomeado/reescrito para os 390px do MP11; a citação antiga já não existe no repo). */
.mapa-dia-nomes {
  margin: 0;
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* Fidelidade ao mockup aprovado (`.pde-nomes`): `font-size`/`line-height` viviam no `<li>` (só
     `font-size: 10px`, sem `line-height` nenhum) em vez de na lista, e o valor tinha divergido dos
     11,5px/1,5 do desenho sem justificação escrita — é texto que a pessoa lê. */
  font-size: 11.5px;
  line-height: 1.5;
}
.mapa-dia-nomes li { overflow-wrap: break-word; }
/* P4 (passagem de CSS, 2026-08-21): `.mapa-dia-tratamento` apagada — grep confirmou o único
   consumidor a sobrar em `MapaPorDiaTests.cs:466/475` (browser, reescrito na Task 10); o par
   tratamento/oficial deu lugar à `.mapa-marca` + `PrimeiroEUltimo` dentro de `.mapa-dia-nomes li`. */

/* Fim de semana comprimido a 34px, número em vertical — mesma marca das células úteis (9px, sem
   `margin-right`, porque aqui não há nome ao lado a espaçar). Grep de colisão:
   `mapa-dia-fds-numero` — 0 ocorrências. */
.mapa-dia-fds-numero {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  writing-mode: vertical-rl;
  transform: rotate(180deg);
}
.mapa-dia-fds .mapa-marca { margin-right: 0; cursor: help; }

/* ⚠️ AQUI VIVIA a `@container` da célula compacta (520px, subida para 620px durante este PR) e foi
   APAGADA, porque não podia disparar. O container ERA a própria grelha (`container-type:
   inline-size` no `section.mapa-dia`) e o `min-width: 820px` que a direção E exige é o CHÃO da sua
   inline-size: a consulta nunca era verdadeira. Medido em Chromium (PR 3, Task 10): a grelha mede
   820 / 820 / 1006px a 390 / 768 / 1400px de viewport, e a célula fica sempre com os valores de
   base. ⚠️ O `container-type` do `section.mapa-dia` também JÁ NÃO EXISTE — apagado na vaga C
   depois de medido que não mudava um único pixel (a medição está escrita na regra dele, linha
   ~1861), porque um contentor sem consulta nenhuma a lê-lo é só uma armadilha à espera.
   O que o ecrã estreito faz é DESLIZAR dentro do `.mapa-dia-scroll`, com a célula do tamanho
   normal — e é assim que o mockup aprovado também se comporta (tem a mesma regra morta).
   Quem quiser mesmo a célula compacta no telemóvel tem de mudar o `container-type` de sítio (para
   o `.mapa-dia-scroll`, que acompanha a largura do ecrã) — é decisão de desenho, não limpeza.
   Registado no `known-followups.md`. */

/* ── Painel de detalhe do dia da vista «Por dia» (MP5) ──
   Gémeo do `.escala-dia-painel*` (linhas ~2161-2243) — MESMOS valores, só o prefixo muda; a
   receita não se inventa duas vezes. A transição é apanhada pelo bloco global de
   `prefers-reduced-motion` (mais abaixo): não se escreve regra própria aqui, como a `.escala-dia-
   painel` também não escreve.
   Grep de colisão corrido no ficheiro INTEIRO, composto ou não: `mapa-dia-painel` e cada sufixo
   (`-cabeca`, `-titulo`, `-fechar`, `-corpo`, `-secao`, `-secao-titulo`, `-linha`) — 0 ocorrências
   de cada. O `.aberto` reutiliza-se: já é seletor partilhado pelo `.escala-dia-painel.aberto`, sem
   colisão de significado (o mesmo estado, a mesma transição, noutro painel).
   ⚠️ P11 (passagem de CSS, 2026-08-21): NÃO existe `.mapa-dia-painel-fundo` — houve uma regra com
   esse nome (véu fixo `position: fixed; inset: 0`) e foi apagada. Era CSS morto (o markup
   `MapaEquipa.cshtml:358` diz explicitamente que não a escreve) e o comentário que a acompanhava
   contradizia a MP5: a tabela diz «clique fora: NÃO fecha» e o painel é `aria-modal="false"` para
   COEXISTIR com a grelha por trás — um véu a cobrir a grelha inteira (`z-index: 190`) tornava
   impossível a linha vinculativa da mesma tabela («`+N` de outra célula com o painel aberto → troca
   de dia sem fechar»). Não recriar sem reabrir a MP5 primeiro. */
.mapa-dia-painel {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 200;
  background: var(--paper);
  border-top: 1px solid var(--line);
  box-shadow: var(--shadow-md);
  border-radius: var(--radius-md) var(--radius-md) 0 0;
  padding: 16px 20px calc(16px + env(safe-area-inset-bottom, 0px));
  max-height: 46vh;
  overflow-y: auto;
  transform: translateY(100%);
  transition: transform var(--transition-base);
}
.mapa-dia-painel.aberto { transform: translateY(0); }
.mapa-dia-painel-cabeca {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}
.mapa-dia-painel-titulo {
  font-family: var(--font-serif);
  font-size: 17px;
  color: var(--ocean);
  margin: 0;
}
.mapa-dia-painel-fechar {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--paper);
  color: var(--muted);
  cursor: pointer;
}
.mapa-dia-painel-fechar:hover { color: var(--ink); background: var(--sand); }
.mapa-dia-painel-fechar svg { width: 14px; height: 14px; }
.mapa-dia-painel-corpo {
  margin-top: 10px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* `.mapa-dia-painel-secao` não leva regra nenhuma de propósito, tal como o gémeo
   `.escala-dia-painel-secao`: é um embrulho ESTRUTURAL, só para o `gap: 10px` do `-corpo` separar
   as SECÇÕES (uma por equipa) em vez de separar todas as linhas. */
.mapa-dia-painel-secao-titulo {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 4px;
}
/* O painel COPIA o `<strong>` do rótulo da grelha (`mapa-equipa.js:150-151`, `criarSecao`) quando a
   equipa está no limite/excesso — mas herdava só o negrito da folha do browser, sem a cor. O
   mockup (`.dia-painel-secao-titulo strong`) e o gémeo da grelha (`.mapa-dia-equipa-nome strong`,
   linha ~1955) marcam os dois com `--status-warning`; sem esta linha o painel é o único dos três
   sítios (grelha, legenda do triângulo, painel) a perder o canal de cor no mesmo aviso. */
.mapa-dia-painel-secao-titulo strong { color: var(--status-warning); }
.mapa-dia-painel-linha {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 13px;
  margin: 0 0 3px;
}
/* ⚠️ NÃO se reescreve aqui a `.mapa-marca`: a regra base (mais acima) já traz as medidas certas
   (9px, `border-radius: 2px`, `border: 1px solid transparent`) — copiá-las de novo, depois da
   `.mapa-marca-aniversario`, repunha-lhe o `border-radius: 2px` e transformava o círculo do
   aniversário num quadrado. Mesmo acidente que o `.escala-dia-painel-linha` já documenta para a
   `.escala-fora-marca`. */

/* ── PR 3b (mapa da equipa): vista «Anual» ──
   ⚠️ PREFIXO `mapa-ano-`, e é obrigatório: `.ano-fds`, `.ano-feriado` e `.ano-amostra` JÁ EXISTEM
   neste ficheiro (faixa anual PESSOAL do PR 3c, em produção desde 2026-08-18) com outros valores —
   a `.ano-fds` é `background: var(--line)`, muito mais escura do que a desta grelha. Reutilizá-las
   partia uma página que funciona. Grep de colisão corrido nos DOIS ficheiros de CSS do repo
   (`site.css` e `Pages/Shared/_Layout.cshtml.css`), inteiros e por SUBSTRING — logo, composto ou
   não —, antes de escrever a primeira linha: 0 ocorrências de cada uma das 16, mais a
   `mapa-ano-periodo` que a task 8 vai usar.
   ⚠️ UMA das 17 fica SEM regra nenhuma, de propósito: a `.mapa-ano-legenda`, porque a legenda tira
   a forma toda da `.legenda` partilhada e só precisa de um nome onde crescer. A `.mapa-ano-periodo`
   também aqui ficou, e a ruling A18 corrigiu-o: ela veste-se mesmo do
   `tira-meses-titulo`/`tira-meses-ano`, mas as FOLGAS à volta dela são de adjacência e não pegam
   num irmão com outro nome — tem duas linhas próprias ao pé das da tira, e a impressão esconde-a
   com as outras navegações. A `.mapa-ano-linha` não tem regra PRÓPRIA, mas é load-bearing: é ela
   que dá especificidade ao par de regras que corrige as arestas, mais abaixo.

   ⚠️⚠️ `table-layout: fixed`, e não o `auto` que a `.tabela` herda: em `auto` o excedente do
   `min-width` redistribui-se PROPORCIONALMENTE por todas as colunas, mesmo com `width` e
   `max-width` explícitos — pediram-se 48px para a coluna do mês e mediram-se 52,48px (Chromium
   headless, viewport de 1400px, com esta declaração tirada e o resto do bloco no sítio; a prova é
   a `A_coluna_do_mes_fica_na_largura_pedida`, que com a declaração no sítio mede 48,00px).
   Os 916px do `min-width` são a soma das colunas: 48 do mês + 31 × 28 dos dias. */
/* A nota que só existe no papel — ver o `@media print`. Escondida aqui, e não com `hidden`, porque
   o `[hidden]` do browser traz `display: none !important` e nem o `!important` do print lhe ganhava. */
.mapa-ano-so-no-papel { display: none; }

.mapa-ano-tabela { min-width: 916px; table-layout: fixed; }
.mapa-ano-tabela th, .mapa-ano-tabela td { text-align: center; padding: 2px 1px; }
.mapa-ano-tabela thead th {
  font-family: var(--font-mono); font-size: 10.5px; color: var(--muted); font-weight: 500;
}
/* ⚠️ O sticky escreve-se AQUI POR INTEIRO, e não se herda: o sticky da primeira coluna que já
   existe é `.mapa-equipa .mapa-nome` — pede um ancestral `.mapa-equipa` que esta tabela não tem, e
   sem ele `.mapa-nome` sozinho fica em `position: static`. O seletor é composto (2 classes
   + 1 elemento) para bater a regra de cima, que junta um elemento e é por isso mais específica.
   ⚠️⚠️ SÓ `th`, e é deliberado: a `.mapa-ano-mes` NUNCA é escrita num `td`. O rótulo do mês é
   `<th scope="row">` (`_MapaAnual.cshtml:34`) e o da esquina `<th scope="col">` (:22) — são
   cabeçalhos de linha e de coluna, e é assim que têm de ser para um leitor de ecrã anunciar o mês
   ao entrar na linha. A metade `td.mapa-ano-mes` que aqui esteve até à A15 não tinha consumidor
   nenhum: CSS sem consumidor é o sinal barato da costura entre tasks, e o custo dele não é o
   peso — é fazer o leitor seguinte acreditar que existe um caso que nunca existiu. */
.mapa-ano-tabela th.mapa-ano-mes {
  position: sticky; left: 0; z-index: 1; background: var(--paper);
  width: 48px; min-width: 48px; max-width: 48px;
  font-family: var(--font-mono); font-size: 11px; text-transform: lowercase;
  text-align: left; padding: 3px 6px; white-space: nowrap;
}
/* A moldura vai na classe BASE — todas as células REAIS do mês ficam com contorno. Sem raio e sem
   espaço entre células: a 32 colunas isso é ruído, não moldura, e a tabela já herda o
   `border-collapse: collapse` da `.tabela`.
   ⚠️ Classe SOZINHA (0,1,0), e é obrigatório: subi-la a `.mapa-ano-tabela td.mapa-ano-cel` (0,2,1)
   para bater a `.tabela td` fazia o `background: var(--paper)` desta regra ganhar ao
   `.mapa-ano-fds` e ao `.mapa-ano-feriado`, que são classes simples — e o mapa inteiro saía
   branco, sem fim de semana nem feriado. Medido: a célula de 15/08 (sábado feriado) devolvia
   `rgb(255, 255, 255)`. As arestas que a `.tabela` estraga corrigem-se na regra própria mais
   abaixo, que só mexe em `border-bottom` e por isso não pode arrastar fundos atrás dela. */
.mapa-ano-cel {
  width: 28px; min-width: 28px; min-height: 34px; vertical-align: top;
  background: var(--paper); border: 1px solid var(--line);
}
/* AN3 — dias que NÃO EXISTEM. ⚠️ `border: none` NÃO chega, e não é teoria: com `border-collapse:
   collapse` cada aresta é PARTILHADA pelas duas células, e a resolução começa por escolher a mais
   LARGA — `none` conta como largura zero e perde sempre para a borda de 1px da célula real
   vizinha, que passa a pintar-se também deste lado, como um fantasma. `border-color: transparent`
   mantém a LARGURA e tira só a cor: as duas arestas ficam com a mesma largura e o mesmo estilo, e
   o desempate desce ao critério seguinte (a cor da célula mais acima/à esquerda), que é a célula
   REAL do dia 28/29/30 — o único sítio onde ainda se quer ver linha, porque é ela que fecha o mês.
   Medido em Chromium (`As_celulas_de_dias_inexistentes_nao_deixam_fantasma_no_vizinho`): com esta
   linha, as 10 células «fora» do ano dão `borderTopWidth` de 1px; trocando-a por `border: none`,
   dão 0px — ou seja, a célula deixa de ter aresta própria para empatar com a do vizinho. */
.mapa-ano-fora { background: transparent; border-color: transparent; }
/* ⚠️ As DUAS arestas de baixo que a `.tabela` empresta, corrigidas de uma vez — e é uma correção,
   não arrumação. A `.tabela td` escreve `border-bottom: 1px solid #f0eee5` (0,1,1) e a
   `.tabela tbody tr:last-child td` escreve `border-bottom: none` (0,2,3); as duas batem as classes
   simples de cima, que são (0,1,0). Medido em Chromium, sem estas duas linhas: as arestas
   HORIZONTAIS da grelha saíam a `rgb(240, 238, 229)` e as verticais a `rgb(230, 227, 217)` (dois
   tons na mesma moldura), e a última linha — março da antevisão — ficava com `0px` em baixo, ou
   seja a grelha aberta. Guardado pelo `A_grelha_fecha_se_em_baixo_e_as_arestas_sao_da_mesma_cor`.
   Só se mexe em `border-bottom`: um seletor mais específico que arrastasse `background` atrás de
   si voltava a apagar o fim de semana e o feriado (é o acidente que a regra da `.mapa-ano-cel`
   documenta). A `tr.mapa-ano-linha` está aqui pela especificidade — 3 classes contra 2 — e não
   por gosto: sem ela isto empatava com a regra da `.tabela` e ficava a depender da ordem no
   ficheiro. */
.mapa-ano-tabela tbody tr.mapa-ano-linha td.mapa-ano-cel {
  border-bottom: 1px solid var(--line);
}
.mapa-ano-tabela tbody tr.mapa-ano-linha td.mapa-ano-fora { border-bottom-color: transparent; }
/* AN4 — o fim de semana. ⚠️ `var(--line)`, e NÃO o `color-mix(--cream 80%, --paper)` que veio do
   mockup: é a decisão A13, e a razão é que a Anual não tem a segunda pista que as outras vistas
   têm. Na «Por dia» a mesma tinta funciona porque lá as colunas de sábado e domingo são
   COMPRIMIDAS (`repeat(5, minmax(0, 1fr)) 34px 34px`, secção da `.mapa-dia-*`) e é a compressão
   que diz «isto é fim de semana»; aqui as 31 colunas têm todas 28px e a tinta é a única pista que
   resta. MEDIDO (Chromium, células reais da grelha, `As_tres_tintas_de_dia_da_grelha_…`): com o
   `color-mix` do mockup o fim de semana estava a **1,052:1** do dia útil, ou seja pista nenhuma;
   com `--line` está a **1,284:1**. O chão decidido na A13 é 1,20:1.
   ⚠️ É a MESMA tinta que as outras duas células de fim de semana desta app já usam — a `.mapa-fds`
   (grelha «Por pessoa», nesta mesma página) e a `.ano-fds` (faixa anual do 3c). As três classes
   continuam separadas porque as geometrias são: aquelas duas vivem em grelhas de células
   SEPARADAS (`border-collapse: separate; border-spacing: 1px` na `.mapa-equipa`, `gap: 1px` na
   `.ano-lista-barra`) e esta vive numa grelha de bordas COLAPSADAS — ver o parágrafo seguinte.
   ⚠️⚠️ SEM o `radial-gradient` de pontos da `.mapa-fds`, e é decisão, não esquecimento. Aquele
   gradiente não tem `background-size`, logo pinta UM ponto (raio 1px cheio, transparente a 1,5px)
   no centro EXATO da célula — textura legível num quadrado de 22×22px visualmente vazio (a
   `.mapa-cel`, cujo único conteúdo é um `<span class="sr-only">`, ver `MapaEquipa.cshtml:387`),
   ruído numa célula de 28×34px cujo centro está OCUPADO pela coluna de siglas de 9,5px (até oito,
   no dia mais cheio deste cenário). O ponto passaria de ~1% da área da célula (484px²) para ~0,5%
   (952px²) e ainda por cima cairia por trás de texto: perde nos dois sentidos. Aqui o canal não cromático que a D8 pede é o
   próprio bloco de 56px que o par sábado+domingo forma — ver já a seguir.
   ⚠️⚠️⚠️ E o preço, medido e assumido: `--line` é TAMBÉM a cor da moldura da `.mapa-ano-cel`, por
   isso a aresta INTERNA de um fim de semana (sábado|domingo, as duas células cheias da cor da
   própria borda) fica a **1,000:1** — desaparece. As arestas EXTERNAS do par (sexta|sábado e
   domingo|segunda) ficam nos mesmos 1,284:1 contra o branco do dia útil, ou seja o bloco continua
   a ter limites exatos, e cada dia continua endereçável pelo número que o `<thead>` lhe põe por
   cima (a coluna é fixa em 28px). Ler um fim de semana como UM bloco é a leitura que se quer numa
   grelha de 465 quadrados, e é a mesma linguagem que a `.mapa-ano-fora` já usa (região fundida =
   «aqui não há dia»). Os dois números saem do `As_tres_tintas_de_dia_da_grelha_…`, que IMPRIME o
   da aresta interna (é um preço assumido, não um invariante — quem o quiser de volta não deve
   encontrar um teste vermelho pelo caminho) e ASSEGURA o da externa (esse sim: sem ele o bloco
   deixa de ter limites).
   A alternativa — escurecer a tinta até a moldura se voltar a ver — CALCULADO, não medido em
   Chromium: só paga a partir de ~`color-mix(--line 85%, --muted)`, e aí o fim de semana ficaria a
   ~1,55:1 do branco, mais pesado do que qualquer outro fundo desta paleta. */
.mapa-ano-fds { background: var(--line); }
/* ⚠️ Vem DEPOIS da `.mapa-ano-fds` e empata com ela em especificidade (0,1,0): é a ordem no
   ficheiro que decide, e é ela que faz um feriado ao sábado — a célula que tem as duas classes —
   ler-se como feriado. Trocar as duas linhas de sítio muda o que se vê sem mudar uma classe.
   ⚠️⚠️ A MEDIDA DESTES DOIS PARES É ΔE2000, NÃO CONTRASTE WCAG (decisão A14), e o chão é 10.
   O contraste 2.x é um quociente de LUMINÂNCIAS, e por isso é cego ao matiz: não distingue este
   dourado quente de um cinzento da mesma claridade. A aritmética que o mostra: com o fim de
   semana a 1,284:1 do branco, QUALQUER tinta que fique ENTRE os dois não pode estar a 1,20:1 dos
   dois ao mesmo tempo (1,20 × 1,20 = 1,44 > 1,284) — cumprir o chão de luminância obrigaria o
   feriado a ser mais ESCURO do que o fim de semana, o que inverte o significado (um feriado não
   é um fim de semana reforçado). O par NEUTRO — dia útil contra fim de semana, dois cinzentos —
   continua a medir-se por luminância, com o chão de 1,20:1 da A13: aí não há matiz nenhum a
   contar e a luminância é a medida honesta.
   ⚠️⚠️⚠️ MEDIDO nas células reais, com a ΔE2000 verificada contra os pares publicados de Sharma,
   Wu & Dalal (`MedidorDePixeisTests`) ANTES de julgar seja o que for — uma fórmula de ΔE mal
   transcrita dá números plausíveis e errados:
     gold 18% (o valor do mockup)  ΔE ao dia útil  7,16   ΔE ao fim de semana  3,24   ✖ os dois
     gold 48% (o que está escrito) ΔE ao dia útil 16,47   ΔE ao fim de semana 10,15   ✔ os dois
   48% é o MÍNIMO que passa a barra (47% dá 9,99 ao fim de semana), e o MATIZ nÃO se tocou —
   `--gold` é decisão de marca. Em luminância estes dois pares passam de 1,147/1,120 para
   1,447/1,127; são números informativos, não o critério.
   ⚠️⚠️⚠️⚠️ E não destoa: é a tinta de feriado MAIS CLARA desta app, não a mais forte. A
   `.ano-feriado` (faixa anual do 3c) e a `.mapa-feriado` (grelha «Por pessoa», nesta mesma
   página) são `--gold-deep 45%` sobre transparente, que compõe rgb(202, 189, 159) — ΔE 19,07 ao
   branco, contra os 16,47 desta. O que este bloco faz é aproximar-se do que a casa já usa, não
   inventar um dourado novo. Guardado pelo `As_tres_tintas_de_dia_da_grelha_…`. */
.mapa-ano-feriado { background: color-mix(in srgb, var(--gold) 48%, var(--paper)); }
.mapa-ano-hoje { box-shadow: inset 0 0 0 2px var(--cyan-deep); }
/* AN2 — a aresta entre dezembro e a antevisão. Vai na linha de JANEIRO (borda de topo) e não no
   fundo de dezembro: com bordas colapsadas são a mesma aresta, e escrevê-la dos dois lados é a
   disputa da `.mapa-ano-fora` outra vez. */
.mapa-ano-separador th, .mapa-ano-separador td { border-top: 2px solid var(--ocean); }
/* ⚠️ Codex r2 (P3): a mão e o anel de hover pedem a classe `-com-painel`, que o `mapa-equipa.js`
   põe na célula quando lhe dá o `role="button"`. A `-ativa` é do SERVIDOR e diz só «este dia tem
   gente»; sem JS a célula não abre nada, e um cursor de mão por cima de uma coisa inerte promete
   um clique que não acontece — é a mesma promessa falsa do botão servido, na tinta em vez do
   markup. Quem vê é quem paga: sem leitor de ecrã, o ponteiro é o único sinal de que algo é
   clicável. */
.mapa-ano-cel-ativa.mapa-ano-com-painel { cursor: pointer; }
/* ⚠️ OUTLINE e não `box-shadow`, e é a correção de um defeito REAL (A15). Enquanto os dois
   anéis desta grelha viviam na MESMA propriedade, o de hoje perdia-se: `.mapa-ano-cel-ativa:hover`
   (0,2,0) bate a `.mapa-ano-hoje` (0,1,0), por isso pairar sobre o dia de hoje TROCAVA o anel de
   2px `--cyan-deep` por um de 1px `--cyan-soft` — a marca de hoje desaparecia exatamente quando se
   estava a olhar para ela, e a teclado acontecia o mesmo pelo `:focus-visible`.
   ⚠️⚠️ Corrigido pela PROPRIEDADE e não pela especificidade, de propósito. Um
   `.mapa-ano-hoje.mapa-ano-cel-ativa:hover` resolvia este par e só este par: os estados desta
   célula são de naturezas diferentes — hoje é IDENTIDADE (que dia é este) e o hover/foco é
   TRANSIENTE (onde está o ponteiro) — e uma regra por par cresce ao quadrado dos estados. Em
   propriedades separadas nenhum dos dois pode apagar o outro, agora ou quando alguém acrescentar
   um terceiro.
   ⚠️⚠️⚠️ `outline-offset: -1px` põe o anel EXATAMENTE onde o `inset 0 0 0 1px` o punha (o
   contorno passa a desenhar-se por dentro da caixa), por isso nada se move e nada transborda para
   as células vizinhas — que era a razão de o `inset` ter sido escolhido numa grelha de 31 colunas
   coladas. E o `outline: none` que aqui estava desapareceu porque deixou de fazer sentido: o
   contorno do `:focus-visible` passou a ser este, desenhado, em vez de suprimido.
   MEDIDO com o rato em cima do dia de hoje — `O_anel_de_hoje_sobrevive_ao_rato_e_ao_foco`. */
.mapa-ano-cel-ativa.mapa-ano-com-painel:hover,
.mapa-ano-cel-ativa.mapa-ano-com-painel:focus-visible {
  outline: 1px solid var(--cyan-soft); outline-offset: -1px;
}
/* AN6 — sem teto. Coluna, nunca `flex-wrap`: é o empilhamento vertical que impede a sigla de
   transbordar dos 28px da célula.
   AN8 — o `color: var(--ink)` é tinta NORMAL, nunca a cor do motivo: a 9,5px a cor não tem
   contraste que se leia. */
.mapa-ano-siglas {
  display: flex; flex-direction: column; gap: 1px; list-style: none; margin: 0; padding: 0;
  font-family: var(--font-mono); font-size: 9.5px; line-height: 1.2; color: var(--ink);
}
/* ⚠️ A `.mapa-ano-sigla` NÃO tem `cursor` próprio, e é uma correção: teve `cursor: help` desde a
   task 6, quando a célula ainda não abria nada e o `title` de cada sigla era o único canal do nome.
   A task 7 tornou a célula ativável (`.mapa-ano-cel-ativa { cursor: pointer }`) e os dois passaram
   a disputar o MESMO alvo — numa célula de 28px quase toda ocupada pelas siglas, quem ganhava era o
   `help`, o mais específico dos dois em profundidade: o ponteiro prometia um tooltip por cima de um
   quadrado que abre um painel. E a `<li>` só existe DENTRO de uma célula ativável (a célula vazia
   não desenha `<ul>` nenhuma), por isso o `help` nunca chegou a estar certo depois da task 7.
   Sem regra, o `pointer` da célula herda-se até à sigla — uma escrita só, na célula, que é onde o
   clique é tratado. Medido pelo `O_ponteiro_da_celula_e_o_mesmo_por_cima_da_sigla`. */
/* ── Legenda ── A forma (linha, espaçamento, tipografia, lado da amostra) vem toda da `.legenda`
   partilhada — ver a secção «A forma comum das legendas (A6)». Aqui fica só o CONTORNO, e é a
   mesma solução, pela mesma razão, que o PR 3c teve de escrever para a `.ano-amostra`.
   ⚠️ Depois da A13 quem PRECISA do contorno é a amostra do «DIA ÚTIL», e é ela que o justifica
   sozinha: o fundo dela é `--paper`, o mesmo do cartão por baixo — **1,000:1**, invisível sem
   contorno. Com o contorno de `--line` a aresta fica a **1,284:1**. (Antes da A13 quem estava
   assim era a do fim de semana, a 1,052:1; agora o fundo dela é `--line` e separa-se do cartão
   pelos mesmos 1,284:1 — a mesma razão pela qual o PR 3c escreveu a `.ano-amostra`.) O contorno é
   este e não outro porque é EXATAMENTE o que a célula da grelha tem (`.mapa-ano-cel`): uma amostra
   com um contorno que a grelha não tem mentia sobre o que se vê. Guardado pelo
   `A_legenda_repete_as_tintas_da_grelha_e_o_dia_util_separa_se_pelo_contorno`, que compara as três
   amostras contra as três CÉLULAS, uma a uma.
   ⚠️⚠️ O contorno vai na `.mapa-ano-amostra` — as TRÊS amostras, não só a do fim de semana — e a
   `.mapa-ano-normal` fica só com o fundo. Escrever a borda também na `.mapa-ano-normal` (que é a
   amostra do «dia útil», e é a única que tinha razão para a ter sozinha) era uma segunda cópia do
   mesmo valor à espera de divergir; e as três amostras representam três células que na grelha têm
   todas o mesmo contorno.
   ⚠️⚠️⚠️ Depois da A13 a amostra do fim de semana fica com o fundo E o contorno em `--line`, ou
   seja um quadrado liso — e isso É o que a grelha mostra (a célula de fim de semana também tem a
   moldura da cor do próprio fundo). A legenda continua a dizer a verdade porque repete a tinta da
   célula, não porque escolha uma parecida. */
.mapa-ano-amostra { border: 1px solid var(--line); }
/* O «dia útil» não tem cor própria — a amostra reaproveita o fundo da célula, para a legenda dizer
   a verdade sobre o que se vê. O contorno vem da regra de cima. */
.mapa-ano-normal { background: var(--paper); }
.mapa-ano-legenda-nota { color: var(--muted); font-size: 11.5px; }

/* ── Escala do lab (consulta) ──
   Vista «minha»: passou a calendário (PR 2, VC4) — a MESMA grelha `.escala-mes*` da vista «Mês»,
   secção 2 aqui em baixo. A pastilha de estado (`.minha-estado*`) fica junto dela, depois da
   secção 2.
   ⚠️ Morreu aqui a lista vertical (`.escala-lista`, `.escala-dia`, `.escala-data`,
   `.escala-dia-hoje`, `.escala-fds .escala-estado`): sem consumidor nenhum depois da grelha
   substituir as duas colunas de texto — grep feito antes de apagar (Step 1 da tarefa), `.escala-fds`
   e `.escala-estado` não tinham outra regra nem outro ficheiro a usá-los.
   `.escala-observacao`/`.escala-rodape` FICAM — continuam escritas pelas duas vistas de calendário
   («Mês» e «A minha»), notas secundárias discretas, no --muted, menores que o texto normal. */
.escala-observacao, .escala-rodape { font-size: 12px; color: var(--muted); margin: 8px 0 0; }

/* ─────────────────────────────────────────────────────────────────────────
   2. ESCALA DO LABORATÓRIO — vista MÊS (a grelha do Power BI)
   ───────────────────────────────────────────────────────────────────────── */

.escala-mes {
  --escala-mes-borda: 1px solid var(--line);
  container-type: inline-size;
  margin: 16px 0 0;
  border: var(--escala-mes-borda);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.escala-mes-grelha {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  background: var(--line);
  gap: 1px;
}
.escala-mes-cabeca {
  padding: 8px 10px;
  background: var(--sand);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--muted);
  text-align: center;
}
.escala-mes-dia {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-height: 132px;
  padding: 8px 9px 10px;
  background: var(--paper);
  font-size: 12px;
}
/* Os dias do mês vizinho ficam à vista, apagados: uma primeira semana com cinco
   caixas brancas vazias lia-se como escala em falta, e não como «este mês
   começa ao sábado».
   ⚠️ A classe do delta era `.vazio` e passou a `.mes-vizinho` — DIVERGÊNCIA DELIBERADA.
   O `site.css` tem um `.vazio` GLOBAL (o estado vazio de uma página: `text-align:
   center; padding: 32px 20px`) com a mesma especificidade que esta regra; as células
   casavam com as duas e safavam-se só pela ordem no ficheiro. Reordenar as secções
   dava 32px de padding a 11 células e mudava a altura da grelha inteira. Não é
   hipótese: a spec regista o mesmo acidente no editor, onde uma célula chamada
   `vazio` apanhou a da página, as linhas foram a 65px e foi preciso renomear para
   `sem-plano`.
   ⚠️⚠️ A cor do número era `#a8adb8`, que sobre `--cream` mede 2,12:1 — a revisão
   mediu 1,93:1, e o que ambas as contas dizem é o mesmo: muito abaixo dos 4,5:1 que
   o plano exige para texto. E a ironia era exatamente esta: os números estão aqui
   para SEREM LIDOS (é o defeito de cima), e uma cor que os apaga desfaz a razão de
   eles existirem. Passa a `--muted`, o token mais claro da paleta que ainda cumpre
   nesta superfície: 5,77:1 sobre `--cream` (medido, não estimado).
   ⚠️⚠️⚠️ Fica IGUAL ao número de um domingo (`.inerte`, mais abaixo), e é assim de
   propósito: os dois comentários dizem a mesma coisa ao leitor — «este dia não é para
   preencher, salta-o». Distinguir pelo fundo foi medido e rejeitado: o único token
   mais escuro que `--cream` é o `--sand`, que é o fundo dos CABEÇALHOS da grelha —
   as cinco células vizinhas da primeira linha ficavam coladas à fila dos dias da
   semana, num bloco só. O que separa mesmo os dois casos é o conteúdo (um domingo
   pode ter turnos e conta; uma célula vizinha nunca tem nada). */
.escala-mes-dia.mes-vizinho { background: var(--cream); }
.escala-mes-dia.mes-vizinho .escala-mes-numero { color: var(--muted); font-weight: 400; }
/* ⚠️ Era `#fbfaf4`, fora da paleta. Esta mistura dá #fbf9f4 — o mesmo pixel a menos
   de uma unidade por canal, agora amarrado aos tokens. */
.escala-mes-dia.fds { background: color-mix(in srgb, var(--cream) 80%, var(--paper)); }
/* ⚠️ Era `rgba(202, 168, 90, 0.13)` — o valor É o `--gold`, com 13% de alfa, e a
   intenção era um véu de ouro sobre o PAPEL. Só que a `.escala-mes-grelha` aqui em
   cima tem `background: var(--line)` (é o que preenche o `gap: 1px` entre células), e
   o `background` (atalho) desta regra APAGA o `var(--paper)` da `.escala-mes-dia` —
   os 13% acabavam a compor sobre o cinzento da grelha, não sobre branco. Medido em
   Chromium: dava #e2dbc8, um caqui sujo, e não o #f8f4ea desenhado. Opaco, o véu
   volta a ser o que era, e a cor sai da paleta em vez de um rgba solto. */
.escala-mes-dia.feriado { background: color-mix(in srgb, var(--gold) 13%, var(--paper)); }

.escala-mes-numero {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
/* ⚠️ O anel era `var(--cyan)`, que sobre `--paper` mede 2,26:1 — abaixo dos 3:1 que a
   WCAG 1.4.11 exige a um LIMITE DE COMPONENTE, e o anel é exatamente isso. Medido em
   Chromium com a faixa de 6px rente à aresta de cima da célula (Tarefa 9), não estimado.
   Passa a `--cyan-deep`, que já é o token do número deste mesmo dia (a linha a seguir):
   5,48:1 sobre `--paper` e 4,95:1 sobre o véu âmbar da falha de cobertura. Sem token novo.
   ⚠️⚠️ E engrossar o anel NÃO resolvia: a espessura não muda a razão de contraste. Por isso
   o «hoje» ganha também um SEGUNDO CANAL — o `.sr-only` com «Hoje» que o `Index.cshtml`
   escreve dentro do `.escala-mes-numero`. Era o único estado desta secção que dependia só
   da cor: o «eu» tem negrito + ponto, a falha tem ícone + texto, as marcas «fora» têm
   forma própria. As duas metades têm prova em `EscalaVistasTests`. */
.escala-mes-dia.hoje { box-shadow: inset 0 0 0 2px var(--cyan-deep); }
.escala-mes-dia.hoje .escala-mes-numero { color: var(--cyan-deep); }
/* ⚠️ A cor era `--gold-deep` puro, que a 10px/500 (não é texto grande) media 4,44:1
   sobre o fundo de feriado e 4,41:1 sobre o de falha de cobertura — abaixo dos 4,5:1.
   Escurecida com `--ink`, sem sair da paleta nem da família do ouro: 5,47:1 sobre o
   feriado, 5,43:1 sobre a falha, 6,01:1 sobre `--paper` (medido). */
.escala-mes-etiqueta {
  font-family: var(--font-sans);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--gold-deep) 85%, var(--ink));
}

/* A pergunta operacional de um dia é «quantos estão lá?». Fica no canto do
   número, em mono, e vira âmbar quando não chega à regra publicada. */
.escala-mes-conta {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.escala-mes-dia.falha-cobertura .escala-mes-conta { color: var(--status-warning); font-weight: 700; }

/* Domingo sem cobertura exigida não é um dia por preencher — é um dia que não
   existe na escala. Fica inerte para o olho o saltar. */
.escala-mes-dia.inerte { background: var(--cream); }
.escala-mes-dia.inerte .escala-mes-numero { color: var(--muted); font-weight: 400; }

/* Um turno = uma linha «hora + iniciais». A hora é a âncora de leitura, escrita
   por extenso na pastilha — é por isso que a cor já não muda por hora aqui (A10):
   colorir por posição repetia a mesma informação que o número já dava. A pastilha
   usa a cor de ESTADO única (`--turno-cor` sem classe `turno-N`, o recuo desta
   regra): «trabalho» é um estado como folga/falta/férias, não uma cor por hora. */
.escala-turno { display: flex; gap: 6px; align-items: baseline; line-height: 1.45; }
.escala-turno-hora {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  color: var(--turno-cor, var(--cyan-deep));
}
/* ⚠️ Já cá esteve um ::before de 6px com var(--turno-cor) antes da hora — a MESMA cor que o texto
   da hora já tem, ou seja, informação repetida a gastar largura na célula mais apertada da app.
   Saiu na ronda pós-agosto (pedido do Bruno); quem guarda a ausência é o
   EscalaVistasTests.A_hora_do_turno_nao_desenha_marca_nenhuma_antes_do_numero. */
.escala-turno-gente { min-width: 0; color: var(--ink); }

/* ⚠️ As três primeiras têm de ser de FAMÍLIAS diferentes, não tons da mesma.
   A primeira tentativa era ocean → cyan-deep → gold: no plano publicado, com a
   cor a 16% sobre branco, o 07:00 e o 08:00 liam-se como a mesma mancha azul —
   apanhado na renderização. Azul → verde → dourado separam-se à distância a que
   esta grelha é lida. O verde não colide com nada nesta vista (as férias são
   azul cheio e a ausência são riscas roxas) e a hora continua escrita na
   célula: a cor acelera, nunca é o único canal.
   ⚠️⚠️ As seis vinham como hexadecimais literais, e os seis valores JÁ ERAM da paleta
   — só tinham perdido a ligação ao token. Ficam pelos tokens, com o mesmo pixel:
   #015e82=--ocean, #186c46=--status-success, #0e7480=--cyan-deep,
   #51586a=--status-neutral, #4a3d6b=--plum-deep.
   ⚠️⚠️⚠️ A terceira é a ÚNICA que muda de valor, e pela mesma razão da
   `.escala-mes-etiqueta` aqui em cima: `--gold-deep` puro, a 11px/600, media 4,44:1
   sobre o fundo de feriado e 4,41:1 sobre o de falha de cobertura — e é a HORA, que é
   texto a ler, não só a pastilha. Escurecida com `--ink` na mesma proporção da
   etiqueta (as duas eram a mesma cor, e continuam a ser a mesma): 5,47:1 / 5,43:1 /
   6,01:1 sobre `--paper`. A família do ouro mantém-se, que é o que o aviso de cima
   exige.
   ⚠️⚠️⚠️⚠️ A10 tirou a classe `turno-N` da vista «Mês» — e, num ruling de correção do
   controlador (2026-08-14), da bancada do editor também (`.editor-celula.trab-fora`
   deixou de a levar; ver o comentário da regra, mais abaixo). NÃO se apaga esta regra:
   `grep -rn "turno-[1-6]"` ainda encontra dois consumidores vivos — o resumo «A minha
   semana» do dashboard (`.semana-turno`, `Pages/Index.cshtml`) e a legenda do plano
   publicado (`.plano-cel`, `Escala/Gerir.cshtml`). */
.turno-1 { --turno-cor: var(--ocean); }
.turno-2 { --turno-cor: var(--status-success); }
.turno-3 { --turno-cor: color-mix(in srgb, var(--gold-deep) 85%, var(--ink)); }
.turno-4 { --turno-cor: var(--cyan-deep); }
.turno-5 { --turno-cor: var(--status-neutral); }
.turno-6 { --turno-cor: var(--plum-deep); }

/* Os «fora» ficam por baixo de uma régua e em tom apagado: existem, mas não
   competem com quem está ao serviço. Em linha e com quebra — dois andares fixos
   deixavam buracos nos dias que só têm folgas. */
.escala-mes-fora {
  margin-top: auto;
  padding-top: 5px;
  border-top: 1px dashed var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: 2px 12px;
  font-size: 11px;
  color: var(--muted);
}
.escala-fora-linha { display: flex; gap: 5px; align-items: baseline; }
.escala-fora-marca {
  flex: 0 0 10px;
  width: 10px;
  height: 10px;
  border-radius: 2px;
  transform: translateY(1px);
}
/* Mesmas cores e MESMAS FORMAS do mapa da equipa e da faixa anual.
   ⚠️ A folga é REDONDA e a falta leva risca: em quadrado vazio as duas liam-se
   como caixas de seleção por marcar — apanhado na primeira renderização.
   ⚠️⚠️ A risca da ausência era `#b7addd`, uma cor que não existe na paleta — e o
   «mesmas cores» aqui em cima era falso: o `.mapa-ausencia` e a `.ano-ausencia`
   fazem a risca clara com `color-mix(in srgb, var(--paper) 60%, transparent)` sobre
   `--plum`, o que dá ≈#c4bdd5. Passa a ser a MESMA construção, e agora a frase é
   verdade; só o passo (2px) acompanha os 10px desta marca, como já acontecia entre o
   mapa (3px) e a faixa (2px). */
.escala-fora-marca.folga {
  border-radius: 50%;
  background: var(--paper);
  box-shadow: inset 0 0 0 1.5px var(--status-neutral);
}
.escala-fora-marca.falta {
  background: linear-gradient(135deg, transparent 44%, var(--status-warning) 44% 56%, transparent 56%);
  box-shadow: inset 0 0 0 1.5px var(--status-warning);
}
.escala-fora-marca.ferias { background: var(--ocean); }
.escala-fora-marca.ausencia {
  background-color: var(--plum);
  background-image: repeating-linear-gradient(135deg, transparent 0 2px,
                    color-mix(in srgb, var(--paper) 60%, transparent) 2px 4px);
}

/* A minha pessoa dentro da grelha: negrito + ponto cyan. Nunca só a cor. */
.eu { font-weight: 700; color: var(--ocean-dark); }
.eu::before {
  content: "";
  display: inline-block;
  width: 5px; height: 5px;
  margin-right: 3px;
  border-radius: 50%;
  background: var(--cyan);
  vertical-align: 0.15em;
}

/* Cobertura por cumprir: âmbar, o único alarme da app.
   ⚠️ Mesma correção da `.feriado`: era `rgba(110, 86, 32, 0.07)` — o valor é o
   `--status-warning` a 7% — e, por ser translúcido, compunha sobre o `var(--line)` da
   grelha em vez do papel. Medido: #ded9cc em vez de #f5f3ef, e com ele TODO o texto
   da célula perdia contraste (era o alarme a ficar mais difícil de ler do que os dias
   normais). Opaco, e a partir do token. */
.escala-mes-dia.falha-cobertura {
  background: color-mix(in srgb, var(--status-warning) 7%, var(--paper));
}
.escala-mes-dia.falha-cobertura .escala-mes-numero { color: var(--status-warning); }
.escala-aviso-cobertura {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10px;
  font-weight: 600;
  color: var(--status-warning);
}

/* Ecrã estreito: o calendário de 7 colunas vira lista de dias. */
@container (max-width: 780px) {
  .escala-mes-grelha { grid-template-columns: 1fr; }
  .escala-mes-cabeca { display: none; }
  .escala-mes-dia { min-height: 0; }
  .escala-mes-dia.mes-vizinho { display: none; }
}

/* ─────────────────────────────────────────────────────────────────────────
   2a. ESCALA — o PAINEL DE DETALHE do dia (vista «Mês», VC3 + VC12)
   ─────────────────────────────────────────────────────────────────────────
   Pensado para o telemóvel, onde as siglas da grelha (AB, CD…) ficam pequenas demais.
   NADA aqui inventa linguagem visual nova: as cores, as formas e os tempos saem todos de
   classes e tokens que já existem (`.escala-fora-marca`, `--cyan-deep`, `--paper`, `--line`,
   `--shadow-md`, `--radius-md`, `--transition-base`) — só se ligam a um clique.

   ⚠️ OS NOMES SAÍRAM DA FAMÍLIA `.dia-*` do mockup, e é a decisão mais importante desta secção:
   `.dia-*` é o espaço de nomes da vista «Por dia» (`.dia-veredicto`, `.dia-coluna`, `.dia-pessoa`,
   `.dia-fora`, `.dia-medida`, na secção 3 aqui abaixo). Pôr o painel da vista «Mês» lá dentro
   misturava duas vistas na mesma família — e a regra das colisões já foi paga quatro vezes nesta
   app, duas delas nesta secção (o `.vazio` que teve de virar `.mes-vizinho`, e o fundo translúcido
   que compunha sobre o `var(--line)` da grelha).
   Grep de colisão corrido no ficheiro INTEIRO antes de escrever, composto ou não: `escala-dia-painel`,
   `escala-mes-clicavel`, `escala-mes-selecionado` e cada sufixo (`-cabeca`, `-titulo`, `-fechar`,
   `-corpo`, `-secao`, `-secao-titulo`, `-linha`, `-hora`) — 0 ocorrências de cada. O `.aberto`
   também: as 8 ocorrências da palavra no ficheiro são todas de comentários, não há seletor.

   O `display: none !important` no `@media print` (Step 2 da Task 7, VC10) vive no bloco `@media
   print` global, mais abaixo no ficheiro, junto às outras regras de impressão por componente —
   não aqui, para não abrir um segundo `@media print` só para esta classe. */
.escala-mes-clicavel { cursor: pointer; }
/* ⚠️ O `:not(.hoje)` não é ruído: o `.escala-mes-dia.hoje` (mais acima) desenha o seu anel com
   `box-shadow: inset`, e as duas regras empatam em especificidade (0-2-0) — sem a exclusão, esta,
   por vir depois no ficheiro, APAGAVA o anel do dia de hoje enquanto o rato lá estivesse. O
   `box-shadow` é uma propriedade só e não se soma entre regras. Num dia que já traz um anel mais
   forte, o `cursor: pointer` chega como afordância; medido pelo
   `EscalaPainelDiaTests.O_anel_do_hoje_sobrevive_ao_rato_sobre_a_celula_clicavel`. */
/* ⚠️ ESTAS DUAS VÊM ANTES DA DO `:hover` DE PROPÓSITO. O `:focus-visible` GLOBAL (topo do ficheiro)
   escreve `box-shadow: var(--shadow-ring)` + `border-radius: 4px` — o halo pensado para botões e
   campos. Nenhuma das duas propriedades era disputada aqui, e a cascata aplicava-as: uma célula
   focada pelo teclado ficava com o anel de baixo E o halo desfocado por cima. As dez outras regras
   `:focus-visible` deste ficheiro neutralizam sempre uma das duas; esta era a única que não.
     · O `:not(.hoje)` do `box-shadow` é obrigatório: o anel do «hoje» também é um `box-shadow`
       (`.escala-mes-dia.hoje`, mais acima) e empata em especificidade (0-2-0) com
       `.escala-mes-clicavel:focus-visible` — sem a exclusão, focar o dia de hoje pelo teclado
       APAGAVA-LHE o anel. É o espelho exato do empate que a regra do `:hover` aqui em baixo resolve.
     · E ficam ANTES do `:hover` (mesma especificidade, 0-3-0, decide a ordem) para que uma célula
       focada E sob o rato continue a mostrar a afordância do rato.
   ⚠️⚠️ O `border-radius: 0` é uma DECISÃO tomada, não uma limpeza: a célula é um retângulo rente ao
   `gap: 1px` da grelha (que é o `background: var(--line)` a passar entre células), e arredondá-la só
   ao focar fazia aparecer quatro cantos cinzentos nessa célula e em mais nenhuma. Fica quadrada, e
   fica ESCRITO — herdar 4px por acidente não é a mesma coisa que os querer. */
.escala-mes-clicavel:not(.hoje):focus-visible { box-shadow: none; }
.escala-mes-clicavel:focus-visible { border-radius: 0; }
.escala-mes-clicavel:not(.hoje):hover { box-shadow: inset 0 0 0 1px var(--cyan-soft); }
.escala-mes-clicavel:focus-visible { outline: 2px solid var(--cyan-deep); outline-offset: 2px; }
/* ⚠️ `outline`, e NÃO `box-shadow`, pela mesma razão em espelho: o mesmo dia pode ser HOJE e estar
   SELECIONADO ao mesmo tempo, e o `outline` é uma propriedade diferente do `box-shadow` do `.hoje`
   — os dois canais não se apagam um ao outro.
   ⚠️ Mas o foco e a SELEÇÃO não coexistem entre si: as duas regras escrevem a MESMA propriedade
   (`outline`) e empatam em especificidade (0-2-0); `.escala-mes-dia.escala-mes-selecionado` (abaixo)
   vem DEPOIS neste ficheiro, por isso GANHA — numa célula focada E selecionada só se vê o anel de
   seleção (`3px`, `outline-offset: -2px`), o anel de foco (`2px`, `outline-offset: 2px`) desaparece
   por completo. O sinal oposto do `outline-offset` não é para os distinguir quando coincidem (não
   coincidem: um apaga o outro) — só faz o anel de foco ficar por FORA da célula e o de seleção por
   DENTRO quando aparecem sozinhos. Na prática quase não se nota, porque o `abrirPainel` (JS) move o
   foco para o botão de fechar assim que o painel abre — a janela em que uma célula fica focada E
   selecionada ao mesmo tempo é curta.
   Custo aceite à parte: a `.escala-mes` tem `overflow: hidden` e a grelha fica rente à borda da
   caixa, por isso nas células da primeira/última coluna e das linhas de topo/fundo o segmento
   exterior do anel de foco fica cortado (não é regressão de acessibilidade — o foco continua
   visível pelos outros lados da célula; ver known-followups.md). */
.escala-mes-dia.escala-mes-selecionado {
  outline: 3px solid var(--cyan-deep);
  outline-offset: -2px;
  position: relative;
  z-index: 1;
}

/* A gaveta. Encostada ao fundo e por cima de tudo — nasce fora do ecrã e desliza para dentro.
   ⚠️ A transição é apanhada pelo bloco global de `prefers-reduced-motion`; não se escreve regra
   própria aqui. */
.escala-dia-painel {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 200;
  background: var(--paper);
  border-top: 1px solid var(--line);
  box-shadow: var(--shadow-md);
  border-radius: var(--radius-md) var(--radius-md) 0 0;
  /* O `env(safe-area-inset-bottom)` é o que impede a última linha de cair debaixo da barra de
     gestos do telemóvel — que é o ecrã para que este painel foi desenhado. */
  padding: 16px 20px calc(16px + env(safe-area-inset-bottom, 0px));
  max-height: 46vh;
  overflow-y: auto;
  transform: translateY(100%);
  transition: transform var(--transition-base);
}
.escala-dia-painel.aberto { transform: translateY(0); }
.escala-dia-painel-cabeca {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}
.escala-dia-painel-titulo {
  font-family: var(--font-serif);
  font-size: 17px;
  color: var(--ocean);
  margin: 0;
}
.escala-dia-painel-fechar {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--paper);
  color: var(--muted);
  cursor: pointer;
}
.escala-dia-painel-fechar:hover { color: var(--ink); background: var(--sand); }
.escala-dia-painel-fechar svg { width: 14px; height: 14px; }
.escala-dia-painel-corpo {
  margin-top: 10px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* `.escala-dia-painel-secao` não leva regra nenhuma de propósito: é um embrulho ESTRUTURAL, e
   existe só para o `gap: 10px` do `-corpo` separar as duas SECÇÕES («Turnos» e «Fora») em vez de
   separar todas as linhas. Quem espaça as linhas é o `margin` da própria linha. */
.escala-dia-painel-secao-titulo {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 4px;
}
.escala-dia-painel-linha {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 13px;
  margin: 0 0 3px;
}
/* ⚠️ NÃO se reescreve aqui a `.escala-fora-marca`. O mockup repetia-lhe as medidas
   (`flex: 0 0 10px; width/height: 10px; border-radius: 2px`) dentro do painel — mas a regra base
   (secção 2) já traz exatamente essas medidas, e a cópia, por vir DEPOIS da
   `.escala-fora-marca.folga`, repunha-lhe o `border-radius: 2px` e transformava o círculo da folga
   num quadrado. A forma é um canal a sério (em quadrado vazio a folga lê-se como caixa por marcar);
   não se perde por causa de uma duplicação. */
.escala-dia-painel-hora {
  font-family: var(--font-mono);
  font-weight: 700;
  color: var(--cyan-deep);
  flex: 0 0 auto;
}

/* ─────────────────────────────────────────────────────────────────────────
   2b. ESCALA — vista A MINHA (a pastilha de estado, dentro da MESMA grelha da secção 2)
   ───────────────────────────────────────────────────────────────────────── */

/* A REPARTIÇÃO É REGRA, NÃO ARRUMAÇÃO (VC9). `.minha-estado` leva só a COLOCAÇÃO — o mesmo
   `margin-top:auto` + `padding-top:5px` + `border-top:1px dashed var(--line)` do `.escala-mes-fora`
   aqui em cima, para a pastilha cair sempre no mesmo sítio da célula (encostada ao fundo, com a
   régua tracejada). ⚠️ Ronda de correção 1: NÃO é a receita exata — o `font-size` é 12px aqui e
   11px lá (a pastilha é uma linha só, o `.escala-mes-fora` é uma lista que pode ter várias), e só
   a `.minha-estado` leva `overflow-wrap: break-word` (o comentário a seguir explica porquê). As
   `.minha-estado-*` levam só COR, PESO E FAMÍLIA —
   nunca colocação — porque a legenda (mais abaixo) usa-as SOZINHAS, sem `.minha-estado`: um
   modificador BEM órfão do bloco (`.minha-estado--trabalho`) mentiria sobre a própria convenção,
   por isso o nome é um prefixo simples, não BEM.
   ⚠️ `overflow-wrap: break-word`: "Assunção de Nossa Senhora" numa célula de ~140px é o candidato
   exato ao corte silencioso que a app já pagou uma vez no `section.mapa-dia` (`.mapa-dia-nomes`,
   mais acima). */
.minha-estado {
  margin-top: auto;
  padding-top: 5px;
  border-top: 1px dashed var(--line);
  font-size: 12px;
  overflow-wrap: break-word;
}
.minha-estado-trabalho { font-family: var(--font-mono); font-weight: 700; color: var(--cyan-deep); }
/* ⚠️ A cor era `--gold-deep` PURO, e CHUMBOU — como a `.escala-mes-etiqueta` e o `.turno-3` já
   tinham chumbado antes dela, pelo mesmo tom e nas mesmas superfícies. Medido em Chromium com o
   `MedidorDePixeis` (`EscalaMinhaTests.As_cinco_cores_de_estado_leem_se_nos_tres_fundos_de_celula`,
   Task 6 do PR 2), pixel a pixel e não por cálculo sobre os hexadecimais:
   4,64:1 sobre `.fds` e **4,44:1 sobre `.feriado`** — abaixo dos 4,5:1 que a WCAG 1.4.3 exige a
   texto de 12px. É o mesmo 4,44:1 que as duas regras acima registam, o que confirma que era
   exatamente o mesmo defeito.
   Escurecida com `--ink` na MESMA proporção das duas (85/15), sem sair da paleta e sem token novo:
   passa a 5,71:1 sobre `.fds` e 5,47:1 sobre `.feriado` (medido).
   ⚠️ Sobre `--paper` os números — 4,88:1 antes, 6,01:1 depois — são COMPOSTOS e não fotografados,
   e o comentário di-lo porque um valor de composição não pode ficar a fazer de medição: a app não
   desenha um «extra» num dia útil (um extra é sempre domingo ou terceiro sábado). Compõem-se de
   duas luminâncias medidas ao pixel, e o 6,01:1 é, à segunda casa, o mesmo que a
   `.escala-mes-etiqueta` já regista para esta cor sobre este fundo.
   A família do ouro mantém-se — é ela que separa o «extra» do azul do turno normal. */
.minha-estado-extra {
  font-family: var(--font-mono);
  font-weight: 700;
  color: color-mix(in srgb, var(--gold-deep) 85%, var(--ink));
}
.minha-estado-folga { color: var(--muted); }
.minha-estado-falta { font-weight: 600; color: var(--status-warning); }
.minha-estado-ferias { font-weight: 600; color: var(--ocean); }
.minha-estado-sem-plano { color: var(--muted); }

/* ─────────────────────────────────────────────────────────────────────────
   3. ESCALA — vista POR DIA (colunas por horário + bloco «fora»)
   ───────────────────────────────────────────────────────────────────────── */

/* O veredicto da cobertura por cima de tudo: quem abre esta página vem saber se
   o dia está coberto, e antes disto respondia-se a contar nomes em três listas.
   Cada medida traz os DOIS números (o que lá está e o mínimo) — a cor é um
   reforço, nunca o canal. */
.dia-veredicto {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 20px;
  margin: 16px 0 0;
  padding: 12px 16px;
  background: var(--sand);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}
.dia-veredicto-tipo {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--muted);
}
.dia-medida { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; }
.dia-medida strong { font-variant-numeric: tabular-nums; }
.dia-medida.ok { color: var(--status-success); }
.dia-medida.falha { color: var(--status-warning); font-weight: 600; }

/* Uma coluna por horário, e não uma lista por horário: a pergunta é «com quem
   conto às oito?», e a resposta lê-se de uma vez em vez de se contar linhas.
   O `auto-fit` com mínimo de 190px é o que faz as três colunas do dia útil
   virarem uma só no telemóvel, sem media query nem deslize horizontal. */
.dia-colunas {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 1px;
  margin: 14px 0 0;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.dia-coluna { background: var(--paper); padding: 14px 16px 16px; }
.dia-coluna-cabeca {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  padding-bottom: 8px;
  margin-bottom: 10px;
  border-bottom: 2px solid var(--ink);
}
.dia-coluna-hora { font-family: var(--font-mono); font-size: 17px; font-weight: 600; color: var(--ocean); }
.dia-coluna-conta {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.dia-pessoas { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.dia-pessoa { display: flex; align-items: center; gap: 8px; font-size: 14px; }
.dia-inicial {
  flex: 0 0 26px;
  width: 26px; height: 26px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--sand);
  border: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  color: var(--ocean-dark);
}
.dia-pessoa.extra .dia-inicial { background: rgba(22, 190, 207, 0.18); border-color: var(--cyan-soft); }
.dia-etiqueta-extra {
  padding: 1px 6px;
  border-radius: var(--radius-pill);
  background: rgba(22, 190, 207, 0.18);
  color: var(--cyan-deep);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}

/* Quem não está ao serviço fica FORA das colunas, por baixo e em tom apagado:
   existe, mas não conta para a cobertura. O rótulo do estado tem largura mínima
   para os quatro alinharem numa coluna, e leva a MESMA marca do calendário do
   mês (`.escala-fora-marca`) — a folga redonda, a falta com risca. */
.dia-fora { margin: 18px 0 0; }
.dia-fora-titulo {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 8px;
}
.dia-fora-lista { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.dia-fora-item { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; font-size: 14px; }
.dia-fora-estado {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-width: 118px;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
}
.dia-fora-nomes { color: var(--ink); }
.dia-fora-nota { color: var(--muted); font-size: 12px; }

/* ── Configuração da escala ──
   Uma bancada contínua: a régua pessoas + horas é a única peça expressiva; catálogo e equipa
   partilham a mesma superfície e mantêm leitura utilitária. */
.escala-configuracao {
  container-type: inline-size;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--shadow-xs);
}
.escala-config-erros { margin: 18px 20px 0; }
.escala-config-secao { min-width: 0; padding: 24px; }
.escala-config-cabecalho { margin: 0 0 18px; }
.escala-config-cabecalho h3 { color: var(--ocean); font-size: 20px; }
.escala-config-cabecalho p { max-width: 620px; margin: 5px 0 0; color: var(--muted); font-size: 13px; }
.escala-regua { border-top: 1px solid var(--ink); border-bottom: 1px solid var(--ink); }
.escala-regua-linha {
  display: grid;
  grid-template-columns: minmax(90px, 0.7fr) minmax(160px, 1fr) 28px minmax(210px, 1.25fr);
  align-items: center;
  gap: 12px;
  min-height: 58px;
  border-bottom: 1px solid var(--line);
}
.escala-regua-linha:last-child { border-bottom: 0; }
.escala-regua-dia { font-weight: 650; }
.escala-medida { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: 13px; }
.escala-medida input {
  width: 68px;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.escala-regua-soma { color: var(--cyan-deep); font-family: var(--font-mono); font-size: 20px; text-align: center; }
.escala-hora-identidade { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.escala-hora-identidade strong { font-family: var(--font-mono); font-size: 15px; }
.escala-hora-identidade span { color: var(--muted); font-size: 12px; }
.escala-hora-acao { display: grid; grid-template-columns: 1fr auto; gap: 6px 8px; align-items: end; margin-top: 8px; }
.escala-hora-acao label { grid-column: 1 / -1; color: var(--muted); font-size: 12px; }
.escala-hora-acao select { min-width: 0; }
.escala-equipa { display: flex; flex-direction: column; }
.escala-equipa-linha:last-child { border-bottom: 0; }
.escala-equipa-hora { display: flex; flex-direction: column; gap: 4px; color: var(--muted); font-size: 12px; }
.escala-equipa-hora select { font-family: var(--font-mono); }

/* ─────────────────────────────────────────────────────────────────────────
   4. CONFIGURAÇÃO DA ESCALA — fichas da equipa que NÃO transbordam
   ───────────────────────────────────────────────────────────────────────── */

/* ⚠️ Substitui `.escala-config-colunas`: os mínimos somados (280+440) obrigavam
   o cartão a 720px e empurravam os botões para fora.
   ⚠️⚠️ E a ARRUMAÇÃO muda: «Cobertura» e «Horas permitidas» são listas curtas e
   passam a partilhar a linha de cima; a «Equipa» — a lista longa, uma pessoa por
   ficha — fica com a LARGURA TODA. Na primeira renderização a equipa vivia numa
   coluna de ~475px e cada ficha rebentava em três andares (incluir / responsável
   / hora), enquanto a coluna das horas deixava meio metro de branco por baixo. */
/* ⚠️ TRÊS BANDAS de largura total, e não duas colunas.
   Duas tentativas medidas falharam antes desta: a 1fr/1fr a régua da cobertura
   caía nos 420px e partia-se em dois andares; a 1.3fr/0.7fr cabia (607px) mas os
   rótulos «horas diferentes» dobravam e a linha crescia de 58px para 97px. A
   régua precisa de ~560px livres e as fichas da equipa precisam da largura toda
   para alinharem em colunas — nenhuma das duas cabe em meio cartão. */
/* ⚠️ Ronda de correção 1/5: sem `display: grid`, `grid-template-columns` abaixo é inerte — o
   empilhamento das três bandas vem só do fluxo de bloco normal, e uma regressão óbvia
   (`grid-template-columns: 1fr 1fr`) não faria NADA num `display: block`. Declarado
   explicitamente para a guarda ser real: quem reverter para duas colunas parte mesmo o teste do
   transbordo (medido: 108px a 1280px). Hoje é um no-op visual — três `<section>` de bloco sem
   margens dão o mesmo pixel que um grid de uma coluna. */
.escala-config-colunas { display: grid; grid-template-columns: 1fr; }
.escala-config-colunas > .escala-config-secao + .escala-config-secao {
  border-left: 0;                     /* a régua vertical de 2 colunas já não existe; só sobra o traço horizontal a seguir */
  border-top: 1px solid var(--line);
}

/* O catálogo de horas em banda larga: 3 a 6 horas nunca justificaram uma lista
   vertical com meio cartão de branco ao lado. Cada hora é uma ficha. */
/* 🔴 Ronda de correção 1/5: o `site.css` NÃO tem reset global de `<ul>`. Sem estas três
   declarações o catálogo voltava a ter marcadores (`list-style: disc`) e 40px de avanço
   (`padding-left`) — medido em Chromium, 375 a 1680px — com bolinhas a cair dentro do cartão
   anterior e a grelha desalinhada do título "Horas permitidas". */
.escala-catalogo {
  margin: 0; padding: 0; list-style: none;   /* o <ul> não tem reset global neste ficheiro */
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(232px, 1fr));
  gap: 10px;
}
.escala-catalogo > li {
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--paper);
}
.escala-hora-acao { margin-top: 6px; }
/* 🟠 Ronda de correção 1/5 (M3): sem `display: flex`, o `<input type=time>` de "Nova hora"
   esticava pela banda toda (~1000px) com o botão empurrado para baixo — o delta desenhou esta
   secção para uma coluna de ~475px, não para uma banda inteira. Repostos o flex e o limite de
   largura do campo. */
.escala-adicionar-hora {
  display: flex;
  align-items: end;
  gap: 10px;
  margin-top: 12px;
  padding: 10px 12px;
  border: 1px dashed var(--line);
  border-radius: var(--radius-sm);
}
.escala-adicionar-hora .campo { flex: 0 1 220px; margin: 0; }

/* ── Aperto vertical do ecrã inteiro ──
   Eram 24px de padding por secção, 58px por linha da régua e 14px por ficha:
   com 11 pessoas o ecrã pedia duas dobras de scroll para nada. */
.escala-config-secao { padding: 18px 20px 20px; }
.escala-config-cabecalho { margin: 0 0 12px; }
.escala-config-cabecalho h3 { font-size: 18px; }
.escala-config-cabecalho p { margin: 3px 0 0; }
/* ⚠️ O aperto das fichas e da faixa de origem NÃO vive aqui: as regras próprias
   delas estão mais abaixo neste ficheiro e ganhavam por ordem de cascata (medido
   — a ficha ficava nos 71px em vez dos 61px). Estão apertadas na origem. */
.escala-regua-linha { min-height: 46px; }

/* Cada secção é o seu próprio contentor de consulta: as regras abaixo medem a
   COLUNA onde vivem, e não o cartão inteiro. */
.escala-config-secao { container-type: inline-size; }

/* Régua da cobertura em ecrã estreito: as duas medidas empilham em vez de
   espremerem os campos até o «horas diferentes» partir a meio. */
@container (max-width: 520px) {
  .escala-regua-linha {
    grid-template-columns: minmax(80px, 0.9fr) minmax(0, 1fr);
    grid-template-areas: "dia pessoas" ".   horas";
    gap: 6px 10px;
    padding: 10px 0;
  }
  .escala-regua-dia { grid-area: dia; }
  .escala-regua-linha > .escala-medida:first-of-type { grid-area: pessoas; }
  .escala-regua-linha > .escala-medida:last-of-type { grid-area: horas; }
  .escala-regua-soma { display: none; }
}

/* ⚠️ Substitui `.escala-equipa-linha`: era um grid de 5 colunas com mínimos que
   somavam ~660px + gaps dentro de uma coluna mais estreita do que isso. */
.escala-equipa-linha {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    "nome"
    "opcoes";
  align-items: center;
  gap: 8px 12px;
  padding: 9px 0;
  border-bottom: 1px solid var(--line);
}
.escala-equipa-linha > strong { grid-area: nome; overflow-wrap: anywhere; }
.escala-equipa-opcoes {
  grid-area: opcoes;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 18px;
  min-width: 0;
}
.escala-equipa-opcoes .campo-inline { margin: 0; font-size: 13px; }
.escala-equipa-hora { flex-direction: row; align-items: center; gap: 8px; }
.escala-equipa-iniciais input {
  width: 6ch;
  text-transform: uppercase; /* só apresentação — a normalização que conta é a do serviço */
}

@container (min-width: 620px) {
  .escala-equipa-linha {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1.4fr);
    grid-template-areas: "nome opcoes";
  }
  /* Com a faixa toda, as opções alinham em COLUNAS — a leitura vertical de
     «quem está incluído» vale mais do que o texto ficar justo a cada nome.
     ⚠️ Task 6 (revisão I1): 4 tracks, não 3 — Incluir / Iniciais / Hora / Responsável (nesta
     ordem no DOM, ver o comentário junto ao `<label class="campo-inline" for="responsavel-…">`
     no .cshtml). O Responsável é o único item condicional (só RhAdmin/responsável) e fica no
     ÚLTIMO track de propósito: assim os outros três ficam no MESMO track nas duas vistas, e a
     vista sem Responsável só deixa o 4.º track vazio — não empurra a Hora (que é um `<select>`,
     o item mais largo) para uma 2.ª linha. Antes de mover o Responsável para o fim, 4 itens em 3
     tracks faziam a Hora saltar sozinha para baixo em TODAS as linhas da vista RhAdmin,
     duplicando a altura de cada uma — ver
     `EscalaConfiguracaoLayoutTests.As_quatro_opcoes_do_RhAdmin_ficam_na_mesma_linha`. */
  .escala-equipa-opcoes {
    display: grid;
    grid-template-columns:
      minmax(0, 1fr) minmax(0, 0.5fr) minmax(0, 0.9fr) minmax(0, 0.72fr);
    gap: 12px;
  }
}

/* O ecrã diz de onde vem a lista — senão «faltam pessoas» parece um bug. */
.escala-equipa-fonte {
  margin: 0 0 10px;
  padding: 6px 10px;
  background: var(--sand);
  border-radius: var(--radius-sm);
  font-size: 12px;
  color: var(--muted);
}
.escala-equipa-fonte strong { color: var(--ink); }

/* PA6/PA7: estado das linhas do lote e o rodapé do formulário único. */
.escala-equipa-linha-suja { background: rgba(22, 190, 207, .06); }
/* ⚠️ `--status-error` não existe neste site.css — o token de erro já usado por `.alerta-erro`/
   `.texto-erro` é `--status-warning` (ver linhas 1037/1043); reusado aqui de propósito, para a
   linha culpada citar a MESMA cor que o resto da app já chama de "erro". */
.escala-equipa-linha-erro { box-shadow: inset 3px 0 0 var(--status-warning); padding-left: 10px; }
.escala-equipa-rodape { align-items: center; gap: 16px; margin-top: 14px; }
.escala-equipa-estado { margin: 0; font-size: 12.5px; color: var(--muted); }
.param-nota-campo { margin: 0 0 10px; padding: 6px 10px; max-width: 720px; border-left: 3px solid var(--cyan-soft); background: rgba(22, 190, 207, .08); border-radius: var(--radius-sm); font-size: 12px; color: var(--muted); }
.param-nota-campo strong { color: var(--ink); }

/* ─────────────────────────────────────────────────────────────────────────
   8. EDITOR DO RASCUNHO — a bancada em três painéis fixos
   ─────────────────────────────────────────────────────────────────────────
   O editor de antes obrigava a scroll nos DOIS eixos e mostrava menos do que o
   Excel que veio substituir. Três causas, e as três se corrigem aqui:
   1. A `.conteudo` trava tudo aos 1080px (`--conteudo-max`). O editor sai
      dessa trava — é a única página cuja unidade de leitura é o MÊS INTEIRO.
   2. A célula dizia «Trabalho · 08:00» por extenso, 31 vezes por linha. O
      Excel escreve «Trab» e só põe a hora quando ela FOGE da hora habitual da
      pessoa — a coluna «Hora» ao lado do nome é o que torna isso legível.
   3. O painel «Estado e hora» ocupava 244px fixos à direita, sempre, mesmo
      sem nada selecionado. Passa a barra no fundo, e só aparece com seleção.
   O que se ganha em largura é o que paga o painel de contadores. */

#escala-mobile-leitura { display: none; }

.conteudo-largo { max-width: none; }
/* ⚠️ DIVERGÊNCIA do delta (Tarefa 16): o delta punha a `.conteudo-largo` NA `.conteudo`, que vive
   no `_Layout.cshtml` — ficheiro fora do âmbito desta tarefa. O opt-in fica na PÁGINA (a secção do
   editor leva a classe) e o `:has()` leva-o ao contentor. É a mesma técnica que o
   `.conteudo:has(.cal-ausentes[open])` já usa neste ficheiro, e não obriga toda a gente a passar
   pelo layout para pedir largura. */
.conteudo:has(.conteudo-largo) { max-width: none; }

/* ED5: o embrulho da bancada + barra sticky. `width: fit-content; max-width: 100%` — o mesmo
   truque da bancada logo abaixo — porque o embrulho NÃO herda a largura medida da bancada; sem
   isto a barra (que é `width: 100%` do pai) ficava mais larga do que a mesa. `position: relative`
   é para a caixa de ajuda e o popover da hora padrão (Tasks 7–8) se posicionarem em relação a
   este retângulo, não à página inteira. */
.editor-ancora {
  position: relative;
  width: fit-content;
  max-width: 100%;
  /* `--nome-w`/`--hora-w` vivem aqui (e não em `.editor-bancada`) porque o popover da hora padrão
     (`.editor-pop-hora`, ED8) é IRMÃO da bancada, não descendente — precisa de as ler para o
     `left: calc(...)`. `.editor-ancora` é o ancestral comum aos dois. */
  --nome-w: 106px;
  /* ⚠️⚠️ 46px, não 34px, nem os 42px da ronda 2 (2026-08-29). RONDA 4 do Codex (2026-08-29, P2):
     o catálogo de horas aceita qualquer `TimeOnly` alinhada ao minuto (`AdicionarHoraAsync` não
     restringe a meia-hora), e uma hora como 12:30 também é «HoraCurta» — «12·30», 5 glifos, não os
     4 de «8·30». MEDIDO com a mesma sonda fora do fluxo da ronda 2: 5 caracteres mono a 6px cada =
     30px de conteúdo (não os 24px de «8·30» — a ronda 2 mediu certo para o valor errado, o único
     que o cenário de teste usava). Com margem do lápis 1px + `.editor-lapis` 13px + padding da
     célula 2px (1px de cada lado): 30 + 1 + 13 + 2 = 46px de conteúdo — ZERO folga a 46px. Fica-se
     por 46px e não se soma o 1px de folga habitual: são os contadores que pagam esta ronda (ver o
     comentário do orçamento em `.editor-bancada`, mais abaixo, que é onde a soma tem de fechar), e
     esticar `--hora-w` mais um pixel só para ter folga custava esse pixel a uma coluna que já não
     tem margem nenhuma para dar.
     MEDIDO (não só calculado): com 46px, o teste `O_lapis_da_hora_12_30_cabe_...` (novo, ronda 4)
     confirma o lápis contido e «12·30» sem corte; a mutação (repor 42px) falha esse teste. */
  --hora-w: 46px;
}
/* ⚠️ `fit-content` e não largura total: com o painel dos dias em `flex: 1` a
   esticar, sobrava uma faixa branca entre o dia 31 e os contadores sempre que a
   janela era maior do que o mês. A bancada mede o que precisa e não mais. */
.editor-bancada {
  display: flex;
  align-items: stretch;
  width: fit-content;
  max-width: 100%;
  margin: 16px 0 0;
  border: 1px solid var(--ink);
  border-radius: var(--radius-md);
  background: var(--paper);
  overflow: hidden;
}
/* Os três painéis partilham a MESMA altura de linha — é o que os mantém
   alinhados sem uma única tabela de 41 colunas. */
.editor-bancada {
  --linha: 30px;
  --cabeca: 34px;
  /* ⚠️ Estas cinco medidas são um ORÇAMENTO, não gosto pessoal.
     «Folga» e «08·30» medem 28,5px em JetBrains Mono a 9,5px (medido no
     browser, com a fonte carregada) — daí os 30px da coluna de um dia, e não
     28, que cortava por meio pixel em 224 células. O resto está apertado ao
     mínimo para que a soma dê 1276px:
       106 + 34 + 31×30 + 8×24 + 6 de réguas = 1268
     contra os 1276px de conteúdo disponíveis a 1440px de janela com a barra
     lateral recolhida. É esse o alvo: o mês inteiro sem uma passada de scroll.
     Abaixo disso os dias deslizam entre dois painéis fixos, que é como o Excel
     também se comporta.
     Os 106px do nome saem de uma MEDIÇÃO e não de um palpite: «C. Lourenço», o
     mais largo, mede 64px a 11,5px em Instrument Sans, mais 20 da sigla, 8 de
     folgas, 6 do ponto da observação e 8 de padding. A hora e os contadores
     pagaram esse alargamento — nenhum deles precisa de mais do que tem.
     ⚠️ `--nome-w`/`--hora-w` foram MOVIDAS para `.editor-ancora` (hotfix 2026-08-28) — o
     popover `.editor-pop-hora` (ED8) precisa de as ler e é irmão da bancada, não descendente.
     `--hora-w` passou de 34px para 46px ao longo de quatro rondas (ver comentário em
     `.editor-ancora`); o orçamento acima ainda usa os valores originais para explicar o alvo de
     1276px.
     ⚠️⚠️ RONDA 2 do Codex (2026-08-29, P2): a primeira compensação (`--cont-w: 23px`) cabia no
     orçamento mas não deixava a coluna «seguidos» mostrar «11△?» (2 dígitos + `△` de
     `AUmSabadoDoExtra` + `?` de `SerieIncerta`) sem cortar — MEDIDO com uma sonda fora do fluxo:
     26,36px de conteúdo (não os ~16px que 4 caracteres mono a 4px pareceriam render, porque `△`
     foge da fonte mono para uma de reserva mais larga). Nenhuma das OUTRAS 7 colunas de contador
     mostra símbolo nenhum — só dígitos —, por isso só ESSA coluna precisa de mais espaço; alargar
     as 8 por igual (como a Ronda 1 fez ao repor 24px) gastava orçamento que as outras 7 não
     precisam. Daqui a `--cont-w-serie`, uma variável SÓ para essa coluna (`.editor-contador-serie`,
     na `th`/`td` — ver a marcação em `Editar.cshtml`), com `--cont-w` a voltar aos 24px originais
     para as restantes (depois apertado a 23px nessa mesma ronda para fechar o orçamento).
     ⚠️⚠️ RONDA 4 do Codex (2026-08-29, P2): o catálogo de horas NÃO restringe a meia-hora
     (`AdicionarHoraAsync`) — uma hora como 12:30 é tão válida quanto as três semeadas por
     `HasData`, e «12·30» tem 5 glifos contra os 4 de «8·30» que as rondas 1-3 mediram. MEDIDO com a
     mesma sonda: 30px de conteúdo (5 × 6px), não 24px. `--hora-w` subiu de 42px para 46px (ver o
     comentário em `.editor-ancora` — 30 + 1 margem + 13 lápis + 2 padding = 46, zero folga). Os 4px
     que isso pede tinham de sair de outro lado: `--dia-w` continua fora de questão (hard-coded a
     30px no teste, ver parágrafo acima) e o nome continua sem folga nenhuma (64/64px, reconfirmado
     de novo). A válvula voltou a ser `--cont-w`: as OUTRAS 7 colunas (só dígitos, ≤12px de
     conteúdo, e cabeçalhos de duas linhas a 8-9px, ≤16,2px) desceram de 23px para 21px — MEDIDO com
     a sonda: 2 dígitos a 10px mono ≈ 12px + 2px de padding = 14px de mínimo; o cabeçalho de 3
     letras a 9px ≈ 16,2px + 2px = 18,2px de mínimo — 21px fica com folga nos dois. `--cont-w-serie`
     (a coluna «seguidos») fica intocado a 30px — não é ela que tem de pagar. Orçamento final:
     106 + 46 + 31×30 + 7×21 + 30 + 6 = 1265px contra os 1276px disponíveis, 11px de folga —
     confirmado o rodapé (`colspan="8"`, o texto «09/25→08/26» + botão «?») e o cabeçalho «?» dos
     contadores continuam a caber (7×21 + 30 = 177px, mais largo do que qualquer um dos dois). */
  --dia-w: 30px;
  --cont-w: 21px;
  /* ⚠️⚠️ SÓ a coluna «seguidos» (`.editor-contador-serie`) — as outras 7 ficam em `--cont-w`. 30px
     dá 3,64px de folga sobre os 26,36px medidos de conteúdo + 2px de padding (1px de cada lado) =
     28,36px — mais folga do que o resto desta bancada, de propósito: a largura de `△` depende da
     fonte de RESERVA do sistema (não está em JetBrains Mono), que pode variar ligeiramente entre
     Windows/macOS/Linux, ao contrário do texto mono medido em todo o resto da bancada. */
  --cont-w-serie: 30px;
  --dias: 31;
}
/* ⚠️ O número de dias vem do ATRIBUTO e não de um `style=` na página: os constrangimentos desta
   ronda proíbem `style=` no markup, e o delta dizia só «a página põe o número de dias do mês».
   São quatro valores possíveis num calendário — quatro regras chegam. */
.editor-bancada[data-dias="28"] { --dias: 28; }
.editor-bancada[data-dias="29"] { --dias: 29; }
.editor-bancada[data-dias="30"] { --dias: 30; }
.editor-bancada[data-dias="31"] { --dias: 31; }

.editor-painel { flex: 0 0 auto; }
.editor-dias { flex: 0 1 auto; min-width: 0; overflow-x: auto; overscroll-behavior-x: contain; }
.editor-fixo-esq { border-right: 2px solid var(--ink); }
.editor-fixo-dir { border-left: 2px solid var(--ink); background: var(--cream); }

/* ⚠️ `table-layout: fixed` + largura CALCULADA, nas três tabelas.
   Em layout automático é o conteúdo que manda: a coluna de um dia, pedida a
   28px, media 35,8px porque «Folga» a 9,5px exigia isso — 31 colunas, 240px de
   largura a mais, e a bancada só cabia num ecrã de 1920px. Com layout fixo a
   coluna é a que está escrita e ponto; o que não couber, corta (e há uma guarda
   que mede se alguma vez corta). */
.editor-tabela {
  border-collapse: collapse;
  table-layout: fixed;
  font-size: 11px;
}
.editor-fixo-esq .editor-tabela { width: calc(var(--nome-w) + var(--hora-w)); }
.editor-dias .editor-tabela { width: calc(var(--dias) * var(--dia-w)); }
/* ⚠️⚠️ 7 colunas em `--cont-w` + 1 em `--cont-w-serie` (ronda 2, P2) — não `8 * var(--cont-w)`
   como antes: só a coluna «seguidos» precisa de mais espaço (ver os comentários dos dois valores
   em `.editor-bancada`). */
.editor-fixo-dir .editor-tabela { width: calc(7 * var(--cont-w) + var(--cont-w-serie)); }
.editor-tabela th, .editor-tabela td {
  height: var(--linha);
  padding: 0 4px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.editor-tabela thead th {
  height: var(--cabeca);
  border-bottom: 1px solid var(--ink);
  background: var(--sand);
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: .4px;
  text-transform: uppercase;
  color: var(--muted);
  vertical-align: middle;
}
.editor-tabela tfoot td, .editor-tabela tfoot th {
  border-top: 1px solid var(--ink);
  border-bottom: 0;
  background: var(--sand);
  font-family: var(--font-mono);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.editor-tabela tbody tr:hover { background: transparent; }

/* ⚠️ O nome tem de caber numa LINHA. Com a sigla em `display: block` a linha do
   painel esquerdo passava a ~60px e a dos dias ficava nos 30px — e como são
   três tabelas irmãs, e não uma, os painéis DESALINHAVAM (a bancada media 846px
   em vez de ~430px). É o preço de ter painéis fixos: as alturas de linha são um
   contrato, não uma consequência. */
.editor-nome {
  width: var(--nome-w);
  text-align: left;
  font-family: var(--font-sans);
  font-size: 11.5px;
  font-weight: 600;
  overflow: hidden;
  /* O «−» de tirar a pessoa do rascunho ancora-se aqui — ver `.editor-remover`. */
  position: relative;
}
/* O nome é um BOTÃO: é por ali que se escreve a observação do mês daquela
   pessoa. Sem isto não havia sítio nenhum no editor para o fazer — o campo
   existia no modelo e não existia no ecrã. */
.editor-nome-btn {
  display: flex;
  align-items: center;
  gap: 4px;
  width: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.editor-nome-btn:hover .editor-nome-curto { text-decoration: underline; }
.editor-nome-btn:focus-visible { box-shadow: var(--shadow-ring); outline: none; }
.editor-nome-btn[aria-expanded="true"] .editor-nome-curto { text-decoration: underline; }

.editor-obs-painel {
  margin: 0;
  padding: 14px 16px;
  background: var(--sand);
  border: 1px solid var(--line);
  border-top: 0;
  border-radius: 0 0 var(--radius-md) var(--radius-md);
}
.editor-obs-painel[hidden] { display: none; }
.editor-obs-painel h3 { margin: 0 0 8px; font-size: 15px; }
.editor-obs-painel textarea { width: 100%; max-width: 560px; }
.editor-obs-painel .form-acoes { margin-top: 10px; }

/* A sigla é largura fixa e não encolhe; o que cede é o nome.
   ⚠️ Seletor descendente e NÃO filho direto: desde que o nome passou a botão, a
   sigla deixou de ser filha da célula e a largura fixa não pegava (media 11,75px
   em vez de 20) — medido. */
.editor-nome .editor-sigla {
  flex: 0 0 20px;
  width: 20px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  color: var(--ocean);
}
.editor-nome-curto {
  display: inline-block;
  /* 20 sigla + 4 gap + 4 gap + 6 ponto + 8 de padding da célula = 42 */
  max-width: calc(var(--nome-w) - 42px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
  font-weight: 500;
}
/* Uma observação é rara (2 pessoas em 12) e não paga uma coluna de 150px numa
   grelha que luta por largura. Fica um ponto ao lado do nome e o texto na lista
   por baixo da bancada. */
/* ⚠️ SEM `margin-left`, ao contrário do delta — MEDIDO: o botão do nome é `display: flex` com
   `gap: 4px`, portanto a margem era uma segunda folga por cima da primeira. Os 4px que ela comia
   eram exatamente os que faltavam ao nome mais largo: «C. Lourenço» media 64px numa caixa de 60 e
   levava reticências. A conta do delta («20 sigla + 4 gap + 4 gap + 6 ponto + 8 de padding = 42»)
   só fecha sem esta margem. */
.editor-marca-obs {
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--gold-deep);
  vertical-align: 0.1em;
}
/* ⚠️ O ponto some-se por CLASSE e não por `style="visibility:hidden"` no markup: os
   constrangimentos desta ronda proíbem `style=` na página. O JS troca a classe; o espaço fica
   sempre ocupado (6px + 4px), que é o que a coluna de 106px já orçamentou. */
.editor-marca-obs-oculta { visibility: hidden; }

/* ── Tirar alguém do rascunho ── */
/* ⚠️⚠️ POSICIONADO EM ABSOLUTO, e é a única forma que a bancada consente. A coluna do nome tem
   106px orçamentados ao milímetro (20 da sigla + 64 do nome mais largo + 6 do ponto + folgas) e a
   ALTURA DE LINHA É UM CONTRATO entre as três tabelas irmãs: um botão no fluxo empurrava o nome
   para reticências e, se envolvesse a linha, desalinhava os três painéis (§9, item 10). Fora do
   fluxo, não mede nada e não empurra nada — sobrepõe-se ao fim do nome enquanto está visível, que
   é só com o rato em cima ou com o foco lá dentro.
   ⚠️ `opacity` e NÃO `visibility: hidden`: escondido por visibilidade, o botão saía da ordem de
   tabulação e não havia caminho de teclado nenhum para tirar uma pessoa da grelha. Assim o Tab
   chega-lhe, e o `:focus-within` da célula acende-o no momento em que chega. */
.editor-remover {
  position: absolute;
  right: 1px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--paper);
  color: var(--status-neutral);
  font: inherit;
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--transition-fast), color var(--transition-fast),
              border-color var(--transition-fast);
}
.editor-nome:hover .editor-remover,
.editor-nome:focus-within .editor-remover { opacity: 1; }
.editor-remover:hover { color: var(--ink); border-color: var(--ink); }
.editor-remover:focus-visible { opacity: 1; box-shadow: var(--shadow-ring); outline: none; }
.editor-remover:disabled { display: none; }

/* ── A equipa do rascunho: o «+» e o que está por guardar ── */
.editor-equipa {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  margin: 12px 0 0;
}
.editor-equipa-nota { font-size: 12px; color: var(--muted); }
/* A linha do que está por guardar tem de se ver: é o ÚNICO sinal que resta depois de a linha da
   pessoa desaparecer da grelha. */
.editor-equipa-pendente {
  margin: 0;
  padding: 6px 12px;
  border-left: 3px solid var(--gold);
  background: var(--sand);
  border-radius: var(--radius-sm);
  font-size: 12.5px;
  color: var(--ink);
}
.editor-equipa-pendente[hidden] { display: none; }
.editor-equipa-painel {
  margin: 12px 0 0;
  padding: 14px 16px;
  background: var(--sand);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  max-width: 720px;
}
.editor-equipa-painel[hidden] { display: none; }
.editor-equipa-painel h3 { margin: 0 0 8px; font-size: 15px; }
.editor-equipa-painel p { margin: 0 0 10px; font-size: 13px; color: var(--muted); }
.editor-equipa-campos { display: flex; flex-wrap: wrap; gap: 16px; }
.editor-equipa-campos .campo { margin: 0; flex: 0 1 260px; }
.editor-equipa-painel .form-acoes { margin-top: 14px; }

/* ── Importação do Excel para o rascunho (IMP-12): o painel e a lista de avisos ── */
/* Mesmos tokens e espaçamento do `.editor-equipa-painel` acima — é o mesmo tipo de bloco (um
   formulário curto, fora da grelha), só com outro conteúdo. */
.importar-painel {
  margin: 0 0 20px;
  padding: 14px 16px;
  background: var(--sand);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  max-width: 720px;
}
.importar-painel h3 { margin: 0 0 8px; font-size: 15px; }
.importar-nota { margin: 0 0 10px; font-size: 13px; color: var(--muted); }
.importar-painel .form-campos { display: flex; flex-wrap: wrap; gap: 16px; }
.importar-painel .form-campos .campo { margin: 0; flex: 0 1 260px; }
.importar-painel .form-acoes { margin-top: 14px; }
.importar-painel input[type="file"] { font-size: 12px; max-width: 100%; }

/* A lista de avisos usa a MESMA forma dos avisos já existentes no editor (`.alerta-aviso`: fundo
   `--sand`, texto/borda `--status-warning`) — forma uniforme, conteúdo próprio. Não é `.alerta`
   porque o conteúdo é uma lista com título, não uma frase única. */
.importar-avisos {
  margin: 0 0 20px;
  padding: 14px 16px;
  background: var(--sand);
  color: var(--status-warning);
  border: 1px solid rgba(110, 86, 32, 0.3);
  border-radius: var(--radius-md);
}
.importar-avisos h2 { margin: 0 0 8px; font-size: 15px; color: var(--status-warning); }
.importar-avisos ul { margin: 0; padding-left: 18px; font-size: 13px; }
.importar-avisos li { margin: 2px 0; }
.editor-tabela th.editor-hora-base,
.editor-tabela td.editor-hora-base { width: var(--hora-w); padding: 0 1px; }
.editor-hora-base {
  text-align: center;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--muted);
}

/* ── A célula de um dia ── */
/* ⚠️ A especificidade tem de bater a de `.editor-tabela th, .editor-tabela td`
   (0,2,0), senão o `padding: 0 4px` fica e cada coluna cresce 8px — 31 colunas,
   248px de largura a mais, medidos. */
.editor-tabela th.editor-dia,
.editor-tabela td.editor-dia { width: var(--dia-w); text-align: center; padding: 0; }
.editor-celula {
  display: block;
  width: 100%;
  height: calc(var(--linha) - 1px);
  /* ⚠️ `padding: 0` é OBRIGATÓRIO e não arrumação: a folha do próprio browser
     dá `padding: 1px 6px` a qualquer <button>. Sem isto sobram 17px de caixa
     útil numa coluna de 30px, «Folga» (28,5px) corta em 224 células e o layout
     automático inchava cada coluna para 35,8px. */
  padding: 0;
  border: 0;
  border-right: 1px solid var(--line);
  background: transparent;
  font-family: var(--font-mono);
  font-size: 9.5px;
  color: var(--ink);
  cursor: pointer;
}
.editor-celula:focus-visible { box-shadow: var(--shadow-ring); outline: none; }
/* ⚠️ O anel era `var(--cyan)`, e `--cyan` sobre `--paper` mede 2,26:1 — abaixo dos 3:1 que a
   WCAG 1.4.11 exige a um indicador de estado não-textual. Agrava que desde que a segunda classe
   (`escala-celula-selecionada`) saiu daqui, para não haver duas fontes de verdade do mesmo estado,
   este anel passou a ser o ÚNICO canal visual da seleção — na interação central do editor.
   `--ocean` é o que a bancada anterior usava e mede 7,18:1 sobre `--paper`. Medido em Chromium,
   píxel a píxel e em TODOS os estados selecionáveis, pelo
   `O_anel_da_seleccao_mede_pelo_menos_3_para_1_em_todos_os_estados`. */
.editor-celula[aria-pressed="true"] { box-shadow: inset 0 0 0 2px var(--ocean); }
/* ⚠️ E há UM estado onde o `--ocean` não pode ficar: a FALTA é roxo cheio, e `--ocean` sobre
   `--plum` mede 1,22:1 — é o mesmo aviso que o `:root` já dá («--plum e --ocean estão PERTO em
   luminância»), aqui a morder no anel em vez de na cor de fundo. Sobre um fundo escuro o anel
   inverte-se: `--paper` mede 5,91:1 sobre `--plum` e 9,67:1 sobre a risca `--plum-deep`.
   Férias e ausência partilham o aspeto da falta mas são `disabled` — nunca chegam a ser
   selecionadas, por isso não entram nesta regra. */
.editor-celula.falta[aria-pressed="true"] { box-shadow: inset 0 0 0 2px var(--paper); }

/* Trabalho à hora habitual: nada de cor — é o caso normal, e o normal não se
   pinta. Só a hora FUGIDA ganha destaque — «fora do habitual» é UM estado, com
   UMA cor só (o recuo `--turno-cor` cai em `--cyan-deep`, nunca leva `turno-N`
   — A10, ruling do controlador 2026-08-14: colorir por posição da hora era a
   mesma decoração redundante que a vista «Mês» perdeu primeiro). A hora
   continua escrita na célula — é lá que o VALOR vive; a cor só marca o ESTADO.
   ⚠️⚠️ CORREÇÃO CRÍTICA (ronda 1 de correções, 2026-08-14): esta regra não tinha
   RECUO — ao contrário do `.escala-turno-hora` (`var(--turno-cor, var(--cyan-deep))`,
   mais acima), `background` e `color` liam só `var(--turno-cor)`. Sem nenhuma classe
   `turno-N` a defini-la (a A10 tirou-a da bancada), a variável ficava por definir, as
   duas declarações tornavam-se INVÁLIDAS em tempo de computação, e resolviam para
   `unset`: o fundo (não herdado) ia a `transparent`, a cor (herdada) passava a ser a
   do pai (`--ink`, quase preto) — a célula ficava com texto escuro a negrito e ZERO
   fundo, não com «uma cor só». O recuo explícito corrige isso.
   ⚠️⚠️⚠️ Só o recuo não chega: `--cyan-deep` inteiro sobre 22% dele mesmo mede ~3,99:1
   por cálculo sRGB — abaixo do 4,5:1 que esta suite exige. O texto escurece com
   `--ink`, na MESMA receita que o `.escala-turno-hora` já usa para o terceiro turno
   (dourado): mistura a 85%, não um token novo.
   ⚠️⚠️⚠️⚠️ CORREÇÃO (ronda de correções 2/5, 2026-08-14): o par que o desenho apresenta
   — `color` computado contra `background-color` computado, os dois lidos do próprio
   browser — mede **4,82:1**. NÃO é o 5,16:1 que aqui esteve: esse saiu de medir o pixel
   mais claro e o mais escuro da célula INTEIRA, e a célula tem `border-right: 1px solid
   var(--line)` — mais claro do que o tinte a 22% — por isso o "mais claro" apanhado era
   sempre a borda, nunca o fundo. 4,82:1 é 0,32 acima do mínimo: MARGEM PEQUENA — quem
   mexer na percentagem do tinte ou no token do texto tem de medir outra vez, não
   assumir que ainda passa. Medido via `getComputedStyle` (não por pixel do elemento
   inteiro), em `O_texto_da_celula_fora_do_habitual_cumpre_o_contraste_minimo`. */
.editor-celula.trab { color: var(--muted); }
.editor-celula.trab-fora {
  background: color-mix(in srgb, var(--turno-cor, var(--cyan-deep)) 22%, var(--paper));
  color: color-mix(in srgb, var(--turno-cor, var(--cyan-deep)) 85%, var(--ink));
  font-weight: 700;
}
.editor-celula.folga { background: var(--sand); color: var(--status-neutral); }
.editor-celula.ferias { background: rgba(1, 94, 130, .3); color: var(--ocean-dark); font-weight: 600; }
/* ⚠️ FALTA e AUSÊNCIA partilham o mesmo aspeto, por decisão do Bruno: para quem
   monta a escala as duas dizem a mesma coisa — «esta pessoa não está cá». A
   diferença que SOBREVIVE é a que muda o que se pode fazer: a ausência validada
   pelo RH não se edita por cima, e é isso que o cadeado e o `title` dizem.
   O tramado escuro que a falta teve antes era pouco percetível; o roxo cheio
   com riscas lê-se de longe.
   ⚠️ As riscas são ESCURAS e não claras, e isso é uma correção medida. Com a risca clara
   (`#8d80b8`) o branco a 9,5px/700 media 3,55:1 em cima dela — abaixo dos 4,5:1 do texto — e com
   riscas de 4px a 135° metade dos glifos de «Falta» cai lá. Com `--plum-deep` por cima de `--plum`
   o pior par passa a ser branco/`--plum` = 5,91:1, e o melhor branco/`--plum-deep` = 9,67:1.
   Medido no `A_falta_escreve_branco_sobre_um_tramado_que_da_pelo_menos_4_5_para_1`.
   ⚠️ E NÃO é «o mesmo par já usado no mapa da equipa», como aqui se dizia. O que a
   `.mapa-ausencia` (linha ~1418) partilha com esta célula é só a CONSTRUÇÃO — `background-color`
   com um `background-image` de riscas: as cores são outras (lá as riscas são CLARAS, em
   `color-mix(in srgb, var(--paper) 60%, transparent)`) e sobretudo lá não há texto nenhum por
   cima. O `rgba(107,91,149,.28)` que a afirmação antiga citava é de outro sítio ainda — a
   `.plano-cel.ausencia` (linha ~3024), que escreve em `--plum-deep` e não em branco. A novidade
   desta célula é escrever BRANCO por cima do tramado, e é isso que muda a conta. */
.editor-celula.falta,
.editor-celula.ausencia {
  background-color: var(--plum);
  background-image: repeating-linear-gradient(135deg, var(--plum-deep) 0 4px, transparent 4px 8px);
  color: #fff;
  font-weight: 700;
}
/* Indisponibilidade oficial: não se edita por cima sem se saber. */
.editor-dia.bloqueado .editor-celula { cursor: not-allowed; }
.editor-dia.col-fds { background: rgba(14, 21, 47, .05); }
.editor-dia.col-feriado { background: rgba(202, 168, 90, .16); }

.editor-cabeca-dia { display: grid; grid-template-rows: 11px 12px; justify-items: center; }
.editor-cabeca-dia .num { font-size: 11px; color: var(--ink); font-variant-numeric: tabular-nums; }
.editor-cabeca-dia .periodo { font-size: 8px; color: var(--cyan-deep); letter-spacing: 0; }
.editor-cabeca-dia .medida { font-size: 9px; color: var(--ink); letter-spacing: 0; }
.editor-dia-fds .num, .editor-dia-feriado .num { color: var(--gold-deep); }

/* ED1: enquanto se arrasta, o rato nao pinta texto pela grelha. */
.editor-a-arrastar, .editor-a-arrastar * { user-select: none; -webkit-user-select: none; }
.editor-dia-btn { all: unset; display: block; width: 100%; cursor: pointer; }
.editor-dia-btn:focus-visible { outline: 2px solid var(--ocean); outline-offset: -2px; }
.editor-dia-btn:disabled { cursor: default; }

/* ── Painel de contadores ── */
.editor-tabela th.editor-contador,
.editor-tabela td.editor-contador { width: var(--cont-w); padding: 0 1px; }
/* ⚠️⚠️ Ronda 2 do Codex (2026-08-29, P2): só a coluna «seguidos» mostra `△`/`?` — «11△?» precisa de
   mais largura do que as outras 7 (ver o comentário de `--cont-w-serie` em `.editor-bancada`). A
   MESMA especificidade que a regra geral acima (duas classes + tipo); tem de vir DEPOIS dela no
   ficheiro para o `width` ganhar em cascata — não é `!important` nem um seletor mais específico de
   propósito, para ficar óbvio que é a ORDEM que decide. */
.editor-tabela th.editor-contador-serie,
.editor-tabela td.editor-contador-serie { width: var(--cont-w-serie); }
.editor-contador { text-align: center; font-family: var(--font-mono);
  font-size: 10px; font-variant-numeric: tabular-nums; }
.editor-contador.destaque { font-weight: 700; color: var(--ocean); }
/* Quem está a um sábado do extra: é a única pergunta que muda a decisão de
   quem monta a escala, por isso é a única que grita. */
.editor-contador.quase { background: rgba(110,86,32,.16); color: var(--status-warning); font-weight: 700; }
/* ⚠️ DIVERGÊNCIA do delta: o `.editor-obs` do delta trazia `width: 150px` + reticências, medida da
   coluna de observações que a §7-A.5 da spec REJEITA («não paga 150px numa grelha que luta por
   largura»). Aqui a observação vive na lista por baixo da bancada, e um clamp de 150px cortava
   precisamente o texto que a lista existe para mostrar. Fica o resto do aspeto. */
.editor-obs { text-align: left; font-family: var(--font-sans); font-size: 12px; color: var(--muted); }
.editor-obs-lista { list-style: none; margin: 10px 0 0; padding: 0; }
.editor-obs-lista li { padding: 3px 0; }
.editor-obs-lista li[hidden] { display: none; }
.editor-obs-sigla { font-family: var(--font-mono); font-weight: 700; color: var(--ocean); }

/* ── O rodapé «Ao serviço» (§7-A.1): quantas pessoas cobrem cada dia ──
   ⚠️ Âmbar E seta: a cor não pode ser o único canal, e é o mesmo `△` que a régua da cobertura já
   usa. O número é do RASCUNHO GUARDADO — recalcula-se ao guardar, como os contadores. */
.editor-servico { text-align: center; font-size: 9.5px; }
.editor-servico-abaixo { background: rgba(110,86,32,.16); color: var(--status-warning); }

/* ED7: a ajuda dos contadores — o «?» mede 14px e fica inline; a CAIXA vive fora da bancada. */
.editor-ajuda { display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; padding: 0; margin-left: 6px; border: 0; background: transparent; color: var(--ocean); cursor: pointer; vertical-align: -3px; }
.editor-ajuda svg { width: 12px; height: 12px; }
.editor-ajuda:hover { color: var(--ocean-dark); }
.editor-ajuda-caixa { position: absolute; z-index: 35; width: min(430px, 92%); padding: 12px 14px; background: var(--paper); border: 1px solid var(--ocean); border-radius: var(--radius-md); box-shadow: 0 22px 48px -22px rgba(1, 94, 130, .55); }
.editor-ajuda-caixa[hidden] { display: none; }
.editor-ajuda-caixa .editor-notas { margin: 0; }

/* ED8: o lápis da hora padrão — mesma família do «?» acima (14px → 13px, inline, dentro da coluna
   de --hora-w). O popover é a mesma técnica da caixa de ajuda: fora da `.editor-bancada` mas seu
   IRMÃO, dentro da `.editor-ancora`, posicionado por `position: absolute` do JS.
   `left: calc(var(--nome-w) + var(--hora-w))` — agora que as duas vivem em `.editor-ancora`
   (hotfix 2026-08-28, ver esse seletor) o popover lê-as diretamente em vez de um valor fixo;
   começa logo a seguir à coluna da Hora, no início do painel dos dias. */
.editor-lapis { display: inline-flex; align-items: center; justify-content: center; width: 13px; height: 13px; padding: 0; margin-left: 1px; border: 0; background: transparent; color: var(--ocean); cursor: pointer; vertical-align: -2px; }
.editor-lapis svg { width: 11px; height: 11px; }
.editor-pop-hora { position: absolute; left: calc(var(--nome-w) + var(--hora-w)); z-index: 36; width: 260px; padding: 12px 14px; background: var(--paper); border: 1px solid var(--ocean); border-radius: var(--radius-md); box-shadow: 0 22px 48px -22px rgba(1, 94, 130, .55); }
.editor-pop-hora[hidden] { display: none; }
.editor-pop-hora h3 { margin: 0 0 8px; font-size: 13px; }
.editor-pop-hora-linha { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-family: var(--font-mono); }
.editor-pop-hora .form-acoes { margin: 10px 0 0; }

/* ── Barra de ação: só existe quando há seleção. `sticky bottom: 0` preso ao embrulho
   `.editor-ancora` (que só tem a bancada e a barra) — por construção nunca desce abaixo do
   fundo da bancada, e por isso nunca cobre a legenda nem o que vem a seguir (ED5). ── */
.editor-barra {
  position: sticky;
  bottom: 0;
  z-index: 5;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 16px;
  margin: 0;
  padding: 12px 16px;
  background: var(--ocean-darker);
  color: #e8eaf0;
  border-radius: 0 0 var(--radius-md) var(--radius-md);
}
.editor-barra[hidden] { display: none; }
.editor-barra-resumo { font-family: var(--font-mono); font-size: 11px; color: var(--cyan-soft);
  text-transform: uppercase; letter-spacing: .6px; }
.editor-barra .btn-estado {
  padding: 6px 12px;
  border: 1px solid rgba(255,255,255,.25);
  border-radius: var(--radius-sm);
  background: transparent;
  color: #fff;
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}
.editor-barra .btn-estado:hover { background: rgba(255,255,255,.1); }
/* ⚠️ Acrescentado ao delta: os botões de estado são um grupo de escolha (o JS põe-lhes
   `aria-pressed`) e o delta não trazia o aspeto do escolhido — sem ele, escolher «Folga» não se
   via em lado nenhum. Ciano cheio com tinta escura por cima: 8,7:1. */
.editor-barra .btn-estado[aria-pressed="true"] {
  border-color: var(--cyan);
  background: var(--cyan);
  color: var(--ocean-darker);
  font-weight: 700;
}
.editor-barra select { font-size: 13px; }
.editor-barra-cobertura { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px;
  margin-left: auto; font-family: var(--font-mono); font-size: 12px; color: #c5cad4; }
/* ED2: a pista da barra. */
.editor-barra-hint { margin-left: auto; font-family: var(--font-mono); font-size: 11px; letter-spacing: .4px; color: #c5cad4; }
.editor-barra-hint kbd { font-family: var(--font-mono); font-size: 10px; padding: 1px 5px; border: 1px solid rgba(255,255,255,.3); border-radius: 4px; }

/* ED4: os botões de desfazer/refazer, nas `form-acoes` de baixo — pequenos e discretos, ao lado do
   «Guardar rascunho», não a competir com ele. */
.editor-historico { display: inline-flex; gap: 4px; }
.editor-historico .btn { padding: 6px 8px; }
.editor-historico svg { width: 15px; height: 15px; display: block; }

/* ED9 hotfix: o botão «Imprimir» tinha um <svg> sem regra de tamanho — nada o limitava, o
   SVG saía ao tamanho natural e o botão virava um bloco alto com o rótulo por baixo do ícone.
   O `.btn` é `inline-block` (não `inline-flex`), por isso o alinhamento faz-se por
   `vertical-align`, como em qualquer texto+ícone inline — sem tocar no `display` do `.btn`. */
#ed-imprimir svg { width: 15px; height: 15px; vertical-align: -3px; margin-right: 6px; }

/* A janela dos cumulativos, os meses em falta e as três armadilhas do painel (§FE-13 e as notas do
   coordenador): sem isto o painel mostra números que descem sem dizer porquê. */
.editor-notas { margin: 10px 0 0; font-size: 12px; color: var(--muted); }
.editor-notas strong { color: var(--ink); }
.editor-notas .editor-janela { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.escala-lock-estado {
  margin: 16px 0 0;
  padding-top: 10px;
  border-top: 1px solid var(--line);
  color: var(--status-success);
  font-size: 11px;
  line-height: 1.35;
}
.escala-lock-estado::before { content: "● "; font-family: var(--font-mono); }
.escala-lock-perdido { color: var(--status-warning); font-weight: 650; }
.escala-cobertura-titulo {
  color: var(--cyan);
  font-family: var(--font-sans);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.escala-cobertura-item { white-space: nowrap; }
.escala-cobertura-ok::first-letter { color: var(--cyan); }
.escala-cobertura-aviso { color: var(--gold); }
.escala-publicacao {
  padding: 22px 20px;
  background: var(--paper);
  border-bottom: 1px solid var(--line);
}
.escala-publicacao h2 { margin-bottom: 14px; color: var(--ocean); font-size: 20px; }
.escala-confirmacao-expirada { margin-top: 16px; }

/* PA10 (hotfix): o menu «⋯» vive agora DENTRO de `.form-acoes` (último item, ao lado de
   «Preparar publicação») — antes ficava fora do `<form>` (dois `<form>` lá dentro não são válidos
   aninhados no principal) e o `margin-top: -8px` encostava-o solto à secção «Guardar e
   publicar», esquerda, por baixo do cartão. Sem margem negativa: é mais um item da linha. */
.menu-mais { position: relative; display: inline-flex; }
.menu-mais > summary { list-style: none; min-width: 42px; display: inline-flex; align-items: center; justify-content: center; }
.menu-mais > summary::-webkit-details-marker { display: none; }
.menu-mais-painel {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: 20;
  min-width: 288px;
  padding: 6px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
}
.menu-mais-item {
  display: block;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  background: transparent;
  text-align: left;
  font: inherit;
  color: var(--ink);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.menu-mais-item:hover, .menu-mais-item:focus-visible { background: var(--sand); outline: none; }
.menu-mais-perigo { color: var(--status-warning); }
.menu-mais-nota { display: block; margin-top: 2px; font-size: 11.5px; color: var(--muted); font-weight: 400; }
.menu-mais-sep { display: block; height: 1px; margin: 4px 6px; background: var(--line); }

@media (max-width: 390px) {
  .menu-mais-painel { width: min(288px, calc(100vw - 56px)); }
}


@media (max-width: 639.98px) {
  #form-editor-escala,
  .menu-mais { display: none; }
  #escala-mobile-leitura { display: block; }
  .escala-mobile-estado {
    margin: 14px 0 20px;
    padding: 12px 0;
    border-top: 1px solid var(--ink);
    border-bottom: 1px solid var(--ink);
  }
  .escala-mobile-estado h3 { color: var(--ocean); font-size: 17px; }
  .escala-mobile-estado p { margin: 5px 0; color: var(--muted); font-size: 12px; }
  .escala-mobile-pessoa { padding: 16px 0; border-top: 1px solid var(--line); }
  .escala-mobile-pessoa h3 { color: var(--ocean); font-size: 18px; }
  .escala-mobile-pessoa .lista { margin-top: 9px; }
  .escala-mobile-pessoa .lista li {
    display: grid;
    grid-template-columns: 88px minmax(0, 1fr);
    gap: 4px 9px;
    padding: 7px 0;
    border-bottom: 1px solid var(--line);
    font-size: 12px;
  }
  .escala-mobile-pessoa time { color: var(--muted); font-family: var(--font-mono); font-size: 10px; }
  .escala-mobile-pessoa small { grid-column: 2; color: var(--muted); }
}

/* ⚠️ As antigas @container(760px)/@container(690px) para `.escala-config-colunas` e
   `.escala-equipa-linha` (grid de duas colunas + grid de 5 colunas) saíram na Tarefa 6: eram do
   layout anterior e entravam em conflito com as `grid-template-areas` das secções 4 acima —
   deixar as duas era exatamente o defeito #7 (cascata a ganhar por ordem no ficheiro). A
   responsividade destas peças vive agora dentro da secção 4, com os seus próprios `@container`. */

/* ── Painel de marcar férias (<details> sem JS, como a topbar mobile) ──
   O <summary> é a ação principal desta página e por isso parece um botão, e não
   um link discreto como o da faixa anual: quem chega vem ver o saldo, e marcar
   tem de estar a um clique à vista. Fechado, o painel continua a submeter os
   campos que tem lá dentro — é markup, não visibilidade condicional. */
.painel-marcar { margin: 0 0 16px; }
.painel-marcar > summary {
  display: inline-block;
  list-style: none;
  cursor: pointer;
  background: var(--ocean);
  color: #fff;
  font-weight: 600;
  font-size: 14px;
  border-radius: 8px;
  padding: 9px 18px;
  transition: background-color var(--transition-fast), border-radius var(--transition-fast);
}
.painel-marcar > summary::-webkit-details-marker { display: none; }
.painel-marcar > summary:hover { background: var(--ocean-dark); }
/* O foco TEM de ser visível: o summary é o único caminho de teclado para o
   painel (WCAG 2.4.7), e o --shadow-ring é o mesmo anel do resto da app. */
.painel-marcar > summary:focus-visible { outline: none; box-shadow: var(--shadow-ring); }
/* \00a0 (espaço FIXO) em vez de um espaço normal (Task 3, fix round 1): um espaço comum a seguir
   ao conteúdo de um ::before pode colapsar contra o texto do summary que se segue — medido em
   screenshot ("-Marcar férias", colado). Um espaço fixo nunca colapsa. */
.painel-marcar > summary::before { content: "+\00a0"; font-family: var(--font-mono); }
.painel-marcar[open] > summary { background: var(--ocean-dark); }
.painel-marcar[open] > summary::before { content: "\2212\00a0"; }
/* Aberto (pedido do dono do produto, Task 3 fix round 1): "um bloco só, DESDE o botão marcar até
   ao submeter" — fechado isso já acontecia (pastilha isolada, é uma AÇÃO), mas aberto o botão lia-se
   como uma peça solta ANTES da caixa, não como o topo dela. Aqui o <summary> deixa de ser uma
   pastilha (inline-block, largura do texto) e passa a CABEÇALHO (block, largura toda do bloco,
   cantos arredondados só em cima) — encostado ao .painel-corpo (sem o antigo espaço entre os dois,
   ver o `margin-top` removido abaixo). Fechado continua sem esta regra: `[open]` é exatamente o
   seletor que já distinguia a cor e o `::before`, por isso reaproveita-se aqui. */
.painel-marcar[open] > summary { display: block; border-radius: 14px 14px 0 0; }
/* Regra órfã removida aqui (Task 3, acabamentos): `.painel-marcar > .lead { margin-top: 14px; }`.
   Desde a Task 1 o `.lead` deixou de ser filho DIRETO do `.painel-marcar` — está dentro do
   `.painel-corpo` (ver abaixo), por isso o seletor de filho nunca voltava a casar. Confirmado
   visualmente a 1440x900 e 390x844 que o espaçamento continua bom sem ela: o padding do
   `.painel-corpo` (22px/16px) mais o `margin: 8px 0 0` do `.lead` base já dão folga suficiente. */

/* O corpo do painel: a caixa que faltava. Mesma linguagem do .card (fundo de papel, borda fina,
   cantos), mas colado ao summary — é a continuação do CABEÇALHO acima, não um cartão à parte.
   Sem margin-top nem borda de cima (Task 3 fix round 1): um <details> só desenha isto quando está
   ABERTO (a folha do browser esconde os filhos que não sejam o summary enquanto fechado), e aberto
   o summary já É o cabeçalho colado — um espaço ou uma segunda borda aqui voltava a ler-se como
   duas peças em vez de uma. */
.painel-corpo {
  background: var(--paper);
  border: 1px solid var(--line);
  border-top: none;
  border-radius: 0 0 14px 14px;
  padding: 22px 24px;
  box-shadow: var(--shadow-xs);
}
/* O calendário dentro do painel não repete a moldura — a caixa é a de cima. */
.cal-sem-cartao { margin: 0; }

/* Correção da onda final (Minor 5 da revisão): o `#calendario` é o alvo do `asp-fragment` dos links
   de mês (ver `_CalendarioMes.cshtml` e `_FaixaAnual.cshtml`), e sem margem o browser aterra com o
   topo da grelha colado ao topo da janela — o cabeçalho "Marcar férias" e o parágrafo de instruções
   (a aresta de CIMA do bloco que a Task 1/3 construíram) ficam ACIMA da dobra, e perde-se a leitura
   de "isto é um bloco só" logo a seguir a mudar de mês.
   Medido (1400×1200, DeviceScaleFactor 3): o cabeçalho `<summary>` tem ~40px de altura e está a
   ~139px do topo do `#calendario`. A relação entre este valor e o `top` final NÃO é a soma ingénua
   que pareceria óbvia: sem NENHUMA regra de scroll-margin-top, o `top` final assenta a ~57px sozinho
   (comportamento nativo do browser para `#fragmento`); mas assim que se define um `scroll-margin-top`
   explícito, ele passa a dominar sozinho — `top final ≈ scroll-margin-top − 3,5px`.

   ⚠️⚠️ Correção da re-revisão da onda final (2026-08-03, Reserva 2 do Ponto 3): 160px SÓ tinha sido
   medido a 1440×900/1400×1200. A 390px o `.lead` quebra em mais linhas e a distância
   `summary→#calendario` sobe de ~139px para ~203px — a MESMA margem passou a deixar o cabeçalho
   INTEIRO acima da dobra (medido, com 160px: `top=-47,1px`, `bottom=-7,4px` do `<summary>` depois de
   mudar de mês a 390×844). 220px cobre as duas larguras, medido nas DUAS, não só calculado:
     · desktop (1400×1200): `#calendario` aterra a `top=216,3px` — 83,7px de folga abaixo do limiar
       absoluto de 300px dos testes de scroll (ratio 1,39×; era 1,92× com 160px — MENOS folga, mas
       ainda longe do limiar; a app não depende de fonte do SO — fontes self-hosted, viewport e DPI
       fixados por código — logo o risco de variação entre corridas é baixo) e 2,29× de folga do
       limiar relativo (metade de ~992px);
     · mobile (390×844): o cabeçalho do painel (`<summary>`) aterra a `top=12,9px`, `bottom=52,6px` —
       inteiro dentro da janela, com folga.
   Ver `PaginaFeriasTests.Mudar_de_mes_deixa_o_calendario_a_vista_em_vez_de_saltar_para_o_topo` (o
   limiar de 300px, com os números atuais) e
   `PaginaFeriasTests.Mudar_de_mes_a_390px_deixa_o_cabecalho_do_painel_visivel` (a cobertura nova do
   mobile, que faltava).

   ⚠️⚠️ Re-revisão da correção final (2026-08-04): a janela viável para este valor é
   [207,1px ; 303,7px) — abaixo de 207,1px o mobile fura (`sumTop` fica negativo, contra uma
   asserção de tolerância zero); a partir de 303,7px o desktop fura o limiar de 300px do teste de
   scroll. O lado APERTADO é o MOBILE, não o desktop: os 220px atuais estão a 83,7px do tecto mas
   só 12,9px do chão. O `.lead` do painel já quebra em 6 linhas a 390px e é texto de PRODUTO — uma
   linha a mais nessa cópia (~20px de altura) chega para empurrar o cabeçalho para cima da dobra,
   pôr `sumTop` negativo e partir o teste dos 390px
   (`PaginaFeriasTests.Mudar_de_mes_a_390px_deixa_o_cabecalho_do_painel_visivel`), sem nada à vista
   que ligue a falha à edição de texto que a causou. Se isso acontecer, o remédio é subir ESTA
   margem — há ~83px de folga antes de o limiar de 300px do teste de desktop também ter de subir. */
#calendario { scroll-margin-top: 220px; }

@media (max-width: 480px) { .painel-corpo { padding: 16px; } }

/* ── Os blocos escolhidos: substituem os campos Início/Fim ── */
.blocos { margin-top: 12px; padding: 10px 12px; border: 1px dashed var(--line);
          border-radius: var(--radius-sm); }
.blocos-titulo { font-family: var(--font-mono); font-size: 11px; color: var(--muted);
                 text-transform: uppercase; letter-spacing: 0.5px; }
.bloco-chip { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px;
              margin: 6px 6px 0 0; border-radius: var(--radius-pill); font-size: 13px;
              background: color-mix(in srgb, var(--ocean) 10%, transparent);
              border: 1px solid color-mix(in srgb, var(--ocean) 35%, transparent);
              color: var(--ocean-dark); }
.bloco-chip button { background: none; border: 0; cursor: pointer; font-size: 15px;
                     line-height: 1; color: var(--ocean); padding: 0; }
.blocos-vazio { font-size: 13px; color: var(--muted); }

/* ---------- Justificativos das ausências ----------
   Uma linha por documento (nome + Remover) e o formulário de anexar por baixo. O `flex-wrap` é o
   que impede um nome de ficheiro comprido — «atestado-medico-hospital-sao-joao-2026.pdf» — de
   esticar a coluna e desalinhar a tabela toda; o `word-break` parte o nome em vez de o deixar
   empurrar. Em ecrã estreito a `.tabela-pedidos` já transforma cada `td` num bloco do cartão. */
.anexo { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 6px; }
.anexo > a { font-size: 13px; word-break: break-all; }
.anexo-acao { margin: 0; }
.form-anexar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; }
/* O seletor de ficheiro nativo é enorme por omissão e a coluna é estreita. */
.form-anexar input[type="file"] { font-size: 12px; max-width: 100%; }

/* ─────────────────────────────────────────────────────────────────────────
   9. INÍCIO — a semana como tese da página
   ─────────────────────────────────────────────────────────────────────────
   O hero dizia «A tua área de RH: férias, saldos e aprovações num só sítio»:
   uma descrição do menu, no cimo da página, todos os dias, sempre igual. Passa
   a responder à única pergunta que se faz ao abrir — «o que é que me diz
   respeito agora».
   A faixa dos sete dias é a régua da app aplicada ao tempo, e não um widget
   novo: o `site.css` já descreve a régua como a assinatura da casa. Serve
   TODA A GENTE — quem está na escala vê o turno, quem não está vê os feriados,
   os fins de semana e as suas férias aprovadas. */

/* ⚠️ Sete colunas só quando há largura para elas. Em 390px davam 50px por dia e
   o conteúdo saía de todas as sete células — medido. Abaixo dos 720px a faixa
   quebra em linhas de 92px, que é o que «08:30» mais o dia precisam. */
.semana {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
  gap: 6px;
  margin: 18px 0 0;
}
@media (min-width: 720px) {
  .semana { grid-template-columns: repeat(7, minmax(0, 1fr)); }
}
.semana-dia {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 82px;
  padding: 9px 8px 10px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.semana-dia.fds, .semana-dia.feriado { background: var(--cream); }
.semana-dia.hoje { border-color: var(--cyan); box-shadow: inset 0 0 0 1px var(--cyan); }
.semana-cabeca {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted);
}
.semana-num { font-size: 15px; font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.semana-dia.hoje .semana-num { color: var(--cyan-deep); }
.semana-hoje-marca {
  font-size: 9px;
  letter-spacing: .6px;
  text-transform: uppercase;
  color: var(--cyan-deep);
}
.semana-estado { margin-top: auto; font-size: 12px; line-height: 1.35; }
.semana-turno {
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 700;
  color: var(--turno-cor, var(--cyan-deep));
}
.semana-turno::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 2px;
  background: var(--turno-cor, var(--cyan-deep));
}
.semana-nota { display: block; margin-top: 2px; font-size: 11px; color: var(--muted); }
.semana-estado.folga { color: var(--status-neutral); }
.semana-estado.ferias { color: var(--ocean); font-weight: 600; }
.semana-estado.feriado { color: var(--gold-deep); font-weight: 600; }
.semana-estado.quieto { color: var(--muted); }

/* A linha do trabalho à espera. Uma linha, não um cartão: é um atalho para uma
   decisão, e um cartão dava-lhe o peso de uma secção. */
.espera-linha {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 14px;
  margin: 0 0 16px;
  padding: 14px 18px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-left: 4px solid var(--cyan);
  border-radius: var(--radius-md);
}
.espera-numero {
  font-family: var(--font-serif);
  font-size: 26px;
  line-height: 1;
  color: var(--ocean);
  font-variant-numeric: tabular-nums;
}
.espera-texto { font-size: 14px; }
.espera-linha .btn { margin-left: auto; }

/* O saldo: o número grande fica, mas deixa de poder ser um zero sem contexto.
   «0 dias» era o elemento tipográfico mais forte da página no dia em que a
   pessoa já tinha gozado tudo — o facto verdadeiro estava na legenda. */
.saldo-de { font-size: 15px; color: var(--muted); margin: 0 4px 0 5px; }

/* ⚠️ A régua tinha um só estado para 22 dias «gozados» — e 22 segmentos iguais
   não dizem o que já passou nem o que ainda está para vir. É a diferença entre
   «já gastaste o ano» e «tens cinco dias marcados para daqui a duas semanas»,
   e a app tem as datas para o saber.
   `.seg-gozado` (azul cheio) fica a significar o que está MARCADO e ainda não
   aconteceu — é o que interessa a quem olha. O que já passou desbota. */
/* ⚠️ O BORDO fica a `--ocean` cheio e só o PREENCHIMENTO desbota. Com o bordo
   também a 45% o segmento media ~2,2:1 sobre o branco — abaixo dos 3:1 que um
   limite de componente precisa (WCAG 1.4.11). Assim o contorno diz «isto é um
   dia» e o preenchimento diz «este já passou». */
.seg-passado { background: rgba(1, 94, 130, .28); border-color: var(--ocean); }

/* A pergunta seguinte é «quando». Uma linha, logo por baixo da régua. */
.saldo-proximas {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 10px;
  margin: 12px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  font-size: 14px;
}
.saldo-proximas-rotulo {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .6px;
  text-transform: uppercase;
  color: var(--muted);
}
.saldo-proximas-quando { font-weight: 650; }
.saldo-proximas-falta { color: var(--muted); font-size: 13px; }
/* ⚠️ A classe do delta era `.vazio` e passou a `.sem-marcacoes` — DIVERGÊNCIA DELIBERADA, e é a
   QUARTA vez que este nome colide nesta ronda (ver `.mes-vizinho` aqui em cima e o `sem-plano` do
   editor, que a spec regista). O `site.css` tem um `.vazio` GLOBAL — o estado vazio de uma página,
   `text-align: center; padding: 32px 20px` — com a MESMA especificidade que esta regra e declarado
   ANTES (linha ~897): a linha casava com as duas e só o `padding-top` daqui é que a repunha.
   ⚠️⚠️ E esta via-se, ao contrário das outras. Medido em Chromium na linha «As próximas» de quem
   não tem férias marcadas: com `vazio`, padding 12/20/32/20 e `text-align: center`, altura 67px;
   sem ela, padding 12/0/0/0, `text-align: start`, altura 35px. Sobravam 32px de vazio morto no
   fundo do cartão, 20px de recuo lateral e o texto centrado — para toda a gente que não tenha
   férias marcadas. Guardado em `DashboardLayoutTests.A_linha_das_proximas_vazia_nao_apanha_o_estado_vazio_global`. */
.saldo-proximas.sem-marcacoes { color: var(--muted); }

/* ── Lateral compacta ──
   Os dois cartões usavam `.tabela`, com linhas de ~40px: três feriados e três
   aniversários ocupavam mais altura do que o saldo e as quatro ações juntas. */
.lista-lateral { list-style: none; margin: 0; padding: 0; }
.lista-lateral li {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 6px 0;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
  line-height: 1.35;
}
.lista-lateral li:last-child { border-bottom: 0; }
.lista-lateral .quando {
  flex: 0 0 46px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.lista-lateral .quem { min-width: 0; }
.lista-lateral li.passou { opacity: .55; }
/* O separador de mês entre aniversários: um rótulo, não um título de secção. */
.lista-lateral .mes-sep {
  display: block;
  padding: 10px 0 2px;
  border-bottom: 0;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--muted);
}
.lista-lateral li:first-child.mes-sep { padding-top: 0; }

/* Quatro atalhos, não um. As Ausências e a Escala estavam em produção e não
   tinham entrada nenhuma na primeira página da app. */
@media (min-width: 900px) {
  .acoes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ─────────────────────────────────────────────────────────────────────────
   GERIR ESCALA — uma página só (estado + versões + plano)
   ─────────────────────────────────────────────────────────────────────────
   Tarefa 13 / FE-07: o «Histórico da escala» fundiu-se aqui e a rota antiga
   passou a 301. Portado da secção 6 do `docs/frontend-2026-08-delta.css`, com
   as peças do plano publicado e da linha do tempo das versões que lá ficaram
   arrumadas na secção 7 mas são desta página. */

.mes-painel {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: 18px 24px;
  padding: 20px 22px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-left: 4px solid var(--ocean);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xs);
}
.mes-painel.rascunho { border-left-color: var(--gold); }
.mes-painel.sem-escala { border-left-color: var(--line); }
.mes-painel-titulo { margin: 0; font-size: 26px; }
.mes-painel-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  margin: 10px 0 0;
  font-size: 13px;
  color: var(--muted);
}
.mes-painel-meta strong { color: var(--ink); font-weight: 600; }
.mes-painel .form-acoes { margin: 0; }

.mes-numeros {
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
  margin: 16px 0 0;
  padding: 14px 0 0;
  border-top: 1px solid var(--line);
  grid-column: 1 / -1;
}
.mes-numero { display: flex; flex-direction: column; gap: 2px; }
.mes-numero-valor {
  font-family: var(--font-serif);
  font-size: 24px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
/* ⚠️ `critico` e NÃO `alerta`: o site.css já tem uma `.alerta` que é uma CAIXA
   (borda + padding + raio). Com o nome repetido, o número «2 dias sem cobertura»
   aparecia dentro de um retângulo solto — apanhado na primeira renderização. */
.mes-numero-valor.critico { color: var(--status-warning); }
.mes-numero-rotulo {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.7px;
  text-transform: uppercase;
  color: var(--muted);
}

/* A tira de 12 meses substitui os dois campos numéricos «Ano»/«Mês». */
.tira-meses { margin: 20px 0 0; }
/* O mês aberto POR EXTENSO, por cima da tira (hoje só o mapa da equipa o usa — o «Gerir escala» já
   tem o seu no `.mes-painel-titulo`). Sem ele, o único sinal do mês aberto era a moldura acesa do
   `.tira-mes[aria-current="true"]`, cor e mais nada. Ao contrário da tira, IMPRIME-SE: no papel é a
   única linha que diz de que mês é o mapa.
   O texto fica como vem do `MesTitulo` («agosto 2026», em minúscula, que é como se escreve em
   português) — igual ao que a `<nav class="mapa-meses">` removida desenhava e ao que o Gerir
   escreve no seu `.mes-painel-titulo`. */
.tira-meses-titulo { margin: 20px 0 0; font-size: 22px; }
.tira-meses-titulo + .tira-meses { margin-top: 8px; }
/* Ruling A18: o cabeçalho do ano da vista «Anual» ocupa o MESMO lugar que a tira dos meses (o mesmo
   título por cima, os mesmos segmentos por baixo) e por isso pede as MESMAS duas folgas. Vive aqui,
   ao pé das regras que espelha e não no bloco `mapa-ano-*`, porque o que se está a declarar é
   ADJACÊNCIA: os dois seletores abaixo têm de andar sempre com os irmãos deles.
   ⚠️ A ruling A4 tinha-a deixado SEM regra, com a premissa de que «o estilo vem todo do
   `tira-meses-titulo`/`tira-meses-ano`». Estava incompleta: essas duas dão a tipografia, mas as
   FOLGAS são de adjacência e um `+` não pega num irmão com outro nome. Sem estas duas linhas, medido
   em Chromium a 1400px: `título→navegação` −24,63px (o `<h2>` estava lá dentro) e
   `navegação→segmentos` 10px, contra os 8px e 20px da vista «Por dia» — ou seja, a barra dos três
   segmentos saltava de posição ao trocar de vista. */
.tira-meses-titulo + .mapa-ano-periodo { margin-top: 8px; }
.mapa-ano-periodo + .segmentos { margin-top: 20px; }
/* E o `<p>` de dentro perde os 10px de baixo, que aqui não separam nada: na tira eles afastam a
   linha dos anos da GRELHA dos doze, e o cabeçalho do ano não tem grelha nenhuma a seguir. Não é
   arrumação — medido, davam 30px em vez de 20px: como a `.segmentos` é `inline-flex`, é uma caixa
   de nível INLINE e nunca colapsa margens com o bloco anterior, por isso os 10px que sobravam
   SOMAVAM-SE aos 20px de cima em vez de desaparecerem dentro deles. */
.mapa-ano-periodo .tira-meses-ano { margin-bottom: 0; }
.tira-meses-ano {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 10px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--muted);
}
.tira-meses-grelha {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: 8px;
}
/* Em desktop os 12 meses ficam em DUAS linhas de 6 (ronda pós-agosto): o auto-fit dava 9+3 — uma
   linha cheia e um resto solto, sem forma nenhuma. Abaixo dos 900px o auto-fit continua a mandar:
   forçar 6 colunas num telemóvel esmagava os tiles. Vale para as duas páginas que usam a tira
   (mapa da equipa e Gerir escala) — é o mesmo componente, e duas formas eram duas gramáticas. */
@media (min-width: 900px) {
  .tira-meses-grelha { grid-template-columns: repeat(6, minmax(0, 1fr)); }
}
/* O seletor de vista («Por dia | Por pessoa») vinha COLADO à tira no mapa da equipa — a folga
   é a mesma dos 20px que a .tira-meses já recebe do título. Adjacência e não classe nova: só o
   mapa tem um .segmentos a seguir à tira. */
.tira-meses + .segmentos { margin-top: 20px; }
.tira-mes {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 9px 11px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  color: var(--ink);
  text-decoration: none;
  transition: border-color var(--transition-fast), background-color var(--transition-fast);
}
.tira-mes:hover { border-color: var(--cyan-soft); background: var(--sand); text-decoration: none; }
.tira-mes[aria-current="true"] { border-color: var(--ocean); box-shadow: inset 0 0 0 1px var(--ocean); }
.tira-mes-nome { font-size: 13px; font-weight: 600; }
.tira-mes-estado { display: flex; align-items: center; gap: 5px; font-size: 11px; color: var(--muted); }
.tira-mes-ponto { width: 7px; height: 7px; border-radius: 50%; background: var(--line); flex: 0 0 auto; }
.tira-mes-ponto.publicado { background: var(--status-success); }
.tira-mes-ponto.rascunho { background: var(--gold); }
.tira-mes-ponto.desatualizado {
  background: repeating-linear-gradient(135deg, var(--status-warning) 0 2px, #d9c99b 2px 4px);
}

/* Separadores internos — o ÚNICO idioma de separador da app.
   Serve o Gerir escala (Meses · Versões · Plano) e as Aprovações (Férias ·
   Ausências). A `.segmentos` do site.css continua a ser outra coisa: alterna
   VISTAS do mesmo conteúdo (A minha / Por dia / Mês). Aqui não se alterna uma
   vista — muda-se de fila de trabalho, e isso é um separador. */
.abas {
  display: flex;
  /* ⚠️ O wrap não é decorativo: a 390px os quatro separadores do Gerir escala pediam 397px e o
     quarto saía do ecrã — era o pior infrator do transbordo do body medido no
     EscalaGerirPlanoTests (ronda pós-agosto). Em desktop nunca quebra porque cabe. */
  flex-wrap: wrap;
  gap: 4px;
  margin: 24px 0 0;
  border-bottom: 1px solid var(--line);
}
.aba {
  padding: 10px 14px;
  border: 0;
  border-bottom: 2px solid transparent;
  background: transparent;
  color: var(--muted);
  font-family: var(--font-sans);
  font-size: 14px;
  cursor: pointer;
}
.aba:hover { color: var(--ink); text-decoration: none; }
/* ⚠️ DOIS seletores, e não só o `aria-selected` do delta: aqui os separadores são
   LINKS (sem JavaScript a página tem de continuar inteira), e num `<a>` sem
   `role="tab"` a marca correta é o `aria-current="page"`. O `aria-selected` fica
   para quem os desenhe como `role="tab"` — as Aprovações. */
.aba[aria-selected="true"],
.aba[aria-current="page"] { color: var(--ocean); border-bottom-color: var(--ocean); font-weight: 600; }
/* A contagem do separador é uma CONTAGEM, não um alarme: fica em mono e
   discreta. O badge do menu (cyan cheio) é que chama; repeti-lo aqui, já dentro
   da página, era gritar duas vezes a mesma coisa. */
.aba-conta {
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: var(--radius-pill);
  background: var(--sand);
  font-family: var(--font-mono);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}
.aba[aria-selected="true"] .aba-conta,
.aba[aria-current="page"] .aba-conta { background: rgba(1, 94, 130, .1); color: var(--ocean); }

/* O painel da /Estrutura respira do sublinhado das `.abas` — que não tem margem
   inferior, e o `.card` lá dentro não tem margem superior, por isso sem isto o
   cartão encostava à linha. É a mesma folga de 20px que a `.tira-meses` e a
   `.versoes` já dão à mão dentro do Gerir escala; aqui não se pode pendurar na
   tabela, porque os dois painéis começam por um `.card` genérico.
   ⚠️ Fica numa classe própria e NÃO num `[data-painel] > :first-child`: essa
   forma apanhava também os três painéis do Gerir escala, que já resolvem o
   espaço à mão — mexer-lhes daqui era mudar um desenho que não é desta task. */
.painel-estrutura { margin-top: 20px; }

/* ── Plano publicado: grelha equipa × dias, em LEITURA ──
   A tabela de ~400 linhas não era o problema todo: reaproveitar a `.mapa-equipa`
   também não servia, porque ali a célula é uma mancha de 22px e aqui tem de
   caber uma HORA. Coluna de nomes fixa e a cor do turno a fazer o trabalho que o
   texto sozinho não faz. */
/* ⚠️ FLUIDA, e não de largura fixa. Com células fixas de 30px a tabela pedia
   1062px e só cabia acima de ~1425px de janela — abaixo disso os últimos dias do
   mês escondiam-se atrás de uma barra de deslocamento que ninguém repara que
   existe, que é exatamente o defeito que esta vista veio resolver. Assim as 31
   colunas repartem o espaço que houver, e recolher a barra lateral devolve 180px
   à grelha.
   ⚠️⚠️ Os 26px do desenho são uma INTENÇÃO, não uma garantia — e o que aqui
   esteve escrito («mínimo 26px, onde 8·30 ainda cabe») prometia o contrário. Sob
   `table-layout: fixed` o `min-width` de uma `td` é INERTE: quem reparte é a
   tabela, e mais nada. MEDIDO em Chromium, a 1280px com a barra aberta, a coluna
   fica em 25,9px (aos 1440/1680 fica em 30,6px). O que segura o «8·30» não é
   portanto um piso de largura, é a repartição não cortar — e é isso que o
   `EscalaGerirPlanoTests` mede, célula a célula (`scrollWidth > clientWidth`):
   ao apertar o espaço, as células cortam muito antes de um piso de 26px falhar. */
.plano-grelha {
  border-collapse: separate;
  border-spacing: 0;
  font-size: 11px;
  width: 100%;
  min-width: 132px;
  table-layout: fixed;
}
/* ⚠️ Só no regime MOBILE (o breakpoint da casa, o mesmo que esconde a sidebar): num telemóvel a
   repartição fluida dava ~7px por dia — cabeçalhos uns por cima dos outros e o «8·30» cortado a
   6px (fotografia do Bruno, ronda pós-agosto). Aqui a grelha ganha um chão real — 132px de nomes
   + 31×26px, o tamanho de célula do desenho — e passa a DESLIZAR dentro do .tabela-scroll que
   sempre a embrulhou, com a coluna dos nomes sticky a segurar o «de quem é» durante o deslize.
   O desktop não muda: acima dos 900px vale a nota grande da .plano-grelha (repartição fluida,
   intervalo 25,9-30,6px medido no EscalaGerirPlanoTests). A prova mobile é o
   Em_mobile_a_grelha_do_plano_desliza_no_contentor_em_vez_de_esmagar_as_celulas. */
@media (max-width: 899.98px) {
  .plano-grelha { min-width: calc(132px + 31 * 26px); }
}
.plano-grelha th, .plano-grelha td { padding: 0; }
/* A coluna dos nomes fica FIXA a 132px e presa à aresta: é a única que não pode
   encolher, porque sem ela uma linha de 31 manchas não se sabe de quem é. Os
   132px são o que o delta mediu para os nomes da equipa não levarem reticências.
   ⚠️ O cálculo «132 + 31×30 = 1062px» que acompanhava esta regra no delta era o
   da versão de células FIXAS, e essa foi abandonada — ver a nota acima. */
.plano-grelha .plano-nome {
  position: sticky;
  left: 0;
  z-index: 3;
  width: 132px;
  min-width: 132px;
  padding: 0 10px 0 2px;
  text-align: left;
  font-weight: 500;
  font-size: 12px;
  background: var(--paper);
  border-right: 1px solid var(--line);
}
.plano-grelha thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--paper);
  border-bottom: 1px solid var(--ink);
}
.plano-grelha thead .plano-nome { z-index: 4; }
.plano-cabeca { display: grid; grid-template-rows: 12px 15px; justify-items: center; padding-bottom: 4px; }
.plano-semana {
  font-family: var(--font-mono);
  font-size: 9px;
  line-height: 12px;
  color: var(--muted);
  text-transform: lowercase;
}
.plano-numero {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 15px;
  font-variant-numeric: tabular-nums;
}
.plano-grelha th.plano-fds { background: rgba(14, 21, 47, 0.04); }
.plano-cel {
  /* ⚠️ INERTE enquanto a tabela for `table-layout: fixed` — fica declarado porque
     é a intenção do desenho (e voltaria a valer se a tabela deixasse de o ser),
     não porque esteja a fazer alguma coisa hoje. Ver a nota grande da
     `.plano-grelha`. */
  min-width: 26px;
  height: 25px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-variant-numeric: tabular-nums;
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.plano-cel.fds { background: rgba(14, 21, 47, 0.04); }
/* O turno pinta a célula com a MESMA cor da vista Mês — as duas leem-se juntas. */
.plano-cel.turno {
  background: color-mix(in srgb, var(--turno-cor) 20%, var(--paper));
  color: var(--turno-cor);
  font-weight: 600;
}
.plano-cel.folga { color: var(--status-neutral); }
/* Sem glifo: a mancha azul cheia já diz «férias», e o «▨» que aqui esteve era
   ruído dentro de uma célula de 30px (e cai para caixa vazia em fontes sem ele). */
.plano-cel.ferias { background: rgba(1, 94, 130, 0.3); }
.plano-cel.ausencia {
  background: repeating-linear-gradient(135deg, rgba(107, 91, 149, .28) 0 3px, transparent 3px 6px);
  color: var(--plum-deep);
}
.plano-grelha tbody tr:hover .plano-cel { box-shadow: inset 0 -1px 0 var(--cyan-soft); }

/* A legenda das manchas — a cor nunca é o único canal, e «férias» é a única
   marca sem glifo nenhum dentro da célula.
   ⚠️ Classe própria: a `.regua-legenda` já tem dono (o saldo de férias).
   A forma (linha, espaçamento, tipografia) vem da `.legenda` partilhada desde a A6 — ver a secção
   «A forma comum das legendas». Aqui fica só a amostra, que NÃO é um quadrado abstrato de cor: é a
   própria `.plano-cel` da grelha, com o texto lá dentro («8», «F»). Por isso não leva a classe
   `.amostra` nem os 14px dela — encolhê-la fazia a legenda deixar de mostrar o que está na grelha. */
.plano-legenda .plano-cel {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  border: 1px solid var(--line);
  border-radius: 2px;
}

/* Linha do tempo das versões. */
.versoes { list-style: none; margin: 20px 0 0; padding: 0 0 0 22px; position: relative; }
.versoes::before {
  content: "";
  position: absolute;
  left: 5px; top: 6px; bottom: 6px;
  width: 1px;
  background: var(--line);
}
.versao { position: relative; padding: 0 0 22px; }
.versao::before {
  content: "";
  position: absolute;
  left: -22px; top: 5px;
  width: 11px; height: 11px;
  border-radius: 50%;
  background: var(--paper);
  box-shadow: inset 0 0 0 2px var(--status-neutral);
}
.versao.ativa::before { background: var(--ocean); box-shadow: inset 0 0 0 2px var(--ocean); }
.versao-cabeca { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px 12px; }
.versao-numero { font-size: 16px; font-weight: 650; }
.versao-meta { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.versao-nota { margin: 5px 0 0; font-size: 14px; }
.versao-avisos { margin: 6px 0 0; font-size: 12px; color: var(--status-warning); }
.versao-acoes { margin: 10px 0 0; display: flex; gap: 8px; }

/* ─────────────────────────────────────────────────────────────────────────
   APROVAÇÕES — a fila como uma pauta, e não como uma pilha de cartões
   ─────────────────────────────────────────────────────────────────────────
   Três cartões brancos iguais empilhados não deixam COMPARAR: e comparar é o
   trabalho — quem espera há mais tempo, qual é que parte a cobertura, qual é
   que é meio dia. A fila passa a uma pauta de linhas alinhadas, separadas por
   fio, com as mesmas três zonas em todas: quem/o quê · impacto · decidir.
   A assinatura é a RÉGUA DA ESPERA na aresta esquerda. Não é decoração: a fila
   das ausências já é servida da mais antiga para a mais recente, e a própria
   página já o diz por palavras. Aqui esse facto passa a ter forma.
   ⚠️ Serve as DUAS filas (Férias e Ausências) — é o que faz delas a mesma cara.
   O que se muda entre elas são as `.abas` lá acima, e nunca as `.segmentos`:
   aqui muda-se de FILA, não de vista do mesmo conteúdo. */

.fila { border-top: 1px solid var(--ink); margin: 20px 0 0; }
.fila-pedido {
  display: grid;
  grid-template-columns: 3px minmax(0, 1fr) auto;
  align-items: start;
  gap: 0 18px;
  padding: 16px 0 16px 0;
  border-bottom: 1px solid var(--line);
}
/* ⚠️ COLOCAÇÃO EXPLÍCITA nas três zonas, e não a colocação automática do delta.
   Cada `.fila-pedido` é uma grelha SUA — é a coluna `1fr` que absorve a folga e
   faz os botões acabarem todos na mesma coordenada à direita, mesmo em grelhas
   independentes —, mas com colocação automática o `.fila-decidir` caía na coluna
   de 3px assim que uma linha ganhasse um elemento a mais, e a pauta desalinhava
   sem ninguém lhe tocar. */
.fila-espera {
  grid-column: 1;
  /* ⚠️ `1 / span 2`, e NÃO o `1 / -1` do delta: o `-1` conta linhas da grelha
     EXPLÍCITA, e esta grelha não declara linhas nenhumas — o `1 / -1` resolve-se
     a uma linha só, e a régua ficava a meio da altura assim que a nota abrisse.
     O `span 2` cobre a linha do pedido e a linha da nota; sem nota aberta, a
     segunda linha não tem altura e o span não custa nada. */
  grid-row: 1 / span 2;
  align-self: stretch;
  border-radius: 2px;
  background: var(--line);
}
/* A partir de cinco dias à espera a régua acende. Um limiar e não um gradiente:
   «há muito tempo» é uma decisão, não uma escala contínua. */
.fila-pedido.demorado .fila-espera { background: var(--status-warning); }

.fila-corpo { grid-column: 2; grid-row: 1; min-width: 0; }
.fila-quem { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px; }
.fila-nome { font-size: 16px; font-weight: 650; }
.fila-idade {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.fila-pedido.demorado .fila-idade { color: var(--status-warning); font-weight: 700; }

.fila-datas { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 0; }
.fila-impacto {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  margin: 8px 0 0;
  font-size: 13px;
  color: var(--muted);
}
.fila-impacto strong { color: var(--ink); font-variant-numeric: tabular-nums; }
.fila-impacto .em-falta { color: var(--status-warning); }

/* O aviso que muda a decisão fica na coluna do texto, com a marca âmbar à
   esquerda — nunca uma caixa de largura total, que empurrava a linha para o
   dobro da altura e desalinhava a pauta toda. */
.fila-obstaculo {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 10px 0 0;
  padding-left: 10px;
  border-left: 2px solid var(--status-warning);
  font-size: 13px;
  color: var(--status-warning);
}

/* ⚠️ O formulário das ações não é uma zona — é o INVÓLUCRO de duas (os botões à
   direita, a nota numa linha por baixo do texto). `display: contents` põe os
   filhos dele na grelha do pedido sem o formulário lá estar a ocupar uma célula.
   Sem isto, ou a nota ficava fora do formulário (e não era submetida com a
   decisão) ou os botões e a nota empilhavam-se na coluna estreita da direita. */
.fila-acoes { display: contents; }

/* ⚠️ `flex-wrap: wrap` não é opcional, e é a lição já paga pela `.form-acoes`:
   a linha é «+ nota · Aprovar · Recusar (· Pedir parecer)» e, sem wrap, a 360px
   o Recusar saía FORA do cartão — medido em browser (MobileUiTests). Uma fila
   que não cabe parte para a linha de baixo, nunca para fora da caixa. */
.fila-decidir {
  grid-column: 3;
  grid-row: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
/* Na fila das ausências cada ação tem o seu próprio <form> (o destino vive todo
   no formulário, nunca num `formaction` do botão), e é o formulário que precisa
   de ser a linha. */
.fila-decidir form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; }

.fila-nota-abrir {
  padding: 6px 10px;
  border: 1px dashed var(--line);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}
.fila-nota-abrir:hover { border-color: var(--cyan-soft); color: var(--ink); }
/* A nota é opcional e quase nunca se escreve: nasce fechada. Três campos de
   texto sempre abertos numa fila de três pedidos era o ecrã a pedir uma coisa
   que ninguém preenche.
   (O `.fila-nota[hidden]` do delta não se porta: a regra global `[hidden]` lá em
   cima já o faz, e leva `!important` precisamente porque a folha do BROWSER
   perde para qualquer `display` de autor. Duas regras para o mesmo é a próxima
   pessoa a mudar a errada.) */
.fila-nota { grid-column: 2 / -1; grid-row: 2; margin: 10px 0 0; }
.fila-nota input { width: 100%; max-width: 520px; }

/* A anulação é a ação destrutiva da fila do RH e leva SEMPRE uma razão (spec §4)
   — é o que a pessoa vai ler no email. Fica numa linha própria por baixo do
   texto, e não espremida na coluna dos botões: um campo obrigatório de 260px ali
   dentro empurrava a zona de decidir para o dobro da largura, e é essa zona que
   tem de acabar toda na mesma coordenada. */
.fila-anular { grid-column: 2 / -1; grid-row: 2; margin: 10px 0 0; }
.fila-anular input { flex: 1 1 200px; }

/* Um formulário de UMA ação, em linha. Mesma forma da `.form-anexar`, e não a
   mesma classe: aquela nomeia o que faz, e um formulário de anular com classe
   «anexar» é a próxima pessoa a procurar um upload que não existe. */
.form-em-linha { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; }

/* ⚠️ Um campo SEM rótulo visível — quem o nomeia é o botão que o abre (a nota) ou
   o `aria-label` (a razão da anulação). A aparência de campo desta app vive em
   `.campo input[...]`, e estes não estão num `.campo`: sem esta regra saíam com a
   folha do próprio browser, e foi exatamente por isso que aqui estiveram `style=`
   inline durante meses. */
.campo-nu {
  font: inherit;
  font-size: 14px;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 8px 12px;
  max-width: 320px;
  transition: border-color var(--transition-fast);
}
.campo-nu:hover { border-color: var(--cyan-soft); }
.campo-nu:focus-visible { border-color: var(--cyan-soft); box-shadow: var(--shadow-ring); outline: none; }

/* ── O que já foi decidido ── */
.decididas { margin: 26px 0 0; }
.decididas > summary {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 12px 0;
  border-top: 1px solid var(--line);
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--muted);
}
.decididas > summary:hover { color: var(--ink); }
.decididas > summary::marker { color: var(--cyan-soft); }
.decidida {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 4px 14px;
  padding: 9px 0;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
}
.decidida-quando {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.decidida-quem { min-width: 0; }
.decidida-quem strong { font-weight: 600; }
.decidida-nota { grid-column: 2 / -1; color: var(--muted); font-size: 12px; }
.decidida-estado { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .5px; }
.decidida-estado.aprovada { color: var(--status-success); }
.decidida-estado.recusada { color: var(--status-warning); }
/* Os dois veredictos da fila das AUSÊNCIAS. O par é o mesmo — o que correu como
   se esperava e o que não —, e por isso partilha as duas cores em vez de trazer
   tokens novos. */
.decidida-estado.validada { color: var(--status-success); }
.decidida-estado.anulada { color: var(--status-warning); }
.decididas-mais { margin: 14px 0 0; }

/* O registo em nome de outra pessoa não é uma fila de decisão — é outro
   trabalho, e fica por baixo das duas, separado por ar. */
.registar-por-outrem { margin-top: 22px; }

/* A paginação das validadas, centrada. Era um `style=` inline; uma regra que só
   serve um sítio leva uma classe. */
.paginacao-centrada { justify-content: center; margin-top: 16px; }

/* Ecrã estreito: a zona de decidir deixa de caber ao lado do texto muito antes
   de o texto deixar de caber. Passa a uma coluna (a régua fica), e os botões
   descem para debaixo do pedido a que pertencem — dentro do pedido, nunca fora
   dele (é o que o MobileUiTests mede a 360px). */
@media (max-width: 720px) {
  .fila-pedido { grid-template-columns: 3px minmax(0, 1fr); }
  .fila-decidir { grid-column: 2; grid-row: 2; margin: 12px 0 0; }
  .fila-nota, .fila-anular { grid-column: 2; grid-row: 3; }
  .fila-espera { grid-row: 1 / span 3; }
}

/* Ecrã estreito: o painel do mês passa a uma coluna — os botões ao lado do
   título deixam de caber muito antes de a grelha o fazer. */
@media (max-width: 639.98px) {
  .mes-painel { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- Print (mapa da equipa, export) ---------- */

@media print {
  .sidebar, .topbar, .rodape, .form-acoes, .btn { display: none !important; }
  /* O painel de importação é uma AÇÃO, não informação — como o `.menu-mais` (Sair da edição/
     Descartar rascunho, PA10), que já desaparece por a `<summary>` ter `.btn` na classe. O
     `.importar-painel` não tem essa classe no elemento raiz (só o `<div class="form-acoes">`
     interno, com os botões), por isso precisa da regra própria — senão o `<h3>`, a nota e o campo
     de ficheiro ficavam no papel. */
  .importar-painel { display: none !important; }
  /* O `.btn` acima só apanha a `<summary>` (é o gatilho); se o `<details>` ficasse ABERTO ao
     imprimir, o painel do menu (que não é `.form-acoes` nem `.btn`) ia para o papel — ação, não
     conteúdo. */
  .menu-mais { display: none !important; }
  /* A `.tira-meses` entrou nesta lista quando o mapa da equipa trocou o `<input type="month">` pela
     tira dos 12 (Task 9 de PR 3a): é navegação, e navegação não se imprime. A `.mapa-meses` fica —
     continua a ser a navegação da `/Escala/Index`. */
  /* A `.mapa-ano-periodo` entrou nesta lista pela MESMA razão da `.tira-meses`, e não como exceção
     nova: é navegação. O que muda é a consequência de a deixar de fora — na vista do mês o
     `<strong>` do ano vive DENTRO da `.tira-meses` escondida, e na Anual vive num irmão do `<h2>`,
     por isso sem esta linha a folha saía com o ano escrito duas vezes (os dois `<a>` já lá não
     chegavam, escondidos pelo `.btn` desta mesma lista). O `.tira-meses-titulo` continua a
     IMPRIMIR-SE nas duas vistas: no papel é a única linha que diz de que mês (ou de que ano) é o
     mapa. */
  .mapa-filtros, .mapa-meses, .tira-meses, .mapa-ano-periodo, .mapa-chips { display: none !important; }
  /* ⚠️ Codex r2: a grelha ANUAL não se imprime, e a nota do papel toma-lhe o lugar. «Sem imprimir»
     é decisão da spec desta vista — a folha anual entra depois, com uso real por trás. O que esta
     regra evita é papel silenciosamente ERRADO: o `min-width: 916px` da `.mapa-ano-tabela`
     sobrevive aqui (o `.tabela-scroll` fica em `overflow: visible` logo abaixo, ou seja, sem barra
     que absorva o excesso) e numa A4 vertical as últimas colunas de dia saíam cortadas — MEDIDO,
     122px fora da folha, no `No_papel_a_anual_nao_sai_cortada_e_manda_para_a_vista_que_imprime`.
     ⚠️⚠️ A legenda vai com ela: uma legenda de uma grelha que não está lá explica o quê?
     ⚠️ E o `.mapa-ano-so-no-papel` é o inverso — nasce escondido no ecrã (regra fora deste bloco) e
     só aqui aparece. */
  .mapa-ano-tabela, .mapa-ano-legenda { display: none !important; }
  .mapa-ano-so-no-papel { display: block !important; }
  /* O painel de detalhe do dia (vista «Mês» da escala, VC3) é `position: fixed` — aberto, imprimia-
     se por cima da folha inteira, tapando o que estivesse por baixo. Como o painel nasce `hidden`
     e só abre por clique (progressive enhancement, VC3), quem imprime já está a ver a grelha, nunca
     o painel; esta regra só evita o acidente de alguém imprimir com ele aberto. Step 2 da Task 7
     (VC10) — a nota que a apontava para aqui ficava na secção 2a do CSS, junto ao `.escala-mes-
     clicavel`. */
  .escala-dia-painel { display: none !important; }
  /* MP10, mesma razão em espelho para a vista «Por dia»: o painel e o `+N` que o abre são
     AÇÃO/estado transitório de ecrã, não informação da grelha — quem imprime já vê a grelha
     completa (o `+N` é só um atalho, a célula continua completa sem JS). ⚠️ P11: já não existe
     `.mapa-dia-painel-fundo` para esconder aqui (era CSS morto, apagado acima). */
  .mapa-dia-painel, .mapa-dia-mais { display: none !important; }
  /* ⚠️⚠️ P12 (passagem de CSS, 2026-08-21), medido no JS: «a célula continua completa sem JS» só é
     verdade SEM JS. Com JS ligado, o teto de 6 (`mapa-equipa.js:83-93`, o `forEach` sobre
     `.mapa-dia-celula`) põe `li.hidden = true` nos `<li>` a partir do 7.º e injeta o
     `.mapa-dia-mais` («+N · ver o dia», `mapa-equipa.js:95-100`) como ÚNICA forma de os voltar a
     ver — e a regra logo acima acaba de o esconder da impressão. Sem esta linha, uma célula de 8
     nomes imprime 6, sem barra de rolagem nem aviso nenhum: o papel perde gente em SILÊNCIO.
     `[hidden]` do browser é UA stylesheet (baixa especificidade) — `li[hidden] { display: list-item
     !important; }` ganha e o `!important` é preciso porque o `[hidden]` também é `!important` por
     defeito em alguns motores. NÃO apagar por parecer redundante com o `<li>` de cima: fora do
     `@media print` isto nunca entra em jogo (o `[hidden]` do browser continua a esconder no ecrã). */
  .mapa-dia-nomes li[hidden] { display: list-item !important; }
  /* ⚠️ REGRESSÃO (achados C1/B1 da revisão): a grelha «Por dia» ganhou `overflow-x: auto` própria
     (`.mapa-dia-scroll`) e um chão de `min-width: 820px` (`section.mapa-dia`) — sem o par que a
     tabela «Por pessoa» já tem duas linhas abaixo (`.tabela-scroll { overflow: visible }` +
     `.mapa-scroll { contain: none }`), o `min-width` sobrevive à impressão e a área útil de A4
     retrato (medida pela revisão: ~717px CSS) corta colunas inteiras em silêncio — antes deste PR
     a grelha era fluida e imprimia inteira.
     Ao contrário da `.mapa-equipa` (tabela `table-layout: auto`, que só distribui espaço a mais
     pelas colunas sem um `table-layout: fixed` + `font-size` menor a travá-la), esta grelha é um
     `display: grid` com `grid-template-columns: repeat(5, minmax(0, 1fr)) 34px 34px`: as 5 colunas
     do dia útil já são `1fr` (proporcionais, chão em 0) e as 2 do fim de semana já são fixas a
     34px — é o PRÓPRIO `min-width: 820px` que impede essa fluidez de atuar no ecrã. Sem ele, a
     aritmética do papel é: (717 − 2×34 − 6×1 gap − 2×1 borda) ÷ 5 ≈ 128px por coluna de dia útil
     (era ~149px a 820px de chão). Os tamanhos de letra da grelha (10–13px:
     `.mapa-dia-equipa-nome` 10px, `.mapa-dia-nomes` 11,5px — a vaga B tirou-o do `<li>` e pô-lo na
     LISTA —, `.mapa-dia-numero` 13px) já são fixos e pequenos e o `.mapa-dia-nomes li` já
     tem `overflow-wrap: break-word` — a esses 128px o texto ganha mais LINHAS (a célula cresce em
     altura, sem `max-height` a cortá-la), nunca se corta; não há colunas nem símbolos a apertar
     como na tabela. Por isso não é preciso o equivalente ao `table-layout: fixed`/`font-size`
     menor — só travar o chão que os impede de encolher. Não medido em browser real por esta vaga
     (só CSS, sem Playwright) — é aritmética escrita, não olho; a vaga C confirma com Playwright a
     impressão real da vista «Por dia» antes de dar isto por fechado. */
  section.mapa-dia { min-width: 0; }
  .mapa-dia-scroll { overflow: visible; }
  .tabela-scroll { overflow: visible; }
  .mapa-scroll { contain: none; }
  .mapa-equipa {
    width: 100%; table-layout: fixed; font-size: 8px;
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }
  .mapa-equipa .mapa-nome {
    position: static; min-width: 0; width: 100px; padding-right: 4px;
  }
  .mapa-equipa thead th { min-width: 0; }
  .mapa-equipa td.mapa-cel { width: auto; height: 14px; text-align: center; color: var(--ink); }
  .mapa-legenda .mapa-amostra {
    background: none; box-shadow: none; opacity: 1; color: var(--ink); text-align: center;
  }
  .mapa-equipa td.mapa-cel::after,
  .mapa-legenda .mapa-amostra::after { color: var(--ink); font-weight: 700; line-height: 1; }
  /* ⚠️ Os 14px são a ALTURA DA AMOSTRA (`.legenda .amostra`), não um número solto: é o que centra a
     letra dentro do quadrado. Eram 22px, o lado que a amostra do mapa tinha antes da A6 — com a
     amostra a encolher e este a ficar, a letra saía por baixo da caixa e a legenda impressa
     desalinhava-se toda. Se o lado da amostra mudar, este número muda com ele. */
  .mapa-legenda .mapa-amostra::after { display: block; font-size: 10px; line-height: 14px; }
  .mapa-equipa td.mapa-aprovado::after,
  .mapa-legenda .mapa-amostra.mapa-aprovado::after { content: "A"; }
  .mapa-equipa td.mapa-pendente::after,
  .mapa-legenda .mapa-amostra.mapa-pendente::after { content: "P"; }
  .mapa-equipa td.mapa-ausencia::after,
  .mapa-legenda .mapa-amostra.mapa-ausencia::after { content: "◆"; }
  .mapa-equipa td.mapa-aniversario::after,
  .mapa-legenda .mapa-amostra.mapa-aniversario::after { content: "●"; }
  .mapa-equipa td.mapa-feriado::after,
  .mapa-legenda .mapa-amostra.mapa-feriado::after { content: "F"; }
  .mapa-equipa td.mapa-fds::after,
  .mapa-legenda .mapa-amostra.mapa-fds::after { content: "×"; }
  .mapa-equipa td.mapa-inerte::after,
  .mapa-legenda .mapa-amostra.mapa-inerte::after { content: "–"; }
  /* Achado C2 da revisão: as regras acima só apanham `.mapa-legenda .mapa-amostra` (a vista «Por
     pessoa») — a vista «Por dia» usa as MARCAS REAIS da grelha (`.mapa-marca-*`, 9px), não a
     `.amostra` de 14px, e ficava sem canal nenhum a preto e branco.
     ⚠️ São DUAS metades, e a vaga B só escreveu uma: a legenda E a GRELHA. É o espelho do que a
     vista irmã já faz duas dúzias de linhas acima (`.mapa-equipa td.mapa-aprovado::after` E
     `.mapa-legenda .mapa-amostra.mapa-aprovado::after`, no mesmo par de seletores). Com letra só
     na legenda, o papel ficava a prometer «A = Férias aprovadas» por cima de um calendário onde
     cada nome saía com um quadrado INVISÍVEL à frente — os gráficos de fundo vêm desligados por
     omissão em qualquer impressora, e o motivo vive no `.sr-only`, que é recortado.
     ⚠️⚠️ A MESMA receita de letra serve os dois porque a caixa é a mesma: medido em Chromium
     (`MapaPorDiaPinturaTests`, `@media print`) — marca da grelha 9×9, marca da legenda 9×9. É o
     teste que compara as duas, e não este comentário, que impede as duas de divergirem.
     ⚠️⚠️⚠️ O seletor é `section.mapa-dia` e não `.mapa-dia` a seco (a regra da casa: `.mapa-dia` é
     o `<span>` do cabeçalho da «Por pessoa»); apanha as marcas dos nomes E a do feriado da coluna
     de fim de semana comprimida, que é a única que vive fora de um `.mapa-dia-nomes`.
     Mesmas letras que a legenda irmã já usa, por CORRESPONDÊNCIA de cor/forma (não inventadas):
     `.mapa-marca-ferias` é o mesmo `--ocean` sólido do `.mapa-aprovado` → "A"; `.mapa-marca-falta`
     é o mesmo `--plum` às riscas do `.mapa-ausencia` → "◆"; `.mapa-marca-aniversario` é o mesmo
     `--gold` redondo do `.mapa-aniversario` → "●"; `.mapa-marca-feriado` é o mesmo `--gold-deep`
     às riscas do `.mapa-feriado` → "F". O triângulo de aviso (`.mapa-dia-tri`, último item desta
     legenda) já tem FORMA própria — não precisa de letra.
     O tamanho da letra segue a mesma receita da `.mapa-amostra` (`line-height` = lado da caixa, o
     que centra o carácter): lá é 14px de caixa / 10px de letra; aqui a caixa é 9px — proporção
     igual (10÷14 ≈ 0,71 × 9 ≈ 6,4px), arredondado a 7px por ser a impressão, não o ecrã. Se o lado
     da `.mapa-marca` mudar, este número muda com ele, tal como o comentário gémeo já avisa. */
  .mapa-dia-legenda .mapa-marca,
  section.mapa-dia .mapa-marca {
    background: none; border-color: transparent; color: var(--ink); text-align: center;
  }
  .mapa-dia-legenda .mapa-marca::after,
  section.mapa-dia .mapa-marca::after {
    display: block; color: var(--ink); font-weight: 700; font-size: 7px; line-height: 9px;
  }
  .mapa-dia-legenda .mapa-marca-ferias::after,
  section.mapa-dia .mapa-marca-ferias::after { content: "A"; }
  .mapa-dia-legenda .mapa-marca-falta::after,
  section.mapa-dia .mapa-marca-falta::after { content: "◆"; }
  .mapa-dia-legenda .mapa-marca-aniversario::after,
  section.mapa-dia .mapa-marca-aniversario::after { content: "●"; }
  .mapa-dia-legenda .mapa-marca-feriado::after,
  section.mapa-dia .mapa-marca-feriado::after { content: "F"; }
  body { background: #fff; }
  .principal { padding: 0; }
  /* .painel-corpo entrou aqui na Task 3 (acabamentos): mesma linguagem visual do .card, mesmo
     tratamento no papel — plano, sem borda/sombra/padding. NÃO se força o <details> a abrir: o
     painel é a ação de "marcar", já sem botão (o .form-acoes/.btn acima ficam escondidos) — não é
     uma grelha de consulta como o mapa da equipa, que este @media print também serve. Fechado, a
     página imprime só o resumo/lista à volta, o que é o comportamento correto; quem quiser o
     conteúdo do painel no papel abre-o antes de imprimir, exatamente como o veria no ecrã. */
  .card, .painel-corpo { border: none; box-shadow: none; padding: 0; }
  /* Correção da onda final (Minor 2/8 da revisão): o <summary> "Marcar férias" continua com o fundo
     --ocean cheio no papel — fechado já era uma pastilha colorida sem função (o botão não se clica
     em papel; achado não-bloqueante da Task 3, deixado para uma "Task futura"). Aberto (Task 3 fix
     round 1) o <summary> passou de pastilha a CABEÇALHO À LARGURA TOTAL do bloco — confirmado por
     screenshot desta onda (`onda-final-print-painel-aberto.png`): sai uma barra azul-escura de ponta
     a ponta da folha. Com "gráficos de fundo" impressos, isso é muito mais toner do que a pastilha
     pequena de antes; com a definição por omissão do browser (fundos desligados), o texto branco
     "Marcar férias" fica ilegível sobre o papel branco e o bloco imprime sem cabeçalho nenhum — dois
     resultados maus, um deles novo. Achata-se aqui como o .card/.painel-corpo acima: sem fundo
     colorido, sem borda, cor de texto normal — lê-se como um título simples, legível sempre,
     gráficos de fundo ligados ou não.
     ⚠️ As DUAS regras são precisas, não uma: `.painel-marcar[open] > summary` (site.css acima) é
     MAIS específica do que `.painel-marcar > summary` sozinho (a combinação classe+atributo pesa
     mais do que só classe) — sem repetir o seletor com `[open]` aqui, o fundo escuro do estado
     ABERTO sobrevivia a este bloco inteiro, `@media print` ou não: especificidade não se resolve por
     estar dentro de uma media query. */
  .painel-marcar > summary,
  .painel-marcar[open] > summary {
    background: none; color: var(--ink); padding: 0; border-radius: 0;
  }
}

/* ---------- Movimento reduzido ---------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- A porta e a despedida (/Entrar e /Sair) ---------- */

/* As DUAS únicas páginas que se veem sem sessão. Não usam o `_Layout` — não têm barra lateral, nem
   menu, nem caixa de utilizador — e por isso trazem o seu próprio layout (`_LayoutPorta.cshtml`) e
   esta secção.

   ⚠️ Nada de novo entra no sistema: fundo `--ocean-darker`, texto `--cream`, acento `--cyan`, o
   aviso a `--gold`, e as três fontes que já são servidas. Zero `@font-face` novos, zero tokens
   novos.

   ⚠️ TODOS os nomes começam por `porta-` (e o `.porta`, que não existia). Foi verificado que
   nenhum deles aparece no ficheiro em posição nenhuma, composta ou não — esta ronda pagou quatro
   colisões de nome (`.vazio`, `.alerta`) por se ter procurado só no início da linha. Os candidatos
   sem prefixo do desenho original (`.botao`, `.lead`, `.nota`, `.faixa`, `.hoje`) colidiam mesmo:
   `.lead` e `.hoje` já existem neste ficheiro. */

.porta-fundo { background: var(--ocean-darker); }

.porta {
  background: var(--ocean-darker);
  color: var(--cream);
  min-height: 100vh;
  padding: clamp(30px, 5vw, 64px) clamp(22px, 5vw, 64px) clamp(34px, 5vw, 56px);
  display: flex;
  flex-direction: column;
  gap: clamp(30px, 4.6vw, 52px);
}

.porta-topo {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; flex-wrap: wrap;
}
.porta-marca { display: flex; align-items: center; gap: 13px; }
.porta-marca img { height: 26px; width: auto; display: block; }
.porta-marca span {
  font-family: var(--font-mono);
  font-size: 10.5px; letter-spacing: 0.2em; text-transform: uppercase;
  color: rgba(250, 248, 241, 0.72);
  border-left: 1px solid rgba(250, 248, 241, 0.24);
  padding-left: 13px;
}
.porta-estado {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 10.5px; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--cyan);
}

.porta-corpo {
  display: flex; flex-direction: column; gap: 22px;
  max-width: 34em;
}
.porta-corpo h1 {
  margin: 0;
  font-family: var(--font-serif);
  font-variation-settings: 'SOFT' 60, 'WONK' 1, 'opsz' 144;
  font-weight: 500;
  font-size: clamp(32px, 5.4vw, 56px);
  line-height: 1.02; letter-spacing: -0.022em;
  text-wrap: balance;
}
.porta-lead {
  margin: 0;
  font-size: clamp(15px, 1.6vw, 17.5px);
  color: rgba(250, 248, 241, 0.82);
  max-width: 44ch;
}
/* O aviso. A barra é `--gold` — a família do "repara nisto" sem ser alarme. */
.porta-nota {
  margin: 0;
  font-size: 13.5px; line-height: 1.55;
  color: rgba(250, 248, 241, 0.66);
  max-width: 46ch;
  border-left: 2px solid rgba(202, 168, 90, 0.55);
  padding-left: 14px;
}

.porta-accoes {
  display: flex; align-items: center; gap: 20px; flex-wrap: wrap;
  margin-top: 2px;
}
.porta-botao {
  display: inline-flex; align-items: center; gap: 10px;
  background: var(--cream); color: var(--ocean-darker);
  font-family: var(--font-sans); font-weight: 600; font-size: 15.5px;
  text-decoration: none; border: 0; border-radius: var(--radius-md);
  padding: 14px 24px; cursor: pointer;
  transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}
.porta-botao:hover { transform: translateY(-1px); box-shadow: 0 10px 24px -12px rgba(22, 190, 207, 0.9); }
/* O anel de foco: o mesmo desenho do `--shadow-ring` do sistema, com o miolo à cor do FUNDO desta
   página em vez de `--paper` — aqui o botão é que é claro, e um miolo branco não o separava do
   anel. Medido em Chromium: 5,99:1 contra o `--ocean-darker` (o mínimo de componentes é 3:1). */
.porta-botao:focus-visible,
.porta-ajuda a:focus-visible {
  outline: 0;
  box-shadow: 0 0 0 2px var(--ocean-darker), 0 0 0 5px rgba(22, 190, 207, 0.85);
  border-radius: var(--radius-sm);
}
.porta-botao:focus-visible { border-radius: var(--radius-md); }
/* ⚠️ A marca da Microsoft NÃO herda cor nenhuma — é marca registada, vai nas cores dela e sem
   deformar (o `flex: none` é o que a impede de ser esmagada quando o texto do botão cresce). */
.porta-marca-ms { width: 15px; height: 15px; flex: none; }

.porta-ajuda { margin: 0; font-size: 13.5px; color: rgba(250, 248, 241, 0.6); }
.porta-ajuda a {
  color: var(--cyan); text-decoration: none;
  border-bottom: 1px solid rgba(22, 190, 207, 0.4);
}
.porta-ajuda a:hover { border-bottom-color: var(--cyan); }

/* ── A faixa do ano ────────────────────────────────────────────────────────
   O único gráfico das duas páginas, e não leva dados de ninguém: só a data de hoje, que vem do
   relógio de negócio (`IRelogio`) e nunca do `DateTime.Today`.
   ⚠️ A posição do marcador é a ÚNICA coisa que o servidor escreve — a `--porta-hoje`, num <style>
   no <head> do layout (ver o comentário lá). Aqui só se lê. */
.porta-faixa { display: flex; flex-direction: column; gap: 9px; margin-top: auto; }
.porta-faixa-meses {
  position: relative;
  display: grid; grid-template-columns: repeat(12, 1fr);
  border-top: 1px solid rgba(250, 248, 241, 0.22);
}
.porta-faixa-mes {
  padding: 9px 0 0;
  font-family: var(--font-mono);
  font-size: 9.5px; letter-spacing: 0.13em; text-transform: uppercase;
  /* 0.55 e não os 0.42 do desenho: a 0.42 este texto media 3,88:1 contra o fundo — abaixo do
     mínimo de 4,5:1. A 0,55 mede 5,4:1 e continua a ler-se como uma etiqueta discreta. */
  color: rgba(250, 248, 241, 0.55);
  border-left: 1px solid rgba(250, 248, 241, 0.13);
  text-align: center;
}
.porta-faixa-mes:first-child { border-left: 0; }
.porta-faixa-mes-agora { color: var(--cyan); }
.porta-faixa-marca {
  position: absolute; top: -1px; bottom: -11px;
  /* ⚠️ O `-1px` CENTRA a barra de 2px no dia exato, e é o que a impede de ficar 2px para lá do fim
     do ano a 31 de dezembro. O marcador (e o ponto dele) ainda podem passar da grelha dos meses por
     uns píxeis — de propósito: é um marcador POR CIMA de uma régua, e essa folga vive dentro do
     `padding` da `.porta`. O que se mede em Chromium é o que interessa: nada sai da `.porta`. */
  left: var(--porta-hoje, 0%); margin-left: -1px;
  width: 2px; background: var(--cyan);
  transform-origin: top;
  animation: porta-cresce 0.7s cubic-bezier(0.2, 0.7, 0.3, 1) both;
}
.porta-faixa-marca::before {
  content: ""; position: absolute; top: -3px; left: -3px;
  width: 8px; height: 8px; border-radius: 50%; background: var(--cyan);
}
.porta-faixa-hoje {
  position: absolute; top: 26px;
  left: var(--porta-hoje, 0%);
  margin-left: 9px;
  font-family: var(--font-mono);
  font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--cyan); white-space: nowrap;
}
/* Em dezembro a etiqueta não cabe à direita do marcador — passa para a esquerda dele. O servidor
   decide (é ele que sabe a percentagem) e diz-o com uma CLASSE, não com um estilo. */
.porta-faixa-hoje-fim { margin-left: -9px; transform: translateX(-100%); }
.porta-faixa-legenda {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase;
  /* Também subiu (era 0.38 no desenho): esta linha é TEXTO a sério — diz o ano e o dia — e é a
     única forma de quem não vê o gráfico saber o que ele mostra. 8,7:1. */
  color: rgba(250, 248, 241, 0.7);
}

/* O ecrã de saída: a faixa esmorece, o marcador fica.
   ⚠️ NÃO usar `opacity` no `.porta-faixa-meses` (o pai): cria um grupo de composição que achata
   TUDO lá dentro à MESMA alfa — um `opacity: 1` num descendente não desfaz o do antepassado. O
   marcador (`.porta-faixa-marca`) e a etiqueta da data (`.porta-faixa-hoje`) são filhos DESTE
   elemento (ver `_LayoutPorta.cshtml`), por isso ficavam apanhados no mesmo achatamento: o
   marcador media a opacidade da faixa (0,45), não a intensidade cheia que a regra ao lado
   prometia (achado do Codex, revisão de 2026-08-13 — prova em
   `BebeVida.People.Web.BrowserTests/PortaTests.cs`).
   A correção esmorece cada peça em vez do pai que a partilha com o marcador: a cor dos próprios
   rótulos e a cor da linha/borda da faixa. 0,50 e não os 0,45 do desenho original: aqui a alfa é
   DIRETA (já não se multiplica pela alfa do próprio texto, 0,55) — a 0,50 mede ~5,0:1 contra o
   fundo (a entrada mede ~5,8:1); a descer mais aproxima-se depressa do mínimo AA de 4,5:1.
   O mês atual (`.porta-faixa-mes-agora`) fica de fora do esmorecer: é outro "estás aqui", ao mês,
   tal como o marcador o é ao dia — e a 0,50 direto o cyan dele não passava o AA (teria de subir
   a alfa até quase não esmorecer nada, o que perdia o sentido). */
.porta-saida .porta-faixa-meses { border-top-color: rgba(250, 248, 241, 0.12); }
.porta-saida .porta-faixa-mes { color: rgba(250, 248, 241, 0.5); }
.porta-saida .porta-faixa-mes-agora { color: var(--cyan); }

/* O marcador cresce UMA vez, ao carregar. O bloco global de `prefers-reduced-motion` no fim deste
   ficheiro já o desliga (`animation-duration: 0.01ms !important`), e é ele que manda — esta regra
   fica na mesma, explícita, porque a de cima é uma rede geral e esta é a intenção declarada. */
@keyframes porta-cresce { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@media (prefers-reduced-motion: reduce) {
  .porta-faixa-marca { animation: none; }
  .porta-botao { transition: none; }
  .porta-botao:hover { transform: none; }
}

/* ---------- A legenda da escala (vista Mês + Editor de rascunhos) ---------- */

/* Portada da secção 10 do delta de 2026-08 («Peças partilhadas», docs/known-followups.md — procurar
   «secção 10»): ficou por portar no fecho da ronda e é a causa do defeito reportado pelo Bruno em
   produção — a Escala do laboratório não tinha legenda nenhuma.
   ⚠️ Só a `.legenda-linha` vem daqui. A `.pilula` da mesma secção CONTINUA por portar, de propósito:
   nenhuma `.cshtml` desta app escreve essa classe hoje — portar CSS sem markup nenhum a usar é dívida
   nova, não dívida paga. Atualizar `docs/known-followups.md` se um dia alguém precisar dela.
   ⚠️ Nome verificado: nem `.legenda-linha` nem `.pilula` existiam neste ficheiro em posição nenhuma
   antes desta secção — composta ou não, não só no início da linha (é a lição que a secção da «porta»
   já deixa escrita, acima, depois de pagar quatro colisões por procurar só aí). */
/* A forma (linha, espaçamento, tipografia) vem da `.legenda` partilhada desde a A6 — ver a secção
   «A forma comum das legendas» lá em cima. O que sobra aqui é só o tamanho da amostra do editor. */

/* O editor mostra a AMOSTRA REAL da célula: as mesmas classes de estado que a bancada usa
   (`.editor-celula.folga`, `.falta`, `.ferias`) — nunca uma cor escrita à mão, para não haver duas
   verdades sobre a mesma célula. Esta regra só ajusta o TAMANHO — de uma coluna de 30px de grelha
   para um item de legenda — e não toca em `background`/`color` nenhum; essas continuam a vir só
   das regras de estado (`site.css`, secção 8).
   ⚠️ A10 (ruling do controlador, 2026-08-14): `.trab-fora` já não leva `turno-N` — nem na bancada
   nem aqui — mas não ganhou item de legenda próprio (a legenda continua só com folga/falta/
   férias). Ver o comentário da regra `.editor-celula.trab-fora`, secção 8, para a razão. */
.legenda-linha .editor-celula {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: auto;
  height: auto;
  padding: 3px 8px;
  border: 0;
  border-radius: var(--radius-sm);
  font-size: 11px;
  white-space: nowrap;
  cursor: default;
}

/* ---------- Conferência do Financeiro (/Despesas/Conferencia) ----------
   Três classes, todas prefixadas `desp-` e todas verificadas contra o ficheiro inteiro antes de
   nascerem (não havia UMA ocorrência de `desp-` em todo o site.css). O resto da página é feito
   inteiramente de classes que já existiam — `.colunas` (2fr/1fr), `.card`, `.tabela`,
   `.lateral-titulo`, `.saldo-valor`, `.obs-pedido`, `.form-acoes`, `.btn-pequeno`.

   ⚠️ `.desp-linha-atual` é o equivalente ao `.mx-linha-atual` do mapa da equipa: diz QUAL das linhas
   está no painel da direita. Sem ela, o painel mostrava um comprovativo e a tabela não dizia de qual
   dos trinta ele era. Pinta-se na `td` e não na `tr` — um `background` numa `<tr>` fica por baixo do
   das células em vários browsers — e a barra é `inset box-shadow`, para não empurrar o texto meio
   pixel para o lado quando a linha muda (uma `border-left` fá-lo, e a tabela «treme» a cada
   Anterior/Seguinte). */
.desp-linha-atual > td {
  background: var(--sand);
  font-weight: 600;
}
.desp-linha-atual > td:first-child { box-shadow: inset 3px 0 0 var(--cyan); }

/* ⚠️⚠️ UMA propriedade, e é a que salva a página no telemóvel. Um item de grelha tem
   `min-width: auto` por omissão, ou seja recusa-se a encolher abaixo da largura MÍNIMA DE CONTEÚDO
   do que tem dentro — e o que esta coluna tem dentro é uma tabela de cinco colunas. O
   `.tabela-scroll` (`overflow-x: auto`) não chega: ele resolve o scroll DENTRO da caixa, mas só
   depois de a caixa ter uma largura, e sem `min-width: 0` a caixa fica com a largura da tabela.
   Medido em Chromium a 390×844, ANTES: a coluna da grelha saía com 472px num ecrã de 390 e o pior
   excesso lateral da página era de 147px — a página inteira a deslizar para o lado, com a tabela a
   passar por baixo do polegar. DEPOIS: 0px. Encontrado pelo
   ConferenciaDespesasLayoutTests.No_telemovel_a_conferencia_empilha_e_nao_desliza_para_o_lado, que
   é quem o guarda; a suite C# não podia vê-lo, e a 1440px o defeito não existe (a tabela cabe). */
.desp-linhas { min-width: 0; }

/* ⚠️ O painel da direita leva o MESMO `min-width: 0` — é o outro item da mesma grelha, e a armadilha
   é a mesma — mais o `overflow-wrap: anywhere`, que a coluna da esquerda não precisa: aqui mostra-se
   o NOME DO FICHEIRO, e os nomes que saem de uma câmara de telemóvel não têm espaços
   («IMG_20260810_193355_recibo_restaurante_do_porto.jpg»). Uma palavra sem espaços não parte em
   lado nenhum: sem isto é ELA a sair do cartão — medido a 390px, o parágrafo do nome fica com
   `scrollWidth = 452` num `clientWidth` de 250, ou seja 202px de texto por cima do que estiver ao
   lado. O `anywhere` (e não `break-word`) é o que também encolhe a largura MÍNIMA INTRÍNSECA da
   caixa, que é o que impede o painel de esticar.
   ⚠️⚠️ E NÃO se mede pela caixa do parágrafo: um `<p>` é um bloco e fica sempre com a largura do
   contentor, haja o que houver lá dentro — o que transborda é o TEXTO, que não é um elemento e por
   isso não tem caixa nenhuma para um `getBoundingClientRect` apanhar. A primeira versão do teste
   comparava exatamente isso, e a mutação SOBREVIVEU. O sinal certo é `scrollWidth > clientWidth`.
   Guarda: ConferenciaDespesasLayoutTests.No_telemovel_a_conferencia_empilha_e_nao_desliza_para_o_lado,
   que semeia um nome de câmara de telemóvel de propósito. */
.desp-painel { min-width: 0; overflow-wrap: anywhere; }

/* O <form> de um botão de conferir é um invólucro, não um bloco: sem isto ganha a margem dos
   formulários e a célula da tabela cresce uma linha inteira por causa de um botão pequeno. */
.desp-conferir { display: inline; margin: 0; }

/* A pré-visualização. `max-width: 100%` porque um recibo digitalizado vem com 3000px de largura e
   arrastava a coluna da direita para fora do ecrã; `max-height` porque uma fotografia de telemóvel
   em retrato empurrava o botão de conferir para fora da vista, que é o oposto do que esta página
   existe para fazer (ler a prova E decidir, sem rolar). */
.desp-comprovativo { margin: 12px 0 0; }
.desp-comprovativo img {
  display: block;
  max-width: 100%;
  max-height: 420px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--paper);
}

/* ---------- Boletim itinerário (/Despesas/Boletim) ----------
   Task 15, spec §8/DP14 — o documento legal que a contabilidade arquiva. É a ÚNICA página desta app
   que não é um ecrã: é uma FOLHA. Por isso tem largura fixa (a de uma A4 útil) em vez de fluida, e
   por isso tem tipografia própria e mais pequena — o que se vê no ecrã é o que sai no papel.

   ⚠️ Todas as classes levam o prefixo `bol-`, e todas foram verificadas contra o ficheiro inteiro
   antes de nascerem: não havia UMA ocorrência de `bol-` em todo o site.css (a mesma disciplina do
   `desp-` da Task 13, e pela mesma razão — um seletor repetido mais abaixo no ficheiro ganha por
   ordem de cascata e desfaz em silêncio a regra antiga que tem o mesmo nome).

   ⚠️ Não há `@page { size: … }` nenhum aqui, e é deliberado: a regra `@page` é do DOCUMENTO, não
   de um seletor — escrita neste ficheiro passaria a valer para TODAS as páginas da app, incluindo o
   mapa da equipa, que se imprime em A4 HORIZONTAL. A orientação de cada impressão continua a ser a
   do diálogo do browser (e, nos testes, a do `PdfAsync`). */

.bol-folha {
  max-width: 190mm;                 /* A4 (210mm) menos as margens do diálogo de impressão */
  margin: 0 auto;
  padding: 24px 28px 28px;
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xs);
  font-size: 13px;
  line-height: 1.45;
}
.bol-folha p { margin: 0; }

/* ── Cabeçalho legal ─────────────────────────────────────────────────────────────────────────── */
.bol-topo {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 24px;
  padding-bottom: 12px;
  margin-bottom: 18px;
  border-bottom: 2px solid var(--ocean);
}
.bol-empresa-nome {
  font-family: var(--font-serif);
  font-size: 17px;
  font-weight: 600;
  color: var(--ocean-dark);
}
.bol-empresa-linha { font-size: 11px; color: var(--muted); }
.bol-titulo { text-align: right; }
.bol-titulo h1 {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
}
.bol-numero { font-family: var(--font-mono); font-size: 13px; margin-top: 4px; }
.bol-mes { font-size: 11px; color: var(--muted); }

/* ── Identificação: empregado · viatura · mapa ───────────────────────────────────────────────── */
.bol-identificacao {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 18px;
}
.bol-bloco {
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--cream);
}
.bol-bloco-titulo {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 6px !important;
}
/* `auto 1fr` e não duas colunas iguais: os rótulos são curtos («NIF», «Nome») e uma coluna de 50%
   deixava o valor — que é o que interessa — a partir a meio numa caixa de um terço da folha. */
.bol-campos {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 3px 10px;
  margin: 0;
}
.bol-campos dt { font-size: 11px; color: var(--muted); }
.bol-campos dd { margin: 0; font-size: 12px; overflow-wrap: anywhere; }

/* ── A grelha do itinerário ──────────────────────────────────────────────────────────────────── */
.bol-grelha {
  width: 100%;
  border-collapse: collapse;
  font-size: 11px;
}
.bol-grelha thead th {
  padding: 6px;
  text-align: left;
  background: var(--sand);
  border-bottom: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
}
.bol-grelha td { padding: 5px 6px; border-bottom: 1px solid var(--line); vertical-align: top; }
/* Números à direita e em mono — é assim que uma coluna de dinheiro se confere com o dedo. O
   `nowrap` impede «43,» numa linha e «20» na seguinte quando a folha aperta. */
.bol-num { text-align: right; font-family: var(--font-mono); white-space: nowrap; }
/* ⚠️ O cabeçalho de uma coluna de números alinha COM os números, e precisa desta linha própria: a
   regra `.bol-grelha thead th` acima é mais específica (0,1,2) do que a `.bol-num` (0,1,0) e
   ganhava-lhe o `text-align: left`. O defeito era visível na prova impressa — «KM» encostado à
   esquerda por cima de um «108» encostado à direita, e o mesmo nas três colunas de euros. */
.bol-grelha thead th.bol-num { text-align: right; }
.bol-dia { font-family: var(--font-mono); white-space: nowrap; }
.bol-total-linha { font-weight: 600; }
.bol-grelha tfoot th,
.bol-grelha tfoot td {
  padding: 7px 6px;
  background: var(--sand);
  border-top: 2px solid var(--ocean);
  font-weight: 600;
  text-align: left;
}
.bol-vazio {
  padding: 18px;
  text-align: center;
  color: var(--muted);
  border: 1px dashed var(--line);
  border-radius: var(--radius-sm);
}

/* ── Rodapé dos parâmetros + notas ───────────────────────────────────────────────────────────── */
.bol-parametros {
  display: flex;
  flex-wrap: wrap;
  gap: 3px 20px;
  margin-top: 10px !important;
  font-size: 10.5px;
  color: var(--muted);
}
.bol-parametros strong { color: var(--ink); font-weight: 600; }
.bol-nota { margin-top: 10px !important; font-size: 10.5px; color: var(--muted); }

/* ── Declaração e assinaturas digitais ───────────────────────────────────────────────────────── */
.bol-fecho { margin-top: 22px; padding-top: 14px; border-top: 1px solid var(--line); }
.bol-declaracao { font-size: 12px; margin-bottom: 14px !important; }
.bol-assinaturas {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}
.bol-assin {
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--paper);
}
.bol-assin-papel {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 5px !important;
}
.bol-assin-nome { font-weight: 600; font-size: 12.5px; }
.bol-assin-data { font-family: var(--font-mono); font-size: 11px; color: var(--muted); }
.bol-assin-nota { font-size: 10.5px; color: var(--muted); font-style: italic; margin-top: 4px !important; }
/* O pagamento é uma quarta assinatura que só existe depois de pago — linha própria, a toda a
   largura, para não fingir que faz parte do trio do circuito de aprovação. */
.bol-assin-pago { margin-top: 12px; background: var(--cream); }

/* ── O cromo da app (não do documento) ───────────────────────────────────────────────────────── */
.bol-imprimir {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px 14px;
  max-width: 190mm;
  margin: 18px auto 0;
  font-size: 12px;
  color: var(--muted);
}
.bol-imprimir kbd {
  padding: 1px 5px;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: var(--radius-sm);
  background: var(--cream);
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink);
}

/* Abaixo dos 860px as duas grelhas de três colunas empilham — a folha continua a ser uma folha, mas
   um telemóvel não tem 190mm. A `.bol-grelha` fica larga de propósito e a página não a esconde: quem
   abre um boletim no telemóvel quer confirmar um valor, e a tabela rola dentro da folha. */
@media (max-width: 860px) {
  .bol-folha { padding: 16px 14px 20px; }
  .bol-identificacao,
  .bol-assinaturas { grid-template-columns: minmax(0, 1fr); }
  .bol-topo { flex-direction: column; gap: 10px; }
  .bol-titulo { text-align: left; }
  .bol-itinerario { overflow-x: auto; }
}

/* ── O papel ──────────────────────────────────────────────────────────────────────────────────
   O `@media print` global (lá em cima) já esconde sidebar, topbar, rodapé e `.btn`, e já põe o
   `.principal` sem padding. O que falta é (1) tirar o cromo desta página, (2) desfazer a metáfora
   da «folha dentro do ecrã» — no papel a folha É a página, sem borda, sem sombra e sem margem
   central — e (3) garantir que nada da estrutura depende de FUNDOS, porque o boletim imprime-se com
   `print-background: false` (é o que o BoletimPdfTests mede, e é o que uma impressora de escritório
   faz por omissão). Onde havia fundo, fica linha. */
@media print {
  .bol-imprimir { display: none !important; }

  .bol-folha {
    max-width: none;
    width: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    font-size: 11px;
  }

  /* Sem fundo impresso, um `background: var(--cream)` é invisível — a caixa deixaria de se ver.
     A borda (que imprime sempre) passa a ser quem separa os blocos. */
  .bol-bloco,
  .bol-assin { background: none; border: 1px solid var(--muted); }
  .bol-grelha thead th,
  .bol-grelha tfoot th,
  .bol-grelha tfoot td { background: none; }
  .bol-grelha thead th { border-bottom: 1px solid var(--ink); color: var(--ink); }
  .bol-grelha td,
  .bol-grelha tfoot th,
  .bol-grelha tfoot td { border-color: var(--muted); }
  .bol-topo { border-bottom-color: var(--ink); }
  .bol-itinerario { overflow-x: visible; }

  /* Uma linha do itinerário partida ao meio por uma quebra de página é ilegível numa conferência
     manual; e o bloco das assinaturas separado da declaração deixa de ser um fecho de documento. */
  .bol-grelha tr,
  .bol-assin { page-break-inside: avoid; break-inside: avoid; }
  .bol-fecho { page-break-inside: avoid; break-inside: avoid; }
  .bol-grelha thead { display: table-header-group; }
}

/* ── Parâmetros: três blocos e o mini-índice (PR 4 da ronda de design, PA1) ── */
.param-indice { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 24px; padding: 0 0 18px; border-bottom: 1px solid var(--line); list-style: none; }
.param-indice a { display: inline-flex; align-items: baseline; gap: 8px; padding: 8px 12px; border: 1px solid var(--line); border-radius: var(--radius-pill); color: var(--ocean); font-size: 13px; font-weight: 600; text-decoration: none; }
.param-indice a:hover { border-color: var(--cyan-soft); color: var(--ocean-dark); }
.param-indice a:focus-visible { outline: none; box-shadow: var(--shadow-ring); }
.param-indice-nota { font-family: var(--font-mono); font-size: 11px; color: var(--muted); font-weight: 400; }
.param-bloco { scroll-margin-top: 20px; margin: 0 0 40px; }
.param-bloco > .cabecalho { margin-bottom: 16px; }
.param-bloco h2:focus { outline: none; }

/* ── Gerir escala: o cabeçalho ganha o atalho para os Parâmetros (PA8) ── */
.cabecalho-com-acao { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.btn-icone { display: inline-flex; align-items: center; gap: 8px; }
.btn-icone svg { width: 18px; height: 18px; }

/* ══ ED9 · A folha de impressão do EDITOR da escala ═══════════════════════════════════════
   Só existe no papel. A regra de esconder é por EXCLUSÃO e ancorada na classe da PÁGINA
   (`.pagina-editor-escala`, escrita pelo Editar.cshtml via ViewData): o que vai ao papel é a
   `.editor-print-folha` e mais nada. Uma lista de classes a esconder tinha de ser mantida à mão
   a cada secção nova — e uma esquecida saía impressa.
   ⚠️ Nenhum teste corre em modo de impressão a sério: a emulação prova que regras se aplicam;
   a paginação A4 verifica-se à mão (Ctrl+P). */
/* regra de ECRÃ: a folha só existe no papel; o bloco @media print no fim revela-a. */
.editor-print-folha, .editor-print-folha[hidden] { display: none; }
/* Hotfix (requisito do dono: a folha do mês cabe SEMPRE numa página A4 paisagem — mover a
   última semana para a página 2 deixou de ser aceitável). Para calcular o zoom que faz a
   folha caber, `montarFolha()` (escala-editor.js) tem de a medir FORA do ecrã, com a MESMA
   tipografia de impressão — daí as regras da folha (abaixo) não estarem presas a
   `@media print`: vivem em `.editor-print-folha` sem condição nenhuma, e só se veem quando a
   folha está visível — em impressão (bloco @media print, mais abaixo) ou durante a medição
   (`.editor-print-medir`, que a tira do fluxo do ecrã sem a esconder). */
.editor-print-folha.editor-print-medir, .editor-print-folha.editor-print-medir[hidden] {
  display: block !important; position: absolute; left: -10000px; top: 0; width: 281mm; visibility: visible;
}
/* Hotfix (defeito 2): a grelha era desenhada com um `background` preto atrás de `gap: 0.3mm`
   — o Chrome não imprime `background` por omissão («Gráficos de fundo» desligado), e a prova
   em PDF anterior só a mostrou por ter corrido com `PrintBackground=true`. Passa a bordas
   reais (`border`), que imprimem sempre. As células só levam `border-left`/`border-top`; o
   `.escala-mes` (contentor) fecha a grelha com a borda dos lados direito/inferior — dobra a
   borda nos dois cantos onde as duas coincidem (topo-esquerda), o que é aceitável e mais
   simples do que `outline` (que dobraria em TODAS as arestas internas) ou margens negativas.
   `print-color-adjust` fica de reforço (só ajuda se o utilizador ligar os fundos; a grelha
   não pode depender disso).
   Estas regras aplicam-se sem `@media print` nem `.pagina-editor-escala` à frente: a
   `.editor-print-folha` é `display:none` por omissão no ecrã (regra acima), por isso só
   ficam visíveis quando a folha está — em papel ou a medir. Ficam presas a
   `.editor-print-folha` (nunca a `.escala-mes-dia` sozinho) para nunca tocar na vista «Mês»
   do ecrã (Index.cshtml), que usa as mesmas classes fora desta folha. */
.editor-print-folha { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.editor-print-folha .editor-print-cabeca { display: flex; align-items: baseline; justify-content: space-between; gap: 10mm; margin: 0 0 2.5mm; padding: 0 0 1.5mm; border-bottom: 0.4mm solid #000; font-size: 10pt; color: #000; }
.editor-print-folha .editor-print-cabeca span { font-size: 8pt; }
.editor-print-folha .editor-print-avisos { margin: 0 0 2mm; font-size: 7.5pt; color: #000; }
.editor-print-folha .editor-print-avisos:empty { display: none; }
.editor-print-folha .editor-print-chave, .editor-print-folha .editor-print-nota { margin: 2mm 0 0; font-size: 7.2pt; color: #000; }
.editor-print-folha .escala-mes { margin: 0; border: 0.3mm solid #000; border-radius: 0; overflow: visible; container-type: normal; }
.editor-print-folha .escala-mes-grelha { display: block; background: none; gap: 0; }
/* Defeito 2b: a grelha era um único `display:grid` de 42 células — a última semana podia
   ser cortada a meio pela quebra de página. Uma `.escala-mes-semana` (grid de 7 colunas) por
   semana, com `break-inside: avoid`, continua a existir como salvaguarda, mas com o zoom a
   garantir UMA página, nunca deve chegar a ser usada. */
.editor-print-folha .escala-mes-semana { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); break-inside: avoid; page-break-inside: avoid; }
.editor-print-folha .escala-mes-cabeca { display: block !important; padding: 1.4mm 1.6mm; background: #fff !important; color: #000; font-size: 9pt; border-left: 0.3mm solid #000; border-top: 0.3mm solid #000; }
.editor-print-folha .escala-mes-dia { display: flex !important; min-height: 0; padding: 1.7mm 1.9mm; gap: 1.1mm; font-size: 9.5pt; line-height: 1.5; background: #fff !important; box-shadow: none !important; border-left: 0.3mm solid #000; border-top: 0.3mm solid #000; }
/* Células vizinhas: sem fundo (não imprime), distinguem-se por texto mais claro — o mesmo
   canal que já não depende de `background graphics`. */
.editor-print-folha .escala-mes-dia.mes-vizinho { color: #888; }
.editor-print-folha .escala-mes-dia.feriado .escala-mes-numero span:first-child { text-decoration: underline; }
.editor-print-folha .escala-mes-numero, .editor-print-folha .escala-mes-conta, .editor-print-folha .escala-turno-hora { color: #000 !important; }
.editor-print-folha .escala-fora-marca { display: none !important; }
.editor-print-folha .escala-fora-linha .sr-only { position: static; width: auto; height: auto; margin: 0 1mm 0 0; clip: auto; clip-path: none; overflow: visible; white-space: normal; font-weight: 700; }
/* Defeito 2c: tipografia apertada para um mês normal caber numa página — as margens de
   `.escala-turno`/`.escala-fora-linha` vinham da folha de estilo do ECRÃ (herdada), com
   `line-height: 1.45` e `gap` maiores do que o papel a 6.5pt precisa. */
.editor-print-folha .escala-turno, .editor-print-folha .escala-fora-linha { margin: 0; gap: 3px; line-height: 1.15; }
.editor-print-folha .escala-mes-fora { gap: 0.3mm 1.5mm; margin-top: auto; padding-top: 0.4mm; border-top-width: 0.15mm; }
@media print {
  .conteudo.pagina-editor-escala > *:not(.editor-print-folha) { display: none !important; }
  .conteudo.pagina-editor-escala .editor-print-folha,
  .conteudo.pagina-editor-escala .editor-print-folha[hidden] { display: block !important; }
}
